Embedded SQL Vtzslav Imrek Embedded SQL je dobrm
Embedded SQL Vítězslav Imrýšek
Embedded SQL je dobrým jazykem pro definování databází a vytváření dotazů nad daty databáze SQL není ideálním jazykem pro vytváření sofistikovaných databázových aplikací Potřeba využití vyššího programovacího jazyka (například C / C++)
Embedded SQL Základní myšlenkou Embedded SQL je možnost využití SQL výrazů v programu napsaném v nějakém vyšším jazyce. . printf(); EXEC SQL. . . scanf(); Preprocesor zanalyzuje kód, přeloží SQL výrazy do systémových volání C/C++ a nakonec vygeneruje samotný program.
Hostitelské proměnné SQL výrazy jsou zabudované v programu Potřeba pro mechanismus, který bude předávat hodnoty mezi prostředím C programu a SQL výrazy, které komunikují s SQL serverem. Speciální proměnné určené pro tento účel nazýváme Hostitelské proměnné. Definovány v bloku mezi begin declare section a end declare section Musí být kompatibilní s datovými typy sloupců tabulky v DB EXEC SQL begin declare section int cno; varchar cname[31]; varchar street[31]; int zip; char phone[31]; EXEC SQL end declare section
Hostitelské proměnné /* varchar cname[31] */ struct { unsigned short len; unsigned char arr[31]; } cname; Při zasílání varchar hodnoty do databáze je prací programátora správně vypnit hodnoty len a arr. Při získání varchar hodnoty z databáze jsou obě pole správně vyplněny systémem
Konverze datových typů Oracle Data Type C Data Type char(N) varchar(N) date number(6) number(10) number(6, 2) char array[N+1] varchar array[N+1] char array[10] int long int float
Hostitelské proměnné jsou v jazyce C používány stejně jako standardní proměnné. Pouze v případě, kdy jsou použity v SQL dotazu, je nutné před tyto proměnné umístit dvojtečku „: “. Pozn. : Přiřazení hodnoty k proměnné pomocí příkazu select into lze použít pouze v případě, můžeme zaručit, že dotaz vrátí právě jednu, či žádnou položku. (řeší tzv. Kurzory, více později) scanf(“%d“, &cno); EXEC SQL select into from where cname : cname customers cno = : cno; scanf(“%d%s%s%d%s“, &cno, cname. arr, street. arr, &zip, phone); cname. len street. len = strlen(cname. arr); = strlen(street. arr); EXEC SQL insert into customers values(: cno, : cname, : street, : zip, : phone);
Indikátorové proměnné SQL obsahuje hodnotu null, tato hodnota ovšem nemá v jazyce C odpovídající protějšek. Příklad: V SQL může mít datový typ integer hodnotu null. V C toto není možné. Pro vyřešení problému komunikace null hodnoty Embedded SQL poskytuje tzv. Indikátorové proměnné. Pomocná proměnná typu integer Každý atribut má jednu Možné hodnoty: -1: položka má hodnotu null 0: položka nemá hodnotu null
Indikátorové proměnné - příklad EXEC SQL begin declare section; struct { int ono; int cno; int eno; char received[12]; char shipped[12]; } order_rec; struct { short ono_ind; short cno_ind; short eno_ind; short received_ind; short shipped_ind; } order_rec_ind; int onum; EXEC SQL end declare section; scanf(“%d“, &onum); EXEC SQL select * into : order_rec indicator : order_rec_ind from orders where ono = : onum; if(order_rec_ind. shipped_ind == -1) printf("SHIPPED is Nulln"); else printf("SHIPPED is not Nulln");
Indikátorové proměnné Pro vložení hodnoty null do databáze: nastaví se hodnota -1 do příslušné indikátorové proměnné indikátorová dotazu. proměnná se využije v insert|update onum = 1021; order_rec_ind. shipped_ind = -1; EXEC SQL update orders set shipped = : order_rec. shipped indicator : order_rec_ind. shipped_ind where ono = : onum;
SQL Communications Area (sqlca) Oznámení o stavu zpracování dotazu. Pro použití sqlca je nutné brzy v programu použít následující příkaz: EXEC SQL include sqlca; Okamžitě po zpracování dotazu dojde k vyplnění proměnné „sqlca“. Možné hodnoty proměnné sqlca: sqlca. sqlcode Interpretace 0 SQL dotaz vykonán úspěšně >0 Žádná další data nebo hodnoty nenalezeny <0 Vyskytla se chyba během vykonávání SQL dotazu.
SQL Communications Area Příklad 1 Kontrola chyby EXEC SQL set transaction read write; EXEC SQL insert into customers values (custseq. nextval, : customer_rec. cname, : customer_rec. street, : customer_rec. zip, : customer_rec. phone); if(sqlca. sqlcode < 0) { printf("CUSTOMER (%s) DID NOT GET ADDEDn", customer_rec. cname. arr); EXEC SQL rollback work; return; } EXEC SQL commit;
SQL Communications Area Příklad 2 Kontrola existence dat EXEC SQL select into from where zip, city : zipcode_rec zipcodes zip = : customer_rec. zip; if(sqlca. sqlcode > 0) { zipcode_rec. zip = customer_rec. zip; printf("Zip Code does not exist; Enter City: "); scanf("%s", zipcode_rec. city. arr); zipcode_rec. city. len = strlen(zipcode_rec. city. arr); EXEC SQL set transaction read write; EXEC SQL insert into zipcodes (zip, city) values (: zipcode_rec); EXEC SQL commit; }
Připojení k Oracle databázi Klíčové příkazy: EXEC SQL connect [user] identified by [password] – připojení k Db EXEC SQL commit release – odpojení od Db EXEC SQL begin declare section; varchar userid[10]; varchar password[15]; EXEC SQL end declare section; strcopy(userid. arr, "Admin"); userid. len = strlen(userid. arr); strcopy(password. arr, "Password"); password. len = strlen(password. arr); EXEC SQL connect : userid identified by : password; if(sqlca. sqlcode == 0) { // Connected }
Kurzory Pokud příkaz select vrací více než jeden výsledek, jednoduchý příkaz select into nelze použít V takovém případě se používá koncept Kurzorů Mechanismus, umožňující C programu přistupovat k výsledným řádkům SQL dotazu po jednom. EXEC SQL declare <cur-name> cursor for <select-statement> [for {read only | update [of <column-list>]}]; for read only select Nedovoluje mazání a úpravu nalezených dat for update [of <column-list>] Používáno v případech pozičního mazání a úpravě dat
Kurzory – použití 1) Otevřít Kurzor 2) Několikanásobné volání příkazu fetch, pomocí kterého postupně získáme všechny řádky zadaného dotazu. 3) Uzavřít Kurzor EXEC SQL open <cur-name>; EXEC SQL fetch <cur-name> into <host-var>, … , <host-var>; EXEC SQL close <cur-name>;
Kurzory Příklad 1 Vypsání všech řádků tabulky{ print_customers() void EXEC SQL declare customers_cur cursor for select cno, cname, street, zip, phone from customers; EXEC SQL set transaction read only; EXEC SQL open customer_cur; EXEC SQL fetch customer_cur into : customer_rec indicator : customer_rec_ind; while(sqlca. sqlcode == 0) { customer_rec. cname. arr[customer_rec. cname. len] = '