Stored Procedures

‹PSM, or “persistent, stored modules,” SQL/PSM allows us to store procedures as schema elements. ‹PSM = a mixture of conventional Procedures Stored in the Database statements (if, while, etc.) and SQL. General-Purpose Programming ‹Lets us do things we cannot do in SQL alone.

1 2

Basic PSM Form Parameters in PSM

CREATE PROCEDURE ( ‹Unlike the usual name-type pairs in ) languages like C, PSM uses mode- name-type triples, the mode can be: ; Š IN = procedure uses value, does not ‹Function alternative: change value. CREATE FUNCTION ( Š OUT = procedure changes, does not use. ) RETURNS Š INOUT = both.

3 4

1 Example: The Procedure

‹Let’s write a procedure that takes two CREATE PROCEDURE JoeMenu ( arguments b and p, and adds a tuple IN b CHAR(20), Parameters are both to Sells(bar, beer, price) that has bar = IN p REAL read-only, not changed ’Joe’’s Bar’, beer = b, and price = p. ) Š Used by Joe to add to his menu more easily. INSERT INTO Sells The body --- VALUES(’Joe’’s Bar’, b, p); a single insertion

5 6

Invoking Procedures Types of PSM statements --- (1)

‹Use SQL/PSM statement CALL, with the ‹RETURN sets the return name of the desired procedure and value of a function. arguments. Š Unlike C, etc., RETURN does not terminate ‹Example: function execution. CALL JoeMenu(’Moosedrool’, 5.00); ‹DECLARE used to declare local variables. ‹Functions used in SQL expressions wherever a value of their return type is appropriate. ‹BEGIN . . . END for groups of statements. Š Separate statements by semicolons.

7 8

2 Types of PSM Statements --- (2) IF Statements

‹Assignment statements: ‹Simplest form: SET = ; IF THEN Š Example: SET b = ’Bud’; END IF; ‹Statement labels: give a statement a ‹Add ELSE if desired, as label by prefixing a name and a colon. IF . . . THEN . . . ELSE . . . END IF; ‹Add additional cases by ELSEIF : IF … THEN … ELSEIF … ELSEIF … ELSE … END IF; 9 10

Example: IF Example: IF (continued)

CREATE FUNCTION Rate (IN b CHAR(20) ) ‹Let’s rate bars by how many customers Number of RETURNS CHAR(10) customers of they have, based on Frequents(drinker,bar). DECLARE cust INTEGER; bar b Š <100 customers: ‘unpopular’. BEGIN Š 100-199 customers: ‘average’. SET cust = (SELECT COUNT(*) FROM Frequents Š >= 200 customers: ‘popular’. WHERE bar = b); IF cust < 100 THEN RETURN ’unpopular’ ‹Function Rate(b) rates bar b. ELSEIF cust < 200 THEN RETURN ’average’ ELSE RETURN ’popular’ END IF; Nested IF statement 11 END; Return occurs here, not at 12 one of the RETURN statements

3 Loops Example: Exiting a Loop

‹Basic form: loop1: LOOP LOOP END LOOP; . . . ‹Exit a loop by: LEAVE loop1; If this statement is executed . . . LEAVE . . . ‹The is associated with a END LOOP;

loop by prepending the name and a Control winds up here colon to the keyword LOOP.

13 14

Other Loop Forms Queries

‹WHILE ‹ General SELECT-FROM-WHERE DO queries are not permitted in PSM. END WHILE; ‹ There are three ways to get the effect ‹REPEAT of a query: UNTIL 1. Queries producing one value can be the END REPEAT; expression in an assignment. 2. Single-row SELECT . . . INTO. 3. Cursors.

15 16

4 Example: Assignment/Query SELECT . . . INTO

‹If p is a local variable and Sells(bar, beer, ‹An equivalent way to get the value of a query price) the usual relation, we can get the price that is guaranteed to return one tuple is by Joe charges for Bud by: placing INTO after the SELECT clause. SET p = (SELECT price FROM Sells ‹Example: WHERE bar = ’Joe’’s Bar’ AND SELECT price INTO p FROM Sells beer = ’Bud’); WHERE bar = ’Joe’’s Bar’ AND beer = ’Bud’;

17 18

Cursors Opening and Closing Cursors

‹A is essentially a tuple-variable ‹To use cursor c, we must issue the that ranges over all tuples in the result command: of some query. OPEN c; ‹Declare a cursor c by: Š The query of c is evaluated, and c is set DECLARE c CURSOR FOR ; to point to the first tuple of the result. ‹When finished with c, issue command: CLOSE c;

19 20

5 Fetching Tuples From a Cursor Breaking Cursor Loops --- (1)

‹To get the next tuple from cursor c, ‹The usual way to use a cursor is to issue command: create a loop with a FETCH statement, FETCH FROM c INTO x1, x2,…,xn ; and do something with each tuple ‹The x ’s are a list of variables, one for fetched. each component of the tuples referred ‹A tricky point is how we get out of the to by c. loop when the cursor has no more ‹c is moved automatically to the next tuples to deliver. tuple. 21 22

Breaking Cursor Loops --- (2) Breaking Cursor Loops --- (3)

‹Each SQL operation returns a status, ‹We may declare a condition, which is a which is a 5-digit number. boolean variable that is true if and only Š For example, 00000 = “Everything OK,” if SQLSTATE has a particular value. and 02000 = “Failed to find a tuple.” ‹Example: We can declare condition ‹In PSM, we can get the value of the NotFound to represent 02000 by: status in a variable called SQLSTATE. DECLARE NotFound CONDITION FOR SQLSTATE ’02000’;

23 24

6 Breaking Cursor Loops --- (4) Example: Cursor

‹The structure of a cursor loop is thus: ‹Let’s write a procedure that examines cursorLoop: LOOP Sells(bar, beer, price), and raises by $1 … the price of all beers at Joe’s Bar that FETCH c INTO … ; are under $3. IF NotFound THEN LEAVE cursorLoop; Š Yes, we could write this as a simple END IF; UPDATE, but the details are instructive anyway. … END LOOP;

25 26

The Procedure Body The Needed Declarations BEGIN OPEN c; Check if the recent FETCH failed to CREATE PROCEDURE JoeGouge( ) Used to hold menuLoop: LOOP get a tuple DECLARE theBeer CHAR(20); beer-price pairs FETCH c INTO theBeer, thePrice; when fetching DECLARE thePrice REAL; through cursor c IF NotFound THEN LEAVE menuLoop END IF; DECLARE NotFound CONDITION FOR IF thePrice < 3.00 THEN UPDATE Sells SET price = thePrice + 1.00 SQLSTATE ’02000’; WHERE bar = ’Joe’’s Bar’ AND beer = theBeer; Returns Joe’s menu DECLARE c CURSOR FOR END IF; END LOOP; (SELECT beer, price FROM Sells If Joe charges less than $3 for WHERE bar = ’Joe’’s Bar’); CLOSE c; the beer, raise it’s price at END; Joe’s Bar by $1. 27 28

7