Rigtig SQL Programmering 1
SQL i Rigtige Programmer Indtil nu har vi brugt SQL direkte i kommandolinje promt/gui program, hvor vi kan lave forespørgsler til databasen I virkeligheden: Programmer kontakter databasen og ikke os. 2
Valgmuligheder 1. Kode gemt I databasen selv I et specielt programmeringssprog til det (PSM, PL/pgsql) 2. SQL statements embedded i et host language (fx. C) 3. Værktøjer til at tillade conventionelle programmeringssprog adgang til en database (fx. CLI, JDBC, psycopg2) 3
Stored Procedures PSM, eller persistent stored modules, tillader os at gemme procedures som database schema elements PSM = Et mix af conventionelle statements (if, while, etc.) og SQL Tillader os at gøre ting vi ikke kan i SQL alene 4
Procedures i PostgreSQL CREATE PROCEDURE <name> ([<arguments>]) AS $$ <program>$$ LANGUAGE <lang>; PostgreSQL tilllader functioner: CREATE FUNCTION <name> ([<arguments>]) RETURNS VOID AS $$ <program>$$ LANGUAGE <lang>; 5
Parametre for Procedures I modsætning til typiske navn-type par i sprog som Java, kan procedures bruge mode-navntype tripler, hvor mode kan være: IN = Input værdi, der ikke ændres OUT = funktionen ændrer værdien, men bruger den ikke (implicit retur-værdi) INOUT = Bruger og sætter værdien. 6
Exempel: Stored Procedure Lad os skrive en procedure, der tager to argumenter b and p, og tilføjer en tuple til Sells(bar, beer, price) der har bar = C.Ch., beer = b, og price = p Bruges af Cafe Chino til at putte ting på deres menu lettere 7
The Procedure CREATE FUNCTION ChinoMenu ( IN b IN p CHAR(20), REAL ) RETURNS VOID AS $$ INSERT INTO Sells VALUES( C.Ch., b, p); $$ LANGUAGE plpgsql; Begge parametre er read-only, dvs de ikke ændres Kodedelen: En enkelt indsættelse 8
Udfør procedure Brug SQL/PSM statement CALL, med navnet på den ønskede procedure og argumenter Exempel: CALL ChinoMenu( Eventyr, 50); Brug funktioner SQL udtryk, når typen af returværdi er anvendelig Bemærk: ingen CALL i PostgreSQL: SELECT ChinoMenu( Eventyr, 50); 9
Typer af PL/pgsql statements Return statement: RETURN <expression> returnerer værdien fra en funktion Ligesom i Java, RETURN afslutter funktionen Declare block: DECLARE <nave> <type> bruges til at erklære lokale variable Grupper af Statements: BEGIN... END Adskilt af semicoloner 10
Kinds of PL/pgsql statements Assignment statements: <variable> := <expression>; Eksempel: b := Od.Cl. ; Statement labels: Giv en statement et label ved at prefixe et navn og et colon 11
IF Statements Simpleste form: IF <condition> THEN <statements(s)> END IF; Add ELSE <statement(s)> hvis det er ønsket, som IF... THEN... ELSE... END IF; Yderligere med ELSEIF <statements(s)>: IF THEN ELSEIF THEN ELSEIF THEN ELSE END IF; 12
Eksenpel: IF Lad os vurdere barer ud fra hvor mange kunder de har, baseret på Frequents(drinker,bar) <100 kunder: upopulær 100-199 customers: gennemsnitlig >= 200 customers: populær Functionen Rate(b) vurderer bar b 13
Example: IF CREATE FUNCTION Rate (IN b CHAR(20)) BEGIN END; RETURNS CHAR(10) AS $$ DECLARE cust INTEGER; Antal kunder i bar b cust := (SELECT COUNT(*) FROM Frequents WHERE bar = b); IF cust < 100 THEN RETURN unpopular ; ELSEIF cust < 200 THEN RETURN average ; ELSE RETURN popular ; END IF; Nested IF statement 14
Loops Basic form: <<<label>>> LOOP <statements> END LOOP; Exit fra et loop med: EXIT <label> WHEN <condition> 15
Eksempel: Exit fra Loop <<loop1>> LOOP... EXIT loop1 WHEN...;... END LOOP; Hvis statement her returnerer sand... ender vi her 16
Andre Loops WHILE <condition> LOOP <statements> END LOOP; Ekvivalent til: LOOP EXIT WHEN NOT <condition>; <statements> END LOOP; 17
Andre Loop FOR <name> IN <start> TO <end> LOOP <statements> END LOOP; Ekvivalent til: <name> := <start>; LOOP EXIT WHEN <name> > <end>; <statements> <name> := <name>+1; END LOOP; 18
Forespørgsler Generelle SELECT-FROM-WHERE forespørgsler er ikke tilladt i PL/pgsql Men der er tre måder at få svaret på en forespørgsel: 1.Forespørgsel der producerer en enkelt værdi kan bruges som expression I en assignment 2.SELECT... INTO 3.Cursors 19
Eksempel: Assignment Brug lokal variabel p og Sells(bar, beer, price), til at få prisen Cafe Chino sælger Odense Classic til: p := (SELECT price FROM Sells WHERE bar = C.Ch AND beer = Od.Cl. ); 20
SELECT... INTO En anden måde er ved at bruge INTO <variable> efter SELECT delen Eksempel: SELECT price INTO p FROM Sells WHERE bar = C.Ch. AND beer = Od.Cl. ; 21
Cursor En cursor er essentielt en tuple-variabel der indeholder allle tuplerne I resultatet fra en forespørgsel Erklær en cursor c : DECLARE c CURSOR FOR <query>; 22
Open/Close Cursor For at bruge cursor c, skal vi åbne den med: OPEN c; Det afvikler forespørgslen, og placerer resultatet i c, pegende på det første element Når vi er færdige med c, skal vi bruge: CLOSE c; 23
Hente Tupler Fra en Cursor For at hente den næste tupel fra cursor c, brug: FETCH FROM c INTO x 1, x 2,,x n ; Hvor x erne er en liste af variable, en for hver kolonne i resultatet for c c flyttes automatisk til den næste tupel 24
Stoppe Cursor Loops (1) Den typiske måde at bruge en cursor er at oprette et loop, med en FETCH statement, og gøre noget med hver tuple Det specielle er at der skal stoppes når der ikke er flere tupler 25
Stoppe Cursor Loops (2) Mange operationer returnerer hvis en række er fundet, ændret, indsat eller slettet (SELECT INTO, UPDATE, INSERT, DELETE, FETCH) I plpgsql, kan vi finde resultatet I en variabel: FOUND 26
Stoppe Cursor Loops (3) Strukturen af et cursor loop er: <<cursorloop>> LOOP FETCH c INTO ; IF NOT FOUND THEN EXIT cursorloop; END IF; END LOOP; 27
Eksempel: Cursor Lad os skrive en procedure der undersøger Sells(bar, beer, price), hæver prisen med 10, for alle øl på Cafe Chino der sælges under 30 Kunne skrives som en simpel UPDATE, men jeg mangler et bedre (simpelt) eksempel 28
Needed Declaration CREATE FUNCTION RaisePrices() RETURNS VOID AS $$ DECLARE thebeer CHAR(20); theprice REAL; c CURSOR FOR (SELECT beer, price FROM Sells WHERE bar = C.Ch. ); Bruges til at holde beer-price par når vi itererer cursor c Returnerer Cafe Chino s pris liste 29
Procedurens kode BEGIN OPEN c; <<menuloop>> LOOP FETCH c INTO thebeer, theprice; EXIT menuloop WHEN NOT FOUND; IF theprice < 30 THEN UPDATE Sells SET price = theprice + 10 WHERE bar = C.Ch. AND beer = thebeer; END IF; END LOOP; CLOSE c; END;$$ LANGUAGE plpgsql; Check hvis den seneste FETCH ikke fandt en tupel Hvis Cafe Chinos pris er mindre end 30 for øllen, hæv prisen med 10 30
Tuple-Valued Variables PL/pgsql tillader en variabel x at have tuple type x R%ROWTYPE giver x typen of R s tupler R kan være enten en relation eller en cursor x.a giver værdien af componenten for attribut a i tuplen x 31
Eksempel: Tuple Type Gentagelse af RaisePrices() med variablen bp af typen beer-price par CREATE FUNCTION RaisePrices() RETURNS VOID AS $$ DECLARE CURSOR c IS SELECT beer, price FROM Sells WHERE bar = C.Ch. ; bp c%rowtype; 32
RaisePrices() brug af bp BEGIN OPEN c; LOOP FETCH c INTO bp; EXIT WHEN NOT FOUND; IF bp.price < 30 THEN UPDATE Sells SET price = bp.price + 10 WHERE bar = C.Ch. AND beer = bp.beer; END IF; END LOOP; CLOSE c; END; Elementerne i bp tilgåes med. Og attribut-navn 33
Database-Connection Libraries 34
Host/SQL Interfaces Via Libraries Den tredje tilgang til at forbinde databaser til conventionelle programmeringssprog er at bruge biblioteker 1. C + CLI 2. Java + JDBC 3. Python + psycopg2 4.... 35
3-lags arkitektur En typisk opsætning i arkitektur med databaser har tre lag: 1. Web servere Kommunikerer med brugeren. 2. Application servere Håndterer business logic 3. Database servere Håndterer hvad app serverne har brug for fra databasen 36
Eksempel: Amazon Databasen indeholder information om produkter, kunder, etc. Business logic inkluderer ting som Hvad skal jeg gøre når nogen klikker på checkout? Svar: Vis Hvordan vil du betale? skærmbilledet 37
Environments, Connections, Queries Database er, i mange DB-access languages, et environment Database servere tilbyder et antal connections, så app servere kan udføre forespørgsler og lave opdateringer App serveren afsender statements: typisk forespørgsler og ændringer 38
JDBC Java Database Connectivity (JDBC) er et library for adgang til sin DBMS med Java som host language >200 drivere tilgængeligt: PostgreSQL, MySQL, Oracle, ODBC,... http://jdbc.postgresql.org/ 39
Making a Connection import java.sql.*;... Statisk loaded URL for databasen, brugernavn og password The JDBC classes Class.forName( org.postgresql.driver ); Connection mycon =... DriverManager.getConnection( ); Driver for postgresql; 40
URL for PostgreSQL database jdbc:postgresql://<host>[:<port>]/<database >?user=<user>& password=<password> Alternativt brug getconnection variant: getconnection( jdbc:postgresql://<host>[:<p ort>]/<database>, <user>, <password>); DriverManager.getConnection( jdbc:postgre sql://10.110.4.32:5434/postgres, petersk, geheim ); På samme system: 'localhost' som ip adresse 41
Statements JDBC udbyder to klasser: 1. Statement = et objekt der kan acceptere en string der er et SQL statement og kan udføre denne forespørgsel 2. PreparedStatement = et objekt der har et tilhørende SQL statement klar til at udføre 42
Oprette Statements Connection klassen har metoder til at oprette Statement og PreparedStatement Statement stat1 = mycon.createstatement(); PreparedStatement stat2 = mycon.preparestatement( ); SELECT beer, price FROM Sells + WHERE bar = C.Ch. createstatement returnerer et Statement. preparestatement med argument returnerer et PreparedStatement 43
Afvikle SQL Statements JDBC skelner mellem forespørgsler og modifikationer, som den kalder updates Statement og PreparedStatement har hver methoderne executequery og executeupdate For Statements: et argument SQL der skal udføres For PreparedStatements: ingen argument 44
Eksempel: Update stat1 er et Statement Vi kan indsætte tupler således: stat1.executeupdate( ); INSERT INTO Sells + VALUES( C.Ch., Eventyr,30) 45
Eksempel: Forespørgsel stat2 er et PreparedStatement indeholdende SELECT beer, price FROM Sells WHERE bar = C.Ch. executequery returnerer et object of klassen ResultSet (kommer) Forespørglen udføres ved: ResultSet menu = stat2.executequery(); 46
Eksempel: Forespørgsel stat2 er et PreparedStatement indeholdende SELECT beer, price FROM Sells WHERE bar = C.Ch. executequery returnerer et object of klassen ResultSet (kommer) Forespørglen udføres ved: ResultSet menu = stat2.executequery(); 47
ResultSet Et objekt af typen ResultSet minder om en cursor Methoden next() peger cursor til næste tupel Første gang next() udføres, peges på første tupel Hvis der ikke er flere tupler returnerer, vil next() returnere false 48
Tilgå elementer i tupler Når et ResultSet refererer til en tupel, kan vi få elementerne med metoder på ResultSet Methoden getx (i ), hvor X er en type, og i er elementets number, returneres værdien af det element Værdien skal have type X 49
Eksempel: Tilgå elementer Menu = ResultSet for SELECT beer, price FROM Sells WHERE bar = C.Ch. Tilgå beer og price fra hver tupel med: while (menu.next()) { } thebeer = menu.getstring(1); theprice = menu.getfloat(2); /* Gør moget med dem */ 50
Important Details Reusing a Statement object results in the ResultSet being closed Always create new Statement objects using createstatement() or explicitly close ResultSets using the close method For transactions, for the Connection con use con.setautocommit(false) and explicitly con.commit() or con.rollback() If AutoCommit is false and there is no commit, closing the connection = rollback 51
Et sidespring: SQL Injection SQL queries er ofte sammensat af programmer Disse queries kan have modtaget input fra brugerne Hvis man ikke passer på, kan det skabe yderst uventede resultater, når de afvikles 52
Eksempel: SQL Injection Relationen Accounts(name, passwd, acct) Web interface: Få name og password fra brugereb, gem i string n og p, udfør forespørgslen, vis account number s.executequery("select name, acct FROM accounts WHERE name = '" + navn + "' AND password= '" + password + "';"); 53
User (Der ikke er Bill Gates) Name: gates -- Kommentar i PostgreSQL Password: who cares? Your account number is 1234-567 54
Den udførte forespørgsel SELECT acct FROM Accounts WHERE name = gates -- AND passwd = who cares? Behandlet som kommentar! 55
Resume 7 Det ved vi noget om nu: Stored Procedures, PL/pgsql Declarations, Statements, Loops, Cursors, Tuple Variables 3-lags arkitektur, JDBC 56