51
Databáze I Přednáška 9

Databáze I - cvut.cz...Ošet ření chyb • pomocí indikátorových proměnných – prom ěnné typu short, deklarovány v deklara ční sekci stejn ě jako hostitelské proměnné

  • Upload
    others

  • View
    2

  • Download
    0

Embed Size (px)

Citation preview

Databáze I

Přednáška 9

Programování s SQL

• interaktivní verze SQL– zadávání dotazů v operátorské konzoli

• konzole MySQL, • Oracle SQL Developer

• hostitelská verze SQL (Embedded SQL)– SQL začleněno do nějakého

programovacího jazyka• většinou staticky, tj. dotazy musí být známy při

překladu • programovací jazyk, který umožňuje používat

příkazy SQL, se nazývá hostitelský

Programování s SQL

• dynamické SQL– generování dotazu v programovacím

jazyce za běhu programu (sestaven např. dle hodnoty v políčku formuláře zadaném uživatelem)

• nadstavba SQL v SŘBD– obohacení SQL o výpočetní/procedurální

rysy programovacích jazyků v rámci SŘBD

Poznámka: – vestavěné SQL do jazyků i nadstavby mají

dnes většinou dynamický charakter

Příklady

• PL/SQL– nadstavba SQL v SŘBD Oracle odvozená

od jazyku ADA

• SPL – nadstavba v Informix

• SQL/PSM– SQL/Persistent Stored Modules– standard ISO – rozšíření SQL o procedury

a funkce používané jako „uložené procedury“ (stored procedures)

Příklady

• hostitelské SQL v jazycích– podpora v Oracle

• C, Cobol, ADA, Fortran, Pascal

– MS Access• Visual Basic

– začlenění do PHP– začlenění do Javy

• balík java.sql

PL/SQL

• program v PL/SQL se skládá z bloků

DECLARE

/* Deklarace prom ěnných, typ ů a lokálních podprogram ů. */

BEGIN

/* Výkonná sekce: procedury a SQL kód. */ /* Toto je jediná sekce, která je v bloku povinná. */

EXCEPTION

/* Oblast ošet ření výjimek */

END;

Rysy PL/SQL

• deklarace proměnných a konstant

<název_prom ěnné> <typ>;

kolik_bere NUMBER(6,2);

<název_konstanty> CONSTANT typ := hodnota;

limit CONSTANT REAL := 5000.00;

– typy mohou být „databázové“ (NUMERIC, VARCHAR) nebo „PL“ (PLS_INTEGER)

Rysy PL/SQL

• přiřazení hodnot– přímé operátorem přiřazení :=

cislo := 5;

– výsledek dotazuSELECT plat INTO kolik_bere FROM zamestnanci

WHERE cislo_zamestnance = zam_id;

– výstupní nebo vstupně-výstupní parametr procedury

Rysy PL/SQLDECLARE

prum_plat REAL;

PROCEDURE zvedni_plat (procento INT, plat IN OUT REAL) I S

BEGIN

plat := plat*(1+procento/100);

END;

BEGIN

SELECT AVG(plat ) INTO prum_plat

FROM zam;

zvedni_plat(5,prum_plat);

Rysy PL/SQL

• kurzory– odkazy na tzv. „pracovní oblasti“ (data), což

může být jeden nebo více řádek tabulky vybrané dotazem

– příklad explicitně deklarovaného kurzoruDECLARE CURSOR k1 IS

SELECT id, prijmeni FROM zamestnanci WHERE cislo_oddeleni = 20;

– nad kurzory jsou definovány další operace (otevření/zavření/načtení další řádky)

Řídicí struktury v PL/SQL

• podmínkyIF podmínka THEN

příkazyEND IF;

IF podmínka THEN IF podmínka THENpříkazy příkazy

ELSE ELSIF podmínka THENpříkazy příkazy

END IF; ELSIF podmínka THENpříkazy

ELSEpříkazy

END IF;

Řídicí struktury v PL/SQL

• větvení

[<<label_name>>]CASE selektor

WHEN klauzule1 THEN p říkazy;WHEN klauzule2 THEN p říkazy;...WHEN klauzulen THEN p říkazy;[ELSE sled statement ůn+1]

END CASE [label_name];

Řídicí struktury v PL/SQL

• cyklyLOOP

...

IF podmínka THEN

...

EXIT; -- vysko čí z cyklu

END IF;

END LOOP;

LOOP

...

EXIT WHEN podmínka;

END LOOP;

WHILE podmínka LOOP

příkazy

END LOOP;

Další vlastnosti

• definice modulů (modularita)– definice podprogramů

• procedury• funkce• anonymní bloky

– definice balíčků – CREATE PACKAGE• sdružují proměnné, kurzory a podprogramy

• definice objektový typů

Další vlastnosti – obsluha výjimekDECLARE...vyjimka_chybi_p EXCEPTION; -- deklarace výjimkyBEGIN

...IF provize IS NULL THEN

RAISE vyjimka_chybi_p; -- vyvolání výjimkyEND IF;bonus := (plat * 0.10) + (provize * 0.15);

EXCEPTIONWHEN vyjimka_chybi_p THEN ... -- zpracování výjimkyWHEN OTHERS THEN ... -- zpracování ost. výjim ekEND;

Triggery

• kód v PL/SQL může být uložen např. jako trigger

• trigger – spoušť– kód, který se automaticky spouští v SŘBD na

základě nějaké události• manipulace s daty – operace DELETE, INSERT,

UPDATE.• definice dat – operace CREATE, ALTER, DROP• jiná operace nad databází – např. SERVERERROR,

LOGON, LOGOFF, STARTUP, SHUTDOWN, ...

TriggeryCREATE [OR REPLACE ] TRIGGER trigger_name{BEFORE | AFTER | INSTEAD OF } {INSERT [OR] | UPDATE [OR] | DELETE} [OF col_name] ON table_name[REFERENCING OLD AS o NEW AS n] [FOR EACH ROW] WHEN (condition) DECLARE

Declaration-statementsBEGIN

Executable-statementsEXCEPTION

Exception-handling-statementsEND;

Triggery• trigger, který při změně platu vypíše původní a

nový plat a rozdíl

CREATE OR REPLACE TRIGGER display_salary_changes

BEFORE DELETE OR INSERT OR UPDATE ON customers

FOR EACH ROW

WHEN (NEW.ID > 0)

DECLARE

sal_diff number;

BEGIN

sal_diff := :NEW.salary - :OLD.salary;

dbms_output.put_line('Old salary: ' ||:OLD.salary);

dbms_output.put_line('New salary: ' ||:NEW.salary);

dbms_output.put_line('Salary difference: ' ||sal_diff);

END;

Ukázka• program, který provede odečtení částky pouze, je-li na účtu

dostatečná částka

DECLAREacct_balance NUMBER(11,2);acct CONSTANT NUMBER(4) := 3;debit_amt CONSTANT NUMBER(5,2) := 500.00;BEGINSELECT bal INTO acct_balance FROM accountsWHERE account_id = acct FOR UPDATE OF bal; -- zamkne záznamIF acct_balance >= debit_amt THEN

UPDATE accounts SET bal = bal - debit_amtWHERE account_id = acct;

ELSEINSERT INTO temp VALUES

(acct, acct_balance, 'Insufficient funds');END IF;COMMIT;END;

• SQL PSM – Persistent Store Modules– rozšiřuje SQL na výpočetní úplnost– umožňuje definovat tzv. uložené procedury a

funkce– první zmínka - 1994– rozlišuje externí uložené procedury (jiný

jazyk, běžící mimo server) a SQL procedury– příklad byl již v přednášce o SQL99

SQL PSM

• tabulka ucty(cislo,zustatek)

• procedura vrátí zůstatek na účtu do parametru zu

CREATE PROCEDURE vrat_zustatek

(IN c_uctu INTEGER, OUT zust DOUBLE PRECISION)

BEGIN

SELECT zustatek INTO zust

FROM ucty WHERE cislo = c_uctu;

IF zustatek < 2500 THEN SIGNAL nizky_zustatek

END IF

END

Definice procedury

CREATE FUNCTION vrat_zustatek

(IN c_uctu INTEGER) RETURNS DOUBLE PRECISION

BEGIN

DECLARE zust DOUBLE PRECISION;

SELECT zustatek INTO zust

FROM ucty WHERE cislo = c_uctu;

IF zustatek < 2500 THEN SIGNAL nizky_zustatek

END IF;

RETURN zust

END

Definice funkce

Poznámky:• procedury a funkce se volají příkazem

CALL• příkaz SIGNAL vyvolá speciální handler

Hostitelská verze SQL v jazyce CPrincip• do zdrojového kódu v C/C++ se zapíší

speciálně uvozené dotazy SQL– zpravidla s příponou .pc

• speciální prekompilátor Pro*C/C++ (proc v Linuxu) nahradí tyto dotazy voláním funkcí ze standardní knihovny run-time (SQLLIB) a převede soubor .pc do "čistého" C/C++

• dále se kód překládá jako „obyčejný“ zdrojový kód C/C++.

• na konci se k němu linkuje knihovna SQLLIB

Psaní dotazů SQL do kódu v C

1. všechny dotazy SQL jsou uvozeny direktivou

EXEC SQL

a končí středníkem „;“

2. proměnných používané v SQL musí být uvozeny dvojtečkou „:“

Psaní dotazů SQL do kódu v CSELECT

EXEC SQL BEGIN DECLARE SECTION;

int plat_sefa;

EXEC SQL END DECLARE SECTION;

/* ... */

EXEC SQL SELECT plat INTO :plat_sefa

FROMZamestnanci WHEREid_zam = 123;

/* ... */

printf("Sefuv plat: %d \n", plat_sefa);

Psaní dotazů SQL do kódu v CINSERT

typedef struct { int id;

cha r name[20];

} rec;

EXEC SQL BEGIN DECLARE SECTION;

Myrec rec;

EXEC SQL END DECLARE SECTION;

Myrec.id=5;

strcpy(Myrec.name,"Novak");

EXEC SQL INSERT INTO Lide VALUES (:Myrec);

Deklarativní část

• deklarace se uvádějí meziEXEC SQL BEGIN DECLARE SECTION;

EXEC SQL END DECLARE SECTION;

– definují se zde hostitelské proměnné (host variables), které se budou používat pro komunikaci mezi programem a databází (načítání dat i zápis, indikátory)

Typy hostitelských proměnných

• char , int , short , long, float , double

• VARCHAR[n]

– „pseudotyp“ pro řetězce, rozpoznávaný přímo prekompilátorem Pro*C/C++

– struktura v C se 2 položkami:• arr – pole charů• len – délka pole

Implicitní konverze

SQL Pro*C/C++

VARCHAR VARCHAR[n], char

DATE VARCHAR[n], char

INTEGER int

NUMBER(P,S) char, short, int, long, float, double, char[n], VARCHAR[n]

CHAR(X) char[n],VARCHAR[n],int,short,long,float,double

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í */

Ukončení transakcí

• ukončení transakce bez odpojeníEXEC SQL COMMIT;

• storno změnEXEC SQL ROLLBACK;

• ukončení transakce s odpojenímEXEC SQL COMMIT WORK RELEASE;

• storno změn s odpojenímEXEC SQL ROLLBACK WORK RELEASE;

Ošetření chyb

• pomocí indikátorových prom ěnných– proměnné typu short, deklarovány v deklarační

sekci stejně jako hostitelské proměnné– jsou 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 dotazů SQL jsou také uvozeny „:“– následují vždy bezprostředně za příslušnou

hostitelskou proměnnou

Ošetření chyb

EXEC SQL SELECT plat INTO :plat_sefa : plat_sefa_id

FROM Zamestnanci

WHERE id_zam = 123;

/* ... */

if (plat_sefa_id == 0)

printf("Plat: %d \n", plat_sefa);

Návratové kódy v indikátorových proměnných pro SELECT

Indikátor Hostitelská prom ěnná

-1 nedefinovaná hodnota (NULL v databázi)

0 korektní naplnění

-2 vkládaná hodnota je větší než proměnnáa není možné určit skutečnou velikost

>0 vkládaná hodnota je větší než proměnná,skutečná velikost je hodnota indikátoru

Návratové kódy v indikátorových proměnných pro INSERT

Indikátor Databáze

-1 uložena hodnota NULL

>=0 korektní naplnění

Ošetření chyb

• rozšíření:EXEC SQL WHENEVER podmínka akce

– pokud je splněna podmínka, provede se akce

• podmínky:– NOT FOUND

• kritériu SELECT/FETCH neodpovídá žádná položka

– SQLERROR• nějaký příkaz SQL EXEC skončil chybou

Ošetření chyb

– SQLWARNING• nějaký příkaz SQL EXEC skončil s varováním

• akce– CONTINUE

• pokud lze, pokusí se program pokračovat dalším příkazem

– DO <cmd>• vykoná se příkaz <cmd>, typicky volání funkce / exit

– GOTO <navesti>• skok na dané návěští

Ošetření chyb

– STOP• volání exit(), ukončení programu, nepotvrzené akce

jsou stornovány (rollback)

EXEC SQL WHENEVER NOT FOUND tisk_chyby();

EXEC SQL SELECT studentname INTO :st_name

FROM student

WHERE studentid = :id;

printf("Jmeno: %s.\n", st_name);

SQL v PHP

• původně Personal Home Page• od 1997 PHP Hypertext Preprocessor• skriptovací jazyk na straně serveru

založený syntakticky na jazycích C, Java, Perl (interpretovaný), používá se pro dynamické generování WWW stránek

• je volně dostupný a nezávislý na platformě

• má rozsáhlou knihovnu funkcí– práce s řetězci, umí přistupovat k databázím

pomocí SQL

Historie

• 1994 - 1995– Rasmus Lerdorf – sada skriptů v Perlu ke

zpracování záznamů o přístupech na server

• 1997– rozšíření funkčnosti, implementace v

jazyce C - PHP/FI nebo PHP2– PHP3 - Andi Gutmans a Zeev Suraski

• 2000– PHP4 – interpret zvaný Zend Engine– autoři Andi Gutmans a Zeev Suraski– objekty

• 2004– PHP5– jádro Zend Engine 2.0– výjimky, jmenné prostory– listopad 2011 – uvolněna verze PHP5.4 RC1

• verze 6 nebyla oficiálně vydána• 2015

– prosinec: verze PHP7.0– 64 bitová

Zápis PHP skript ů

• skripty se zapisují do HTML stránky mezi značky <? ?>

Příklad:<?php if (date("A")=="AM")

{ echo "Dobré ráno!"; }

else

{ echo "Dobré odpoledne!"; }

/* date("A") vrátí AM nebo PM */

?>

SQL v PHP• PHP podporuje rozhraní API pro přístup

k velkému počtu databází pomocí SQL (Oracle, Sybase, MySQL)

Základní kostra práce s databázemi:• vytvoření připojení k databázi• zaslání SQL příkazu k provedení• zpracování výsledku• odpojení od databáze

Příklad:

$spojeni = mysqli_connect("localhost",

"jméno", "heslo","databaze");

if (mysqli_connect_errno($spojeni))

{

echo "Nepoda řilo se p řipojit k MySQL. <BR>\n";

}

else

{

@$vysledek = mysqli_query($spojeni, "SELECT * FROM

Zamestnanci ORDER BY Jmeno");

if (!$vysledek){echo "Došlo k chyb ě p ři zpracování dotazu v

databázi.<BR>\n";}else{

echo "V tabulce Zamestnanci je ".mysqli_num_rows($vysledek)." záznam ů.<BR>\n";

while ($zaznam = mysqli_fetch_array($vysledek)){

echo $zaznam['OsobniCislo']." ".$zaznam['Jmeno']."<BR>";}mysqli_close($spojeni);

}}

Příklad – databáze uživatelů a přihlašovací formulář

– create table users (uname VARCHAR(20), pass VARCHAR(20);

Přihlašovací formulář<form action="login.php">

<fieldset style="width:300px"><legend> P řihlášení </legend><table align="center">

<tr><TD>Uživatelské jméno:</td><TD><INPUT TYPE=TEXT NAME=jmeno></td>

</tr> <TR><TD>Heslo:</td>

<TD><INPUT TYPE=password NAME=heslo></td></tr> <tr><td align="center" colspan="2"><button type="submit">Odeslat</button></td>

</TABLE></FIELDSET>

</form>

login.php<?php

$jmeno=$_GET["jmeno"];$heslo=$_GET["heslo"];

if($jmeno == ''){

echo '<h1 align="center">Nezadal jste žádné jméno</ h1>';exit();

}

$spojeni = mysqli_connect('localhost', '', '', 'uka zka');

if (mysqli_connect_errno($spojeni)){echo "Nepoda řilo se p řipojit k MySQL. <BR>\n";}else

login.php{

$vysledek = mysqli_query($spojeni, 'SELECT * FROM u sers WHERE uname = \''. $jmeno .'\';');if (!$vysledek){

echo "Došlo k chyb ě p ři zpracování dotazu v databázi.<BR>";mysqli_close($spojeni);exit();

}else{

if(!$zaznam = mysqli_fetch_array($vysledek)){

echo '<h1 align="center">Vaše uživatelské jméno nen í v databázi</h1>';

mysqli_close($spojeni);exit();

}else{

if($zaznam['pass']!=$heslo)

login.php{ echo '<h1 align="center">Nesprávné heslo</h1>';

mysqli_close($spojeni);exit();

} else{

$_SESSION['logged_in']=TRUE;$vysledek = mysqli_query($spojeni, 'SELECT * FROM infousers WHERE uname

= \''. $jmeno .'\';');if ($vysledek && $zaznam = mysqli_fetch_array($vysledek) ){

echo '<h1 align="center">Vaše kontaktní údaje</h1>';echo '<hr/>';echo $zaznam['jmeno'].' '. $zaznam['prijmeni'].'<br>';echo $zaznam['ulice'].'<br>';echo $zaznam['psc']. " " . $zaznam['mesto'].'<br>';echo 'e-mail: '. $zaznam['email'].'<br>';

}}

}} mysqli_close($spojeni);