stringy, kurzory a výjimky

Post on 22-Nov-2021

4 Views

Category:

Documents

0 Downloads

Preview:

Click to see full reader

TRANSCRIPT

[Otto Gold, ORA2]

Stringy, Kurzory a Výjimky

Stringy a VARCHARy

VARCHAR formálně

VARCHAR - jednoduchá strukturu (struct) jazyka CStruct{ unsigned short len; //délka obsahu unsigned char arr[20]; //hodnota obsahu}

Výhody použití VARCHAR

Lze explicitně použít délku řetězce v programových konstrukcích

printf("Username is %.*s\n", username.len, username.arr);

Nejčastěji: dodat si nulu na konec řetězce, aby byl pro C null-terminated

username.arr[username.len] = ’\0’;

Délka VARCHARu

Délku je nutno explicitně specifikovat při deklaraci (rozsah je 1..65533)

Příklad chyby: VARCHAR null_string[]; /* invalid */ Délkou se inicializuje VARCHAR.len Specifikace délky nemusí byt pouze explicitní číslo,

ale cokoli co lze vyčíslit na int v době práce preprocesoru (#defined macro, jiný rozumný výraz)

Použití VARCHARu (1)

...int part_number;VARCHAR part_desc[40];...main(){...EXEC SQL SELECT pdesc INTO :part_descFROM partsWHERE pnum = :part_number;...Bezprostředně po provedení obsahuje part_desc.len

délku získaného řetězce a part_desc.arr samotný řetězec (neukončený nulou)

Použití VARCHARu (2)

Takhle to pak vypadá v samotném C

printf("\n\nEnter part description: ");gets(part_desc.arr);

/* You must set the length of the stringbefore using the VARCHAR in an INSERT or UPDATE */

part_desc.len = strlen(part_desc.arr);

VARCHAR a NULL (Out)

Oracle nastavuje délku VARCHARU automaticky Jenže, jestliže je výsledkem SELECTu nebo

FETCHe NULL, tak server délku nenastavuje (nedojde ke změně)

Jestliže je výsledkem NULL a nezjišťujeme to indikátorovou proměnnou, skončíme s chybou

(Neošetřovat a vyhnout se chybě lze takto: nastavíme UNSAFE_NULL=YES)

VARCHAR a NULL (In)

NULL uložíme do DB tak, že délku VARCHARu nastavíme na 0

Jestliže sloupec nemá povolenu hodnotu NULL, skončím s chybou

Předávání VARCHARu do fce

V Pro*C/C++ předáváme referencí

VARCHAR emp_name[20];VARCHAR *name;emp_name.len = 20;SELECT ename INTO :emp_name FROM emp WHERE empno =

7499;print_employee_name(&emp_name);print_employee_name(name)

printf("name is %.*s\n", name->len, name->arr);

Kurzorové proměnné

Co to je a k čemu to je

Je to handle na kurzor definovaný a otevřený na ORA serveru, v PL/SQL

Udržovatelnost – jde pouze o „zástupce“ pro kurzor definovaný jen jednou v PL/SQL, takže kdekoli se používá beze změn, změna která plní kurzor daty se dělá jen na jednom místě

Bezpečnost – lze omezit uživatele, např. Smí číst kurzor ale nesmí číst tabulky, ze kterých se plní

Deklarace kurzorové proměnné

Pseudotyp SQL_CURSOR, běžná proměnná POZOR: dodržovat case (CASE, ne CaSe)

EXEC SQL BEGIN DECLARE SECTION;sql_cursor emp_cursor; /* a cursor variable */SQL_CURSOR dept_cursor; /* a cursor variable */sql_cursor *ecp; /* a pointer to a var */EXEC SQL END DECLARE SECTION;

/* assign a value to the pointer */ecp = &emp_cursor;

Alokace kurzorové proměnné

Kurzor na serveru je třeba otevřít (nelze spoléhat na embedded SQL OPEN)

Otevřít lze 2 způsoby: Voláním PL/SQL procedury Použitím anonymního bloku přímo v

preprocesoru

Ukázka (1) – PL/SQL balík

CREATE PACKAGE demo_cur_pkg ASTYPE EmpName IS RECORD (name VARCHAR2(10));TYPE cur_type IS REF CURSOR RETURN EmpName;PROCEDURE open_emp_cur (curs IN OUT cur_type,

dept_num IN NUMBER);END;

CREATE PACKAGE BODY demo_cur_pkg ASCREATE PROCEDURE open_emp_cur (curs IN OUT cur_type,

dept_num IN NUMBER) ISBEGIN

OPEN curs FORSELECT ename FROM empWHERE deptno = dept_numORDER BY ename ASC;

END; END;

Ukázka (2) - použití

sql_cursor emp_cursor;char emp_name[11];/* allocate the cursor variable */EXEC SQL ALLOCATE :emp_cursor; /* Open the cursor on the server side. */EXEC SQL EXECUTEdemo_cur_pkg.open_emp_cur(:emp_cursor, :dept_num);

EXEC SQL WHENEVER NOT FOUND DO break;for (;;){

EXEC SQL FETCH :emp_cursor INTO :emp_name;printf("%s\n", emp_name);

}

Použití – anonymní blok

sql_cursor emp_cursor;int dept_num = 10;EXEC SQL EXECUTEBEGINOPEN :emp_cursor FOR SELECT ename FROM emp WHERE deptno = :dept_num;

END;END-EXEC;

Použití – embedded SQL

sql_cursor emp_cursor;EXEC ORACLE OPTION(select_error=no);EXEC SQLSELECT CURSOR(SELECT ename FROM emp WHERE deptno =

:dept_num)INTO :emp_cursor FROM DUAL;EXEC ORACLE OPTION(select_error=yes);

Poznámka: (select_error) Před dotazy využívajícími kurzory je třeba vypnout hlášení chyb. Předejdeme tak zrušení rodičovského kurzoru a tedy chybám v programu.

Uzavření a uvolnění

Příkaz CLOSE pro zavření proměnné /* hostitelská proměnná --> s dvojtečkou*/ EXEC SQL CLOSE :emp_cursor; Odalokace pomocí EXEC SQL FREE :emp_cursor; Důležité: Při odpojení a znovu připojení k

DB je třeba realokovat (ALLOCATE) všechny kurzory

Vybraná omezení pro kurzory

Lze použít jen příkazy ALLOCATE, FETCH, FREE a CLOSE

DECLARE CURSOR s kurzorovými proměnnými nijak nepracuje (PLSQL)

Nelze FETCHovat z proměnné co je CLOSED Analogicky z ne-ALLOCATEd proměnné Ve vybraných módech je chyba zavřít zavřený kurzor Kurzorové proměnné nelze ukládat do DB sloupců Kurzorovou proměnnou nelze psát do PL/SQL kódu,

pouze typ pro odpovídající kurzor ...a další

Zpracování chyb

Error handling - přehled

Průběžné testování SQLSTATE nebo SQLCODE (integer)

SQL Communications Area (cqlca) – update po jakékoli proveditelné akci na serveru Varianta explicitní: ruční kontrola sqlca Implicitní: WHENEVER clause

Extra informace: struktura ORACA (contains cursor statistics, information about the current SQL statement, option settings, and system statistics)

Proměnná SQLSTATE

Použití SQLCA je volitelné, ale SQLSTATE je povinné

Dle normy SQL92 se definuje SQLCODE, který je podobný

Obsahuje informace o úspěchu nebo o výjimce SQL92 definuje všechny obvyklé SQL výjimky SQLCODE informuje pouze o chybách,

SQLSTATE o chybách i varováních, STATE je tedy preferovaná varianta kontroly

SQLSTATE detaily

/* SQLSTATE must be declared with a dimension of exactly 6 characters, Upper case is required */

char SQLSTATE[6]; Co obsahuje:

2 znaky – class code (00 = success) 3 znaky – subclass code

Příklad: 22012 22 (data exception) 012 (division by zero)

SQLCODE

Je vyžadován, jestliže nepoužíváme SQLSTATE Lze deklarovat více než jeden SQLCODE, každý

se specifickým rozsahem platnosti Jestliže nedeklarujeme SQLCA, vytvoří se

implicitní, nám nepřístupné Jestliže deklarujeme obojí, plní se stejně

/* declare status variable--must be upper case */long SQLCODE;

Použití SQLCA

Status codes (0, 1+ Exception, -1- Not executed, internal error)

Warning flags (sqlwarn[0..7]) Rows-processed count (sqlerrd[2]) Parse error offset (kde začíná parse chyba) Error message text (SQLERRMC, 70, sqlglm() )

Struct SQLCA

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];

};

Direktiva WHENEVER

EXEC SQL WHENEVER <condition> <action>; Vyžaduje deklaraci SQLCA !! Kontroluje SQLCA na tyto podmínky

SQLWARNING: Sqlwarn[0] je nastaveno nebo SQLCODE má kladnou hodnotu, různou od +1403

SQLERROR: SQLCODE má zápornou hodnotu NOT FOUND: SQLCODE = +1403 (no rows)

WHENEVER akce

CONTINUE – nic, default DO – předává kontrolu error handleru DO BREAK – standardní break v LOOPu DO CONTINUE - analogicky continue GOTO label – skok na label, max 31zn STOP – konec a odrolování kde nebylo

řádně odkomitováno

WHENEVER příklad (1)

EXEC SQL WHENEVER NOT FOUND GOTO close_cursor;EXEC SQL WHENEVER SQLWARNING CONTINUE;EXEC SQL WHENEVER SQLERROR GOTO error_handler;

EXEC SQL WHENEVER SQLERROR DO handle_insert_error("INSERT error");

EXEC SQL INSERT INTO emp (empno, ename, deptno) VALUES (:emp_number, :emp_name, :dept_number);

EXEC SQL WHENEVER SQLERROR DO handle_delete_error("DELETE error");

EXEC SQL DELETE FROM dept WHERE deptno = :dept_number;

WHENEVER příklad (2)

handle_insert_error(char *stmt){ switch(sqlca.sqlcode){

case -1:/* duplicate key value */

break;case -1401:

/* value too large */break;default:

/* do something here too */break;

}}

Rady pro užití WHENEVER

Vkládat WHENEVER klauzule před první „proveditelné“ SQL operace

Ošetřujte situaci, kdy data „nejsou“ a používáte for(;;)

Ošetřujte nekonečný cyklus nebo nepoužívejte GOTO

Cíl skoku musí být korektně umístěn, analogicky error handler (--> př.)

Nekorektní umístění

func1(){EXEC SQL WHENEVER SQLERROR GOTO labelA;EXEC SQL DELETE FROM emp WHERE deptno = :dept_number;...labelA:...}func2(){EXEC SQL INSERT INTO emp (job) VALUES (:job_title);...}

top related