Unter Embedded SQL versteht man die Einbettung von SQL-Befehlen innerhalb eines Anwendungsprogramms. Das Anwendungsprogramm heißt Host Programm, die in ihm verwendete Sprache heißt Host-Sprache.
Oracle unterstützt Embedded SQL im Zusammenspiel mit den Programmiersprachen C und C++ durch den Pre-Compiler Pro*C/C++. Abbildung 9.5 zeigt den prinzipiellen Ablauf: Das mit eingebetteten SQL-Statements formulierte Host-Programm hallo.pc wird zunächst durch den Pre-Compiler unter Verwendung von SQL-spezifischen Include-Dateien in ein ANSI-C-Programm hallo.c überführt. Diese Datei übersetzt ein konventioneller C-Compiler unter Verwendung der üblichen C-Include-Files in ein Objekt-File hallo.o. Unter Verwendung der Oracle Runtime Library wird daraus das ausführbare Programm hallo.exe gebunden.
Eingebettete SQL-Statements werden durch ein vorangestelltes EXEC SQL gekennzeichnet und ähneln ansonsten ihrem interaktiven Gegenstück. Zum Beispiel werden durch
EXEC SQL COMMIT;
die seit Transaktionsbeginn durchgeführten Änderungen permanent gemacht.
Die Kommunikation zwischen dem Host-Programm und der Datenbank geschieht über sogenannte Host-Variablen, die im C-Programm deklariert werden. Eine Input-Host-Variable überträgt Daten des Hostprogramms an die Datenbank, eine Output-Host-Variable überträgt Datenbankwerte und Statusinformationen an das Host-Programm. Hostvariablen werden innerhalb von SQL-Statements durch einen vorangestellten Doppelpunkt (:) gekennzeichnet.
Für Hostvariablen, die Datenbankattributen vom Typ VARCHAR2 entsprechen, empfiehlt sich eine Definition nach folgendem Beispiel:
VARCHAR fachgebiet[20];
Daraus generiert der Pre-Compiler eine Struktur mit einem Character-Array und einer Längen-Komponente:
Bevor diese Struktur als Null-terminierter String genutzt werden kann, muß das Null-Byte explizit gesetzt werden:struct { unsigned short len; unsigned char arr[20]; } fachgebiet;
fachgebiet.arr[fachgebiet.len] = '\0';
Mit einer Hostvariable kann eine optionale Indikator-Variable assoziiert sein, welche Null-Werte überträgt oder entdeckt. Folgende Zeilen definieren unter Verwendung des Oracle-spezifischen Datentyps VARCHAR eine Struktur prof_rec zum Aufnehmen eines Datensatzes der Tabelle Professoren sowie eine Indikator-Struktur prof_ind zum Aufnehmen von Status-Information.
struct{ int persnr; VARCHAR name [15]; char rang [2]; int raum; } prof_rec; struct { short persnr_ind; short name_ind; short rang_ind; short raum_ind; } prof_ind;
Folgende Zeilen transferieren einen einzelnen Professoren-Datensatz in die Hostvariable prof_rec und überprüfen mit Hilfe der Indikator-Variable prof_ind, ob eine Raumangabe vorhanden war.
EXEC SQL SELECT PersNr, Name, Rang, Raum INTO :prof_rec INDICATOR :prof_ind FROM Professoren WHERE PersNr = 2125; if (prof_ind.raum_ind == -1) printf("Personalnummer %d hat keine Raumngabe \n", prof_rec.persnr);
Oft liefert eine SQL-Query kein skalares Objekt zurück, sondern eine Menge von Zeilen. Diese Treffer werden in einer sogenannten private SQL area verwaltet und mit Hilfe eines Cursors sequentiell verarbeitet.
EXEC SQL DECLARE prof_cursor CURSOR FOR SELECT PersNr, Name, Rang, Raum FROM Professoren WHERE Rang='C4'; EXEC SQL OPEN prof_cursor; EXEC SQL WHENEVER NOT FOUND DO break; for (;;) { EXEC SQL FETCH prof_cursor INTO :prof_rec; printf("Verarbeite Personalnummer %d\n", prof_rec.persnr); } EXEC SQL CLOSE prof_cursor;
Listing 9.4. zeigt ein Embedded-SQL-Programm, die davon erzeugte Ausgabe zeigt Abb. 9.6.
Listing 9.4: Beispiel für embedded SQL