34
[Otto Gold, ORA2] Stringy, Kurzory a Výjimky

Stringy, Kurzory a Výjimky

  • Upload
    others

  • View
    4

  • Download
    0

Embed Size (px)

Citation preview

Page 1: Stringy, Kurzory a Výjimky

[Otto Gold, ORA2]

Stringy, Kurzory a Výjimky

Page 2: Stringy, Kurzory a Výjimky

Stringy a VARCHARy

Page 3: Stringy, Kurzory a Výjimky

VARCHAR formálně

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

Page 4: Stringy, Kurzory a Výjimky

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

Page 5: Stringy, Kurzory a Výjimky

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)

Page 6: Stringy, Kurzory a Výjimky

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)

Page 7: Stringy, Kurzory a Výjimky

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

Page 8: Stringy, Kurzory a Výjimky

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)

Page 9: Stringy, Kurzory a Výjimky

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

Page 10: Stringy, Kurzory a Výjimky

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

Page 11: Stringy, Kurzory a Výjimky

Kurzorové proměnné

Page 12: Stringy, Kurzory a Výjimky

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í

Page 13: Stringy, Kurzory a Výjimky

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;

Page 14: Stringy, Kurzory a Výjimky

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

Page 15: Stringy, Kurzory a Výjimky

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;

Page 16: Stringy, Kurzory a Výjimky

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

}

Page 17: Stringy, Kurzory a Výjimky

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;

Page 18: Stringy, Kurzory a Výjimky

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.

Page 19: Stringy, Kurzory a Výjimky

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

Page 20: Stringy, Kurzory a Výjimky

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ší

Page 21: Stringy, Kurzory a Výjimky

Zpracování chyb

Page 22: Stringy, Kurzory a Výjimky

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)

Page 23: Stringy, Kurzory a Výjimky

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

Page 24: Stringy, Kurzory a Výjimky

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)

Page 25: Stringy, Kurzory a Výjimky
Page 26: Stringy, Kurzory a Výjimky

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;

Page 27: Stringy, Kurzory a Výjimky

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() )

Page 28: Stringy, Kurzory a Výjimky

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

};

Page 29: Stringy, Kurzory a Výjimky

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)

Page 30: Stringy, Kurzory a Výjimky

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

Page 31: Stringy, Kurzory a Výjimky

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;

Page 32: Stringy, Kurzory a Výjimky

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;

}}

Page 33: Stringy, Kurzory a Výjimky

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ř.)

Page 34: Stringy, Kurzory a Výjimky

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);...}