Herbstsemester 2013 CS261 Web Data Management Kapitel DB-6: DB-Anwendungsprogrammierung H. Schuldt Möglichkeiten der DB-Anwendungsprogrammierung SQL kann auf verschiedene Arten mit Programmiersprachen gekoppelt werden. Diese Varianten führen zum Teil zu deutlichen Unterschieden in der Anwendungsentwicklung 1. Erweiterung der Datenbanksprache um Programmierkonstrukte (turing-vollständiges SQL). Diese Programme werden in der Regel in der Datenbank definiert, gespeichert und ausgeführt („stored procedures“). 2. Erweiterung der Programmiersprache um Datenbankkonstrukte: Persistente Programmiersprachen (z.B. Pascal/R) 3. Einbettung der Datenbanksprache in die Programmiersprache: "Embedded SQL" (ESQL). SQL-Anweisungen werden speziell gekennzeichnet und von Precompiler in Bibliotheksaufrufe umgewandelt. 4. Verwendung von standardisierten Schnittstellen zur Datenbank: (Call Level Interfaces). Vermeidung eines Precompilers (z.B. JDBC, ODBC) HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-2 1 Ebenen der DB-Anwendungsprogrammierung • Klassifikation der Anwendungsentwicklung mit Datenbanken – Fat Server/Thin Client: Anwendungsentwicklung im DBMS • Stored Procedures • Trigger – Fat Clients/Thin Server: Anwendungen laufen beim Client ab • Embedded SQL • SQL Call-Level-Interfaces Client … Client DBMS DB HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-3 6.1 Erweiterung von DB-Sprachen • Thin Client / Fat Server-Architekturen Client ProzedurAufruf Rückgabewerte DBMS Stored Procedure Trigger UDT HS 2013 Server Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-4 2 Fat Server Anwendungslogik innerhalb der Datenbank • Stored Procedures (TP-Lite) – Verwendung einer 4GL (forth generation language) • Turing-vollständiges SQL – Speicherung und Ausführung in der Datenbank – Standard unter SQL3 als “SQL/PSM” (= Persistent Stored Module). Kommerzielle DBMS verwenden jedoch proprietäre Dialekte, z.B. • PL/SQL in Oracle • TransactSQL in Sybase und MS SQL Server • Trigger • Benutzerdefinierte Datentypen (User Defined Types, UDTs) – Objektrelationale Erweiterung, Bestandteil von SQL-99 HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-5 Stored Procedures: Übersicht “Stored Procedure” Internal Procedure External Function Procedure Function CREATE PROCEDURE credit (amount NUMBER, accountno INTEGER) IS BEGIN UPDATE account SET balance = balance + amount WHERE account_number = accountno; END debit; Beispiel: Oracle PL/SQL Einbindung von C-Funktionen (Beispiel aus Oracle) CREATE LIBRARY C_utils AS '/DLLs/utils.so'; CREATE FUNCTION debit (amount NUMBER, accountno INT) RETURN INT AS LANGUAGE C LIBRARY C_utils NAME „debit_func"; HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-6 3 Beispiel: Oracle-PL/SQL • Procedural Language extensions to SQL – proprietäre 4GL-Sprache – SQL erweitert um klassische Programmiersprachen-Konstrukte – PL/SQL wurde erstmals 1991 in Oracle Version 6.0 von Oracle-DB-Servern unterstützt • Dient (unter anderem) zur Entwicklung von Stored Procedures in Oracle – Anwendungen, die in der DB gespeichert, verwaltet und auch dort ausgeführt werden • Ab Version 8i: Java VM innerhalb der DB – Java als Alternative zu PL/SQL möglich HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Oracle-PL/SQL: Block Header PL/SQL-Block • Header – Name des Blocks • Declaration Section: Angabe aller verwendeter – Variablen – Cursors – Sub-Blöcke • Execution Section – Programm-Code • Exception Section – Ausnahmeverarbeitung bei Fehlern – Warnungen IS Declaration Section BEGIN Execution Section EXCEPTION Exception Section END; HS 2013 DB-6-7 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-8 4 Oracle-PL/SQL: • Header Procedure, Function PROCEDURE name ( parameter, parameter, ...) IS FUNCTION name ( parameter, parameter, ...) RETURN type IS • Parameter – Variable Name, Direction, Type Dummy1 IN NUMBER, Dummy2 OUT NUMBER HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Oracle-PL/SQL: DB-6-9 Datentypen • Numerisch – BINARY_INTEGER, INTEGER, SMALLINT, INT, POSITIVE, NATURAL • Zeichenketten – CHAR, VARCHAR2, LONG • Binärdaten – RAW, LONG RAW • Verschiedenes – ROWID, BOOLEAN, DATE, NULL, CURSOR, TABLE • Verankerte Datentypen (Anchored) – %TYPE, %ROWTYPE • Konvertierung zwischen Datentypen – Implizit – explizit über Konvertierungsfunktionen: TO_CHAR, TO_NUMBER, TO_DATE, CHARTOROWID, CONVERT HEXTORAW, RAWTOHEX, ROWIDTOCHAR HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-10 5 Oracle-PL/SQL: • Declaration Section Deklaration von Variablen, Cursors, Subtypen, Records, Tables – variable_name NUMBER (2) [:= value]; – variable_name NUMBER (2) [DEFAULT value]; – variable_name schema.name%TYPE; • Deklaration, ohne den genauen Datentyp zu kennen (automatische Übernahme aus dem DB-Katalog) • Prozedur ist von späteren Änderungen des Datentyps in der entsprechenden Tabelle nicht betroffen – TYPE type_name IS RECORD ( name1 typ1, name2 typ2, ...); – TYPE type_name IS TABLE OF type; – SUBTYPE subtype_typname IS base_type; HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Oracle-PL/SQL: • DB-6-11 Cursors Eine Besonderheit von PL/SQL ist, dass immer nur einzelne Tupel zurückgegeben werden können, aber keine Mengen – Abhilfe: Cursor zur Iteration über eine Tupelmenge innerhalb der DB und zum Auslesen einzelner Tupel – Deklaration: • CURSOR • CURSOR – – – – HS 2013 Öffnen: Auslesen: Schliessen: Attribute: c1 IS SELECT empno, ename, sal FROM emp; c2 RETURN dept%ROWTYPE IS SELECT * FROM dept WHERE deptno = 10; OPEN c1; FETCH c1 INTO my_empno, my_ename, my_sal; CLOSE c1; %ISOPEN, %FOUND, %NOTFOUND, %ROWCOUNT Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-12 6 Oracle-PL/SQL: Wertübergabe DECLARE qty_on_hand NUMBER(5); new_order_id NUMBER(5); ... BEGIN SELECT quantity INTO qty_on_hand FROM inventory WHERE product_ID = 4711; ... new_order_id := 42; ... INSERT INTO ORDER(order_id, orderitem) VALUES (new_order_id, this_orderitem); HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Oracle-PL/SQL: Kontrollstrukturen • Verzweigungen: IF – THEN - END IF; IF – THEN – ELSE - END IF; IF – THEN – ELSIF – THEN - ELSE - END IF; • Schleifen: LOOP - EXIT WHEN - END LOOP; FOR counter IN start ... end LOOP - END LOOP; WHILE predicate LOOP - END LOOP; HS 2013 DB-6-13 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-14 7 Oracle-PL/SQL: Built-in Functions • Character Functions ASCII, CHR, CONCAT, INITCAP, INSTR, LENGTH, LOWER, LPAD, LTRIM, REPLACE, RPAD, RTRIM, SOUNDEX, SUBSTR, TRANSLATE, UPPER • Date Functions ADD_MONTHS, LAST_DAY, MONTHS_BETWEEN, NEW_TIME, NEXT_DAY, ROUND, SYSDATE, TRUNC • Numeric Functions ABS, ACOS, ASIN, ATAN, ATAN2, CEIL, COS, COSH, EXP(n), FLOOR, LN(a), LOG(a,b), MOD(a,b), POWER(a,b), ROUND(a,b), SIGN(a), SIN, SINH, SQRT, TAN, TAHH, TRUNC(a,b), DUMP, GREATEST, LAST, NVL, SQLCODE, SQLERRM, UID, USER, USERENV, VSIZE • Built-In Packages DBMS_STANDARD, DBMS_ALERT, DBMS_DDL, DBMS_JOB, DBMS_LOCK, DBMS_MAIL, DBMS_OUTPUT, DBMS_PIPE, DBMS_SESSION, DBMS_SNAPSHOT, DBMS_SQL, DBMS_TRANSACTION, DBMS_UTILITY HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Oracle-PL/SQL: • DB-6-15 Exception Section Exceptions bieten die Möglichkeit, auf vordefinierte Ausnahmen und auch auf individuell deklarierte (und explizit anzustossende) Ausnahmen zu reagieren DECLARE my_exception EXCEPTION; BEGIN ... IF ... THEN RAISE my_exception; ... EXCEPTION WHEN ZERO_DIVIDE THEN -- vordefinierte Ausnahme INSERT INTO ... VALUES ...; COMMIT; WHEN my_exception THEN Update ... SET ... ; ... WHEN OTHERS THEN -- Default-Fehlerbehandlung ROLLBACK; END; HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-16 8 Oracle-PL/SQL: Packages • Logisch zusammengehörige Prozeduren/Funktionen, die in der Datenbank gespeichert werden, lassen sich in Packages zusammenfassen • Eine Package besteht aus zwei Teilen: – Spezifikation. Diese enthält • globale Variablen • Konstanten • Interfaces der Funktionen und Prozeduren – Body mit der • Implementierung der Prozeduren bzw. Funktionen HS 2013 Oracle-PL/SQL: Web Data Management (CS261) – DB-Anwendungsprogrammierung Packages & Stored Procedures – Beispiel CREATE PACKAGE emps AS PROCEDURE hire ( empno INTEGER, empname VARCHAR2(50)) END emps; Spezifikation CREATE PACKAGE BODY emps AS PROCEDURE hire ( empno INTEGER, empname VARCHAR2(50)) IS BEGIN INSERT INTO employees VALUES (empno, empname); END hire; END emps; HS 2013 DB-6-17 Web Data Management (CS261) – DB-Anwendungsprogrammierung Implementierung DB-6-18 9 Oracle-PL/SQL: Zugriff auf Tabellen, Prozeduren, etc. [schema_name.][pkg_name.]object_name [params] • • Tabellen: – Select * from konto; – Select * from user.emp; (Tabelle in eigenem Schema) (Tabelle im Schema von Benutzer 'user') Prozeduren: – Aus SQL-Frontend (sqlplus) • execute user.emps.hire(10, ‘Bill Gates’); – Aus einer anderen Prozedur (execute nicht erforderlich) • finance.banking.abheben (100, 5004); • Funktionen: – Aus SQL-Frontend (sqlplus) • Select user.emps.foo( 10, empno) from emp; (Funktion foo wird für jedes Tupel von emp aufgerufen) • Select finance.banking.gesamtsaldo(‘Ogi’) from Dual; – Aus einer anderen Prozedur bzw. Funktion • finance.banking.gesamtsaldo(‘Ogi’) HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-19 6.2 Einbettung der DB-Sprache in Programmiersprache • Fat Client / Thin Server: Embedded SQL Embedded SQL Anwendung Call-Level SQL Anwendung SQL Client CLI Calls Präcompiler CLI-API (Application Program Interface) PräcompilerCall Level Interface Runtime Library Runtime Library DBMS-Treiber SQL-FAP (Format and Protocols), herstellerdefiniert, z.B. Net8 von Oracle DBMS DB HS 2013 Server Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-20 10 Embedded SQL (ESQL) • • Nach ISO SQL-92 definierte Einbettung von SQL in Programmiersprachen – z.B. Java (SQLJ), C, C++, Fortran, Pascal, Cobol, PL/1, Ada Precompiler ersetzt die SQL-Aufrufe in Calls der jeweiligen Runtime Library des verwendeten Datenbank-Servers – Bei Wechsel der Datenbank müssen ESQL-Programme nur neu kompiliert und gelinkt werden • Statisches ESQL – Alle SQL-Statements müssen bereits zur Compile-Zeit vollständig bekannt sein – Daher müssen auch alle verwendeten Datenbankobjekte zur Compile-Zeit vorhanden sein • Dynamisches ESQL – SQL-Statements werden erst zur Laufzeit erzeugt (dynamisches Generieren von Strings, die SQL-Anweisungen beinhalten) – Die verwendeten Datenbankobjekte müssen daher zur Compile-Zeit noch nicht existieren HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-21 Embedded SQL: Standardarchitektur • Beispiel: Einbettung von SQL in ein C-Programm ESQL/C-Quellprogramm (z.B. Lieferung.pc) DatenbankKatalog ESQL-Precompiler C-Quellprogramm (z.B. Lieferung.c) Zugriffsmodule/ Libraries C-Compiler & Linker Ausführbares Programm (z.B. Lieferung) HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung Datenbank DB-6-22 11 Kernprobleme bei der SQL-Einbettung • Die in Datenbanken verwendeten Datentypen (insbesondere Tupeltypen) sind nicht immer identisch mit den Datentypen der verwendeten Programmiersprache – Abhilfe: Abbildung von Tupeln bzw. Attributen der Datenbank (SQLDatentypen) auf die Datentypen der Programmiersprache und Möglichkeit der Verwendung von Variablen der Programmiersprache (Wirtsprogrammvariable bzw. Host Variables) in SQL-Anweisungen • SQL ist mengenorientiert. Das Ergebnis einer SQL-Anfrage ist eine Menge von Tupeln, die in der Programmiersprache geeignet verarbeitet werden müssen – Abhilfe: Möglichkeit zur Definition von Iteratoren (Schleifen) zur Verarbeitung von Tupelmengen (Cursor-Konzept). Auslesen des Cursor-Inhalts in Host Variablen zur weiteren Verarbeitung HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-23 Wirtsprogrammvariable (Host Variables) • Die Attribute eines Resultattupels einer SQL-Anfrage werden an speziell deklarierte Variable des Wirtsprogramms zugewiesen. Dazu ist eine Erweiterung des SQLStandards für die Einbettung in Programmiersprachen nötig – Die INTO-Klausel gibt an, welche Host Variable mit dem Ergebnis einer SQLAnfrage belegt werden soll. Wirtsprogrammvariablen dienen daher als „Übergabepuffer“ zwischen DBS und Programm. – Beispiel: EXEC SQL SELECT PNr, Menge, Status INTO :pnr, :menge, :status FROM Bestellungen WHERE BestNr = 555; • Analog können SQL-Anweisungen mittels solcher Variable mit Eingabeparametern versorgt werden. – Beispiele: EXEC SQL SELECT PNr, Menge, Status INTO :pnr, :menge, :status FROM Bestellungen WHERE BestNr = :bestnr; INSERT INTO Bestellungen (BestNr,Monat,Tag,KNr,PNr, Menge) VALUES (:bestnr, :monat, :tag, :knr, :pnr, :menge); HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-24 12 Beispiel: Embedded SQL – statisch ESQL/CQuellProgramm (SQL-Anweisungen bekannt) ESQL/C Präcompiler C-QuellProgramm mit SQL Anweisungen und ESQL/C Aufrufen • Beispiel: credit (int accountno) { EXEC SQL BEGIN DECLARE SECTION; NUMBER acc_no; NUMBER bal; • EXEC SQL END DECLARE SECTION; acc_no := accountno; EXEC SQL SELECT a.balance INTO :bal FROM account a WHERE a.account_number = :acc_no; • } HS 2013 CPräprozessor Compiler und Linker Ausführbares Programm Zur Compilezeit führt der Präcompiler u.a. folgende Prüfungen durch (mit Hilfe von Informationen aus dem Datenbank-Katalog): – Existenz von Tabellen und Attributen – Syntaxprüfung, Typenprüfung Zusätzliche Ersetzungen: – Die datenbankspezifischen Datentypen (Host Variables) werden durch Datentypen der jeweiligen Programmierumgebung ersetzt – Beispiel (ESQL/C): VARCHAR2(10) wird zu struct { unsigned short len; unsigned char arr[10]; } Ansatz ist recht unflexibel (da alle SQL-Statements zur Compile-Zeit bekannt sein müssen), jedoch: wenige Laufzeitfehler! Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-25 Indikatorvariable zum Erkennen von Nullwerten • Der Status einer SQL-Operation kann in den Wirtsprogrammen mit so genannten Indikatorvariablen abgefragt werden. Beispiel: EXEC SQL BEGIN DECLARE SECTION; int pnr; int vorrat; short vorrat_ind; EXEC SQL END DECLARE SECTION; ... EXEC SQL SELECT Vorrat INTO :vorrat:vorrat_ind FROM Produkte WHERE PNr = :pnr; if (vorrat_ind == 0) { /* kein Nullwert */ ... } else { /* Nullwert */ ... }; • Allgemein können Indikatorvariable folgende Werte haben: = 0 die entsprechende Wirtsprogrammvariable hat einen regulären Wert = -1 die entsprechende Wirtsprogrammvariable hat einen Nullwert > 0 die entsprechende Wirtsprogrammvariable enthält eine abgeschnittene Zeichenkette HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-26 13 Beispiel eines ESQL/C-Programms … • Programm: lieferung.pc – Variablendeklaration /*** Programm zur Erfassung und Durchführung von Lieferungen bereits bestellter Produkte***/ #include <stdio.h> #include <string.h> EXEC SQL INCLUDE SQLCA; /* Importieren der SQL Communication Area */ /* Innerhalb der SQL-Anweisungen ist Gross-/Kleinschreibung irrelevant. Sie dient hier nur zur Hervorhebung der SQL-Anweisungen */ /* Der Precompiler erzeugt an dieser Stelle die folgende Datenstruktur: struct sqlca { char sqlcaid[8]; long sqlabc; long sqlcode; struct {unsigned short sqlerrml; char sqlerrmc[70];} sqlerrm; char sqlerrp[8]; long sqlerrd[6]; char sqlwarn[8]; char sqlext[8]; }; struct sqlca sqlca; */ HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-27 … Beispiel eines ESQL/C-Programms … main (){ /* Deklaration der Wirtsprogrammvariablen */ EXEC SQL BEGIN DECLARE SECTION; /* Die hier deklarierten Wirtsprogrammvariablen unterliegen bei ihrer Verwendung in SQL-Ausdrücken einer Typprüfung durch den Precompiler. */ int bestnr; int pnr; int menge; VARCHAR status[10]; /* Der Precompiler erzeugt aus einer solchen Deklaration die folgende Struktur (am Beispiel von status): struct {unsigned short len; unsigned char arr[10];} status; */ VARCHAR user[20]; VARCHAR passwd[10]; EXEC SQL END DECLARE SECTION; /* Globale Fehlerbehandlung */ EXEC SQL WHENEVER SQLERROR STOP; HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-28 14 … Beispiel eines ESQL/C-Programms … • Verbindungsaufbau mit dem Datenbanksystem und Beginn einer Transaktion /* Verbindungsaufbau mit dem Datenbanksystem */ printf ("Benutzername?"); scanf ("%s", &(user.arr)); user.len = strlen(user.arr); /* Konvertierung von C-String in VARCHAR */ printf ("Kennwort?"); scanf ("%s", &(passwd.arr)); passwd.len = strlen(passwd.arr); /* Konvertierung von C-String in VARCHAR */ EXEC SQL CONNECT :user IDENTIFIED BY :passwd; /* gleichzeitig Beginn einer Transaktion */ /* Dialogschleife */ printf ("Bitte geben Sie eine Bestellnummer ein. (0 = Programmende)\n"); scanf ("%d", &bestnr); while (bestnr != 0) { EXEC SQL SELECT PNr, Menge, Status INTO :pnr, :menge, :status FROM Bestellungen WHERE BestNr = :bestnr; HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-29 … Beispiel eines ESQL/C-Programms … if (sqlca.sqlcode == 0) /* Testen des SQL-Returncodes */ { status.arr[status.len] = '\0'; /* Konvertierung von VARCHAR in C-String */ if (strcmp (status.arr, "neu") == 0) { EXEC SQL UPDATE Produkte SET Vorrat = Vorrat - :menge WHERE PNr = :pnr AND Vorrat >= :menge; if (sqlca.sqlcode == 0) /* Testen des SQL-Returncodes */ { strcpy (status.arr, "geliefert"); status.len = strlen (status.arr); EXEC SQL UPDATE Bestellungen SET Status = :status WHERE BestNr = :bestnr; } HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-30 15 … Beispiel eines ESQL/C-Programms • Verbindungsabbau und Ende einer Transaktion else printf ("\n *** Ungenügender Lagervorrat ***\n"); } else printf ("\n *** Lieferung bereits erfolgt ***\n"); } else printf ("\n *** Bestellung nicht gefunden ***\n"); EXEC SQL COMMIT WORK; /* Ende Transaktion und Beginn neue Transaktion */ printf ("Bitte geben Sie eine Bestellnummer ein. (0 = Programmende)\n"); scanf ("%d", &bestnr); }; /*while*/ exit (0); /* Verbindung mit dem DBS abbauen */ } /*main*/ HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-31 Fehlerbehandlung in ESQL … Fehler, die während der Abarbeitung von Embedded SQL-Programmen in der Datenbank auftreten, können durch geeignete, automatisch generierte Statusvariablen erkannt und dann auch behandelt werden. 1. Explizites Testen von sqlca.sqlcode im Wirtsprogramm nach einer SQLAnweisung: = 0 Anweisung korrekt ausgeführt, keine besonderen Vorkommnisse < 0 Fehler bei der Ausführung (siehe Fehlercodes im Manual) > 0 Anweisung ausgeführt, Auftreten eines Sonderfalls, z.B. signalisiert der Wert 1403, dass keine (weiteren) Treffertupel existieren Zusatzinformation in den restlichen Komponenten von sqlca, z.B.: sqlca.sqlerrd[2] Anzahl der Tupel, die von einer Insert-, Update- oder Delete-Anweisung betroffen waren sqlca.sqlerrm.sqlerrmc Fehlermeldung als Ascii-Text (max. 70 Zeichen) sqlca.sqlerrm.sqlerrml Länge der Fehlermeldung HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-32 16 … Fehlerbehandlung in ESQL 2. Deklaration von "Exception-Handling"-Strategien: EXEC SQL WHENEVER ( SQLERROR | NOT FOUND | SQLWARNING ) ( STOP | GOTO label | CONTINUE ) wobei SQLERROR einem SQLCODE < 0 entspricht, NOT FOUND dem SQLCODE 1403 und SQLWARNING einem SQLCODE > 0 (aber ungleich 1403). – Der ESQL-Precompiler erzeugt automatisch nach jeder SQL-Anweisung einen entsprechenden Vergleich mit sqlca.sqlcode, und zwar jeweils aufgrund der textuell letzten WHENEVER-Anweisung vor der SQL-Anweisung. HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-33 Cursor-Konzept: Verarbeitung von Tupelmengen • Zweck eines Cursors ist die Verarbeitung von Tupelmengen in einer nichtmengenorientierten Wirtsprogrammiersprache. Ein Cursor ist also notwendig für alle Anfragen mit mehr als einem Resultattupel. – Beispiel: Ausgabe aller Bestellungen eines Kunden ... printf ("Bitte geben Sie eine Kundennummer ein. (0 = Programmende)\n"); scanf ("%d", &knr); EXEC SQL DECLARE Kundeniterator CURSOR FOR SELECT Monat, Tag, Bez, Menge FROM Bestellungen WHERE KNr = :knr ORDER BY Monat DESC, Tag DESC; /* Cursor-Deklaration erfolgen immer ohne INTO-Klausel */ HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-34 17 Cursor-Konzept: Verarbeitung von Tupelmengen EXEC SQL OPEN Kundeniterator; /* An dieser Stelle werden die Eingabeparameter der SQLAnweisung (:knr) ausgewertet, und gedanklich wird hier die Resultattupelmenge ermittelt*/ found = TRUE; while (found) /* solange es noch Resultattupel gibt */ { EXEC SQL FETCH Kundeniterator INTO :monat, :tag, :bez, :menge; /* Hier werden die Wirtsprogrammvariable für die Resultattupel festgelegt. */ bez.arr[bez.len] = '\0'; if ((sqlca.sqlcode >= 0) && (sqlca.sqlcode != 1403)) printf ("%d.%d.: %d %s", tag, monat, menge, bez); else found = FALSE; }; /*while*/ EXEC SQL CLOSE Kundeniterator; /* Freigabe des Cursors & der damit verbundenen DB-Ressourcen*/ HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-35 Dynamisches ESQL • • • Ziel: Einbettung von SQL-Anweisungen, deren Struktur erst zur Laufzeit des Wirtsprogramms bekannt ist. Grobsyntax: QSTR := AufbauQueryString(InputParams); Execute QSTR; Es wird als ein Programm (= SQL-Anweisung oder Folge davon) innerhalb des laufenden Programms erzeugt und ausgeführt Beispiele für Anwendungen, die dynamisches ESQL erfordern: – SQL*Plus und ähnliche universelle, interaktive DBS-Schnittstellen sind Programme, die dynamisches ESQL verwenden. – Anwendungen, die sowohl Daten als auch Metadaten (Relationen des DBKatalogs) verarbeiten, benötigen in vielen Fällen dynamisches ESQL. Solche Anwendungen sind mit dynamischem ESQL realisierbar, weil in praktisch allen relationalen DBS der DB-Katalog in Form von Relationen zugreifbar ist. HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-36 18 Beispiel: Embedded SQL – dynamisch ESQL/CQuellProgramm C-QuellProgramm mit SQL ESQL/C Präcompiler (SQL-Anweisungen bekannt) CPräprozessor Compiler und Linker Anweisungen und ESQL/C Aufrufen Ausführbares Programm Das SQL Statement ist erst zur Laufzeit bekannt – Der Precompiler kann weniger char *table) { Überprüfungen durchführen char dyn_stmt[120]; – Mehr Flexibilität sprintf(dyn_stmt, "UPDATE %s SET balance = balance + – Aber auch mehr Laufzeitfehler möglich! :a WHERE account_number = :ano“, table); EXEC SQL PREPARE sql_stmt FROM :dyn_stmt; EXEC SQL EXECUTE sql_stmt USING :amount, :accountno; Beispiel: credit( int amount, int accountno, • } HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-37 Erweiterungen der SQL-Syntax für Embedded SQL DECLARE cursor OPEN cursor FETCH cursor CURSOR FOR ordered_query : INTO variable , CLOSE cursor table DELETE FROM CURRENT OF WHERE cursor , NULL UPDATE table SET column = expression ( WHERE HS 2013 Unordered_query CURRENT OF Web Data Management (CS261) – DB-Anwendungsprogrammierung ) cursor DB-6-38 19 6.3 Verwendung von standardisierten Schnittstellen • Fat Client / Thin Server: Call-Level SQL Embedded SQL Anwendung Call-Level SQL Anwendung SQL Client CLI Calls Präcompiler CLI-API (Application Program Interface) PräcompilerCall Level Interface Runtime Library Runtime Library DBMS-Treiber SQL-FAP (Format and Protocols), herstellerdefiniert, z.B. Net8 von Oracle DBMS DB HS 2013 Server Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-39 SQL Call-Level Interface (CLI) • Call Level Interfaces sind standardisierte Schnittstellen zur Kommunikation mit Datenbanken ohne Präcompiler – CLI-API erlaubt das Erstellen und Ausführen von SQL-Anweisungen zur Laufzeit (in ähnlicher Weise wie beim dynamischen embedded SQL) • SQL/CLI: Standard seit 1996 – Ursprung in Aktivitäten der SQL Access Group (SAG) mit dem Ziel, einen vereinheitlichten Zugriff auf Datenbanken bereitzustellen – Ist auch Bestandteil von SQL3 • SQL/CLI beinhaltet – DB-Verbindungsaufnahme und Beendigung – Vorbereitung und Ausführen von SQL-Anweisungen (“prepare” und “execute”) – Binden von Parametern an SQL-Anweisungen (“bind”) – Entgegennahme von Resultaten – Festlegung von Datentypen (über spezielle Codes für jeden Datentyp) • CLI-Call wird durch den proprietären DBMS-Treiber umgesetzt in herstellerspezifischen DB-Zugriff – Mit geeignetem Treiber kann prinzipiell jede Datenquelle angesprochen werden HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-40 20 CLI-Dialekte • • Neben standardisiertem SQL/CLI haben sich noch weitere Dialekte herausgebildet – ODBC (Open Database Connectivity): Microsofts CLI-Variante • Beinhaltet die meisten (nicht alle) API-Calls des CLI-Standards • Zusätzlich: spezielle Calls zur Unterstützung von Microsoft-Programmen (Access, Excel, etc.) – Proprietäre CLIs der DB-Hersteller (“Native API”) • z.B. Oracle Call Interface (OCI) In der Regel werden von einem Datenbanksystem mehrere CLI-Dialekte parallel unterstützt ODBC-API SQL/CLI-API Native API Call Level Interface Runtime Library DBMS-Treiber HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-41 Beispiel (CLI): SQL99 CLI #include "sqlcli.h" extern SQLHDBC hdbc; extern SQLHENV henv; /* Verbindung steht schon */ /* Umgebung */ void credit ( SQLHSTMT hstmt, int amount, int accountno , char *table) { /* hstmt wird von aussen gegeben, damit Transaktionskontrolle ausserhalb dieser Prozedur. "credit" ist Baustein */ char update[120]; SQLINTEGER NameParamLength1; SQLINTEGER NameParamLength2; sprintf(update, "UPDATE %s SET balance = balance + ? WHERE account_number = ? ", table); SQLPrepare(hstmt, update, SQL_NTS); SQLBindParameter(hstmt, 1, SQL_PARAM_MODE_IN, SQLCHAR, SQL_CHAR, NAME_LENGTH, 0 &amount, NAME_LENGTH, &NameParamLength1); SQLBindParameter(hstmt, 2, SQL_PARAM_MODE_IN, SQLCHAR, SQL_CHAR, NAME_LENGTH, 0 &accountno, NAME_LENGTH, &NameParamLength2); SQLExecute(hstmt); } HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-42 21 Beispiel (CLI): Oracle-Dialekt (OCI) #include “oci.h” extern static OCIEnv *envhp; void credit (OCIStmt *stmthp, int amount, int accountno , char *table) { char update[120]; static OCIBind *bnd1p = (OCIBind *) 0; sprintf(update, “UPDATE %s SET balance = balance + :a WHERE account_number = :ano “, table); OCIStmtPrepare(stmthp, errhp, update, (ub4) strlen((char *update), (ub4) OCI_NTV_SYNTAX, (ub4) OCI_DEFAULT)); OCIBindByName(stmthp, &bnd1p, errhp, (char *) ":A", -1, (dvoid *) &amount, (sword) sizeof(accountid), SQLT_INT, (dvoid *)0, (ub2 *)0, (ub2 *)0, (ub4)0, (ub4 *)0,OCI_DEFAULT); OCIBindByName(stmthp, &bnd1p, errhp, (char *) ":ANO", -1, (dvoid *) &accountno, (sword) sizeof(accountid), SQLT_INT, (dvoid *) 0, (ub2 *) 0, (ub2 *) 0, (ub4) 0, (ub4 *) 0, OCI_DEFAULT); OCIStmtExecute(svchp, stmthp, errhp, (ub4) 1, (ub4) 0, (CONST OCISnapshot *) NULL, (OCISnapshot *) NULL, OCI_DEFAULT); } HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-43 Object CLI • • Weiterentwicklung von CLI zu Objektschnittstellen (SQL/CLI kennt nur prozedurale APIs) – JDBC (Java Database Connection) – ActiveX Data Objects (ADO) Unterstützung von JDBC – Entweder “direkt” durch Native-API – Oder Umweg über JDBC-ODBC-Bridge Java-Anwendung JDBC-API JDBC-Treiber-Manager JDBC-ODBCBridge SQL/CLI-API JDBC-Native Treiber ODBC-API Native API Call Level Interface Runtime Library DBMS-Treiber HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-44 22 JDBC • JDBC (Java Database Connectivity) besteht aus einer Menge von Java-Klassen und Schnittstellen, die die Verwendung von SQL in Java-Programmen ermöglichen – Java Package java.sql. Definiert Schnittstellen für das • • • • Aufbauen von Verbindungen zur Datenbank dynamische Erstellen von SQL Statements Ausführen der Statements Verarbeiten der Ergebnismengen – Java Package javax.sql. Schnittstellen für server-seitige Verarbeitung • Aktuelle Informationen zu JDBC (Treiber, etc.) sind unter folgender URL zu finden: http://www.oracle.com/technetwork/java/javase/tech/indexjsp-136101.html HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-45 JDBC: Java Package java.sql DriverManager Connection Statement ResultSet • java.sql.DriverManager: Möglichkeit zum Registrieren von Treibern sowie zum Aufbau von Verbindungen zur Datenbank • java.sql.Connection: Repräsentation einer Verbindung zur Datenbank • java.sql.Statement: ermöglicht die Ausführung von SQL-Anweisungen über eine gegebene Verbindung • java.sql.ResultSet: verwaltet die Ergebnisse einer Anfrage in Form einer Relation und unterstützt den Zugriff HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-46 23 JDBC: Beispiel … Ablauf einer JDBC-Datenbankanwendung: 1. Aufbau einer Datenbankverbindung (inklusive Laden eines geeigneten Treibers) 2. Senden einer SQL-Anweisung 3. Verarbeiten der Anfrageergebnisse 4. Freigabe der Ressourcen 5. Fehlerbehandlung import java.sql.*; public class JdbcExample { public static void main (String[] args) { ... HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-47 … JDBC: Beispiel … Aufbau einer Datenbankverbindung • Voraussetzung ist das Laden eines Treibers – Explizit im Programm: Class.forName ("oracle.jdbc.OracleDriver"); – Implizit durch Angabe in der Systemeigenschaft (Property) jdbc.drivers Diese werden dann automatisch geladen • Verbindungsaufbau – Methode getConnection() aus Klasse java.sql.DriverManager. – Parameter sind URL der Datenbank (jdbc:<subprotocol>:<subname>), UserID und Passwort. • <subprotocol> enthält in der Regel der Name des Datenbanksystems und des Treibertyps • <subname> der Name der DB-Instanz HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-48 24 … JDBC: Beispiel … ... String driverClass = "oracle.jdbc.OracleDriver"; try { Class.forName (driverClass); } catch (ClassNotFoundException exc) { System.out.println (exc.getMessage()); System.exit(1); } try { String url = "jdbc:oracle:oci:@mydb.com:1233/testdb"; Connection con = DriverManager.getConnection(url, "user", "password"); HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-49 … JDBC: Beispiel … Senden einer SQL-Anweisung und Verarbeiten des Ergebnisses • createStatement() bereitet ein SQL-Statement für eine existierende Verbindung vor • executeQuery(query) führt eine (dynamisch erzeugte) Anfrage query in der Datenbank aus • Ergebnis ist eine Tupelmenge ResultSet • die Ergebnismenge der Anfrage wird mittels eines implizit vorhandenen Cursors (dieser muss nicht wie bei embedded SQL explizit deklariert werden) verarbeitet – Die Methode next() ermöglicht das Springen zum nächsten Tupel im ResultSet – next() liefert so lange true bis das Ende der Tupelmenge erreicht ist – Für den Zugriff auf einzelne Attribute stehen geeignete get-Methoden zur Verfügung (z.B. getString, getInt, etc.). Parameter dieser getMethoden im Cursor sind die Nummern der jeweiligen Attribute im Cursor bzw. in der Anfrage (beginnend mit 1) HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-50 25 … JDBC: Beispiel … ... String query = "SELECT Knr, name, saldo FROM Kunde"; Statement stmt = con.createStatement (); ResultSet rs = stmt.executeQuery(query); while (rs.next()) { int i = rs.getInt(1); String s = rs.getString(2); double d = rs.getDouble(3); System.out.println(i + ", " } HS 2013 /* lese Kundennummer */ /* lese Name */ /* lese Saldo */ + s + ", " + d + "CHF"); Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-51 … JDBC: Beispiel … Freigabe der Ressourcen • Explizites Schliessen von ResultSet und Statement • Ist eigentlich optional (da diese Aufgabe auch der garbage collector übernehmen kann); es ist jedoch empfehlenswert, die Ressourcen explizit freizugeben, da ein Cursor evtl. auch viele Ressourcen des Datenbanksystems bindet. ... rs.close(); stmt.close(); ... HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-52 26 … JDBC: Beispiel … Fehlerbehandlung • Fehler werden als Ausnahme der Klasse SQLException signalisiert • Details zu einem aufgetretenen Fehler können über die Methode getMessage() entnommen werden ... } catch (SQLException sqlexc) { System.out.println("SQLException: " + sqlexc.getMessage()); } } } HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-53 … JDBC: Beispiel • In JDBC können neben SELECT … Anfragen auch andere SQL-Statements ausgeführt werden (INSERT, UPDATE, DELETE) oder auch DDL-Statements (CREATE TABLE, DROP TABLE, …) • • Diese Operationen liefern keine Ergebnismengen zurück, benötigen also keinen Cursor Für diese Operationen steht die Methode execUpdate() zur Verfügung. Rückgabewert ist die Anzahl der betroffenen Tupel (bei INSERT, UPDATE, DELETE) bzw. 0 bei DDL-Statements. • Beispiel: String update = "UPDATE Kunde SET Stadt = ‘Basel’ WHERE Knr > 4"; Statement stmt = con.createStatement (); int rows = stmt.executeUpdate(update); HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-54 27 JDBC: PreparedStatement ... • • • Wenn in einem Java-Programm eine SQL-Anfrage mehrfach ausgeführt werden soll (jedoch mit jeweils unterschiedlichen Parametern), dann ist es sehr aufwändig, jedes Mal erneut den SQL-String im Java-Programm zu erstellen, ihn an die Datenbank zu schicken, etc. Die Schnittstelle PreparedStatement erlaubt es, eine Anfrage einmal (vor der Ausführung) zum DBMS zu schicken. Dort wird das SQL Statement kompiliert und damit zur Ausführung vorbereitet. Die Eingabeparameter der PreparedStatements müssen mit ? gekennzeichnet werden. Die Zuordnung von Werten zu vorher definierten Eingabeparametern erfolgt über deren Position im PreparedStatement HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-55 … JDBC: PreparedStatement • Beispiel: ... String prep = "INSERT INTO Kunde Values (?, ?, ?, ?, ?)"; PreparedStatement pstmt = con.prepareStatement (prep); pstmt.setInt(1, 4711); pstmt.setString(2, 'Federer'); pstmt.setString(3, 'Lausanne'); pstmt.setDouble(4, 1500.20); pstmt.setDouble(5, 0.15); int i = pstmt.executeUpdate(); /* /* /* /* /* Parameter Parameter Parameter Parameter Parameter 1: 2: 3: 4: 5: Knr Name Stadt Saldo Rabatt pstmt.setInt(1, 4712); /* neue Belegung für /* nächsten Aufruf */ */ */ */ */ */ */ ... HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-56 28 JDBC: CallableStatement … • In JDBC lassen sich auch Fat Server-Konstrukte (Stored Procedures) in JavaProgrammen nutzen (Aufruf von Stored Procedures aus Java-Programmen heraus – sofern die verwendete Datenbank Stored Procedures unterstützt) • Parameter werden im CallableStatement wieder mit dem Platzhalter ? gekennzeichnet. Zusätzlich muss die „Richtung“ der Parameter angegeben werden: IN, OUT oder INOUT • CallableStatement ist von PreparedStatement abgeleitet. Daher stehen alle Methoden zum Setzen der Parameter zur Verfügung (Angabe von Positionsnummer innerhalb des Strings und Wert) • Bei OUT und INOUT-Parametern muss vor der Ausführung deren JDBC-Typ festgelegt werden. Dies geschieht mit Hilfe der Methode registerOutParameter HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-57 … JDBC: CallableStatement • Beispiel: ... String call = "CALL deposit (?, ?, ?)"; /* erster Parameter: Kontonummer (IN) zweiter Parameter: Einzahlungsbetrag (IN) dritter Parameter: neuer Kontostand (OUT) */ CallableStatement cstmt = con.prepareCall (call); cstmt.setInt(1, 13579); /* Angabe Kontonummer */ cstmt.setDouble(2, 98.5); /* Angabe Betrag */ cstmt.registerOutParameter(3, java.sql.Types.float); cstmt.executeUpdate(); double kontostand = cstmt.getDouble(3); ... HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-58 29 Datentypen • SQL und Java besitzen jeweils eigene Typsysteme • Bei der Abbildung zwischen SQL und Java müssen auch die SQL-Datentypen (JDBC-Datentypen) auf Java-Datentypen abgebildet werden. Dies ist insbesondere wichtig – beim Zugriff auf Tupel-Attribute in einem ResultSet mit Hilfe der get...-Methoden – bei der Übergabe von Parametern an ein PreparedStatement mit set...-Methoden – beim Zugriff auf die OUT-Parameter eines CallableStatement HS 2013 JDBC-Typ Java-Typ CHAR String VARCHAR String NUMERIC java.math.BigDecimal DECIMAL java.math.BigDecimal SMALLINT short INTERGER int BIGINT long REAL float FLOAT double ... ... Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-59 Zusammenfassung: Fat Server vs. Fat Client • Fat Client-Architekturen • Traditioneller Ansatz in der zweistufigen Client/Server-Welt + Ausnutzen der Datenunabhängigkeit, die vom DB-Server bereitgestellt wird + Standardisierte Schnittstellen + Gute Unterstützung eigener, individueller Anwendungen + Anwendungen lassen sich recht schnell entwickeln (z.B. mit Hilfe grafischer Entwicklungswerkzeuge) – Problem der Wartung, Software-Verteilung, etc. (Upgrades von Anwendungen, die von vielen Clients verwendet werden, sind recht aufwändig) • Fat Server-Architekturen + Einfachere Wartbarkeit (da zentrale Definition des Anwendungscodes) + Weniger Netzwerkbelastung (durch stärkeren Abstraktionsgrad der bereitgestellten Prozeduren) – Schlechte Unterstützung für individuelle, personalisierte Anwendungen – Entwicklungsumgebungen sind in der Regel schlechter im Vergleich zu Fat Client-Anwendungen HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-60 30 Ergänzende Literatur zu Kapitel 6 • [Neu 92] K. Neumann: Kopplungsarten von Programmiersprachen und Datenbanksprachen, Informatik-Spektrum Band 15, Heft 4, August 1992, pp. 185-194 • [SS 03] G. Saake, K.-U. Sattler: Datenbanken und Java – JDBC, SQLJ, ODMG und JDO. dpunkt.verlag, 2003. HS 2013 Web Data Management (CS261) – DB-Anwendungsprogrammierung DB-6-61 31