Embedded SQL v C/C++ úvod Administrace Oracle Kateřina Opočenská
Motivace potřeba začlenit komunikaci s databází do aplikace v nějakém vyšším programovacím jazyce řešení (na Oracle): a) OCI (Oracle Call Interface) přímý přístup k funkcím, rychlejší, ale programátorsky náročnější b) Embedded SQL přehlednější, uživatel odstaven od znalostí API daného SQL serveru
Embedded SQL Tento referát je o Embedded SQL pro C/C++ SQL lze ale na Oracle začlenovat i do jiných jazyků (např. Cobol, Fortran)
Jak to funguje Do zdrojového kódu v C/C++ píšeme speciálně uvozené SQL příkazy soubor.pc Prekompilátor Pro*C/C++ (proc) tyto dotazy nahradí voláním funkcí standardní run-time knihovny (SQLLIB) a převede soubor.ps do čistého C/C++. soubor.c Dále se už kód překládá jako obyčejný céčkový zdroják. Na konci se k němu přilinkuje SQLLIB soubor.obj, spustitelný program
Syntaxe Pro*C Základní pravidla pro psaní SQL příkazů do C-kódu: 1) všechny SQL příkazy jsou uvozeny direktivou EXEC SQL a končí středníkem ; 2) při použití proměnných v SQL příkazech musí být tyto proměnné uvozeny dvojtečkou : (odlišení od databázových polí), v C-kódu se píší normálně
Příklad: základní syntaxe Pro*C SELECT INTO FROM EXEC SQL BEGIN DECLARE SECTION; int plat_sefa; EXEC SQL END DECLARE SECTION; /*... */ EXEC SQL SELECT plat INTO :plat_sefa FROM Zamestnanci WHERE id_zam = 123; /*... */ printf("sefuv plat: %d\n", plat_sefa); /*... */
Příklad: základní syntaxe Pro*C INSERT INTO VALUES typedef struct { int id; char name[20]; }rec; EXEC SQL BEGIN DECLARE SECTION; Myrec rec; EXEC SQL END DECLARE SECTION; Myrec.id=5; strcpy(myrec.name,"user5"); EXEC SQL INSERT INTO Lide VALUES (:Myrec);
Deklarativní část všechny deklarace mezi EXEC SQL BEGIN DECLARE SECTION; a EXEC SQL END DECLARE SECTION; určují, jaké proměnné se budou používat pro komunikaci mezi programem a databází (načítání dat i zápis, indikátory) těmto proměnným se také říká hostitelské proměnné (host variables)
Typy hostitelských proměnných char, int, short, long, float, double + pointery na ně, pole VARCHAR[n] pseudotyp pro stringy rozpoznávaný přímo prekompilátorem Pro*C/C++ v podstatě céčkový struct se 2 položkami: arr pole charů len délka pole
Implicitní konverze datových typů SQL VARCHAR DATE INTEGER NUMBER(P,S) CHAR(X) Pro*C/C++ VARCHAR[n], char VARCHAR[n], char[] int char, short, int, long, float, double, char[n], VARCHAR[n] char[n],varchar[n],int,short,long,float,doule
Příklad: spojení s databází EXEC SQL BEGIN DECLARE SECTION; char username[20]; char password[20]; EXEC SQL END DECLARE SECTION; strcpy(username, "uzivatel"); strcpy(password, "heslo"); EXEC SQL CONNECT :username IDENTIFIED BY :password; /* práce s databází */ EXEC SQL COMMIT WORK RELEASE; /* potvrzení změn, odpojení */
Spojení s databází - doplnění: Pouze ukončení transakce: EXEC SQL COMMIT; Storno změn: EXEC SQL ROLLBACK; Storno změn + odpojení: EXEC SQL ROLLBACK WORK RELEASE;
Připojení k databázi podrobněji Kompletní syntaxe CONNECTu: EXEC SQL CONNECT { :user IDENTIFIED BY :oldpswd :usr_psw } [[ AT { dbname :host_variable }] USING :connect_string ] [ {ALTER AUTHORIZATION :newpswd IN { SYSDBA SYSOPER } MODE} ] ;
Připojení k databázi Dvě ekvivalentní možnosti zápisu: EXEC SQL CONNECT :username IDENTIFIED BY :password; username a password jsou typu char[n],char* nebo VARCHAR[n] EXEC SQL CONNECT :usr_psw; usr_psw = "username/password "; Připojení k jiné databázi: EXEC SQL CONNECT USING db; db = semora ; Login a heslo nelze uvádět přímo! NE: EXEC SQL CONNECT "scott" IDENTIFIED BY "tiger";
Indikátorové proměnné #1 motivace: co uložit do proměnné, když SELECT vrátí NULL? řešení: indikátor, který ukáže, zda (a jak) je hostitelská proměnná korektně naplněna
Indikátorové proměnné #2 proměnné typu short deklarovány v deklarační sekci stejně jako hostitelské proměnné svázané vždy s jednou konkrétní hostitelskou proměnnou indikují, co je v hostitelské proměnné obsaženo za hodnotu (NULL flags, ořezání řetězce) v rámci SQL příkazů také uvozeny : následují vždy bezprostředně za příslušnou hostitelskou proměnnou (pro přehlednost lze oddělit klíčovým slovem INDICATOR)
Příklad: indikátorové proměnné EXEC SQL SELECT plat INTO :plat_sefa :plat_sefa_id FROM Zamestnanci WHERE id_zam = 123; /*... */ if (plat_sefa_id == 0){ printf("sefuv plat: %d\n", plat_sefa); }
Návratové hodnoty identifikátorů v SELECT INTO indikátor -1 0-2 >0 hostitelská proměnná nedefinovaná hodnota (NULL v databázi) korektní naplnění vkládaná hodnota je větší než proměnná a není možné určit skutečnou velikost vkládaná hodnota je větší než proměnná, skutečná velikost je hodnota indikátoru
Návratové hodnoty identifikátorů v INSERT/UPDATE indikátor -1 >=0 databáze uložena hodnota NULL uložena korektní hodnota
Základní ošetření chyb #1 EXEC SQL WHENEVER <cond> <action>; Kdykoliv je splněna podmínka <cond>, automaticky se vyvolá akce <action> příkazy se vzájemně překrývají #include <sqlca.h> Možné podmínky (a kdy jsou splněny): NOT FOUND kritériům SELECT/FETCH neodovídá žádná položka SQLERROR nějaký příkaz SQL EXEC skončil chybou SQLWARNING nějaký příkaz SQL EXEC skončil s varováním
Základní ošetření chyb #2 Možné akce: CONTINUE DO <stmt> GOTO <label> STOP pokud lze, pokusí se program pokračovat dalším příkazem vykoná se příkaz <stmt>, typicky volání fce / exit skok na daný label volání exit(), ukončení programu, nepotvrzené akce jsou stornovány (rollback)
Příklad: ošetření chyb při připojování k databázi: EXEC SQL WHENEVER SQLERROR DO sql_error( Nelze se pripojit ); SELECTy v cyklu (pomocí kurzoru): EXEC SQL WHENEVER NOT FOUND DO break;
Více o Oracle Pro*C/C++ Pro*C/C++ Programmer's Guide http://mates.ms.mff.cuni.cz/intra/oracle/doc/ora804nt/appdev.804 /a58233/toc.htm Introduction to Pro*C Embedded SQL http://www-db.stanford.edu/~ullman/fcdb/oracle/or-proc.html Embedded SQL FAQ https://www1.columbia.edu/sec/acis/dba/oracle/faq-esql.html Oracle Precompiler FAQ http://www.orafaq.com/faqpro.htm