❖ PLpgSQL |
PLpgSQL = Procedural Language extensions to PostgreSQL
A PostgreSQL-specific language integrating features of:
Provides a means for extending DBMS functionality, e.g.
❖ Defining PLpgSQL Functions |
PLpgSQL functions are created (and inserted into db) via:
CREATE OR REPLACE funcName(param1, param2, ....) RETURNS rettype AS $$ DECLARE variable declarations BEGIN code for function END; $$ LANGUAGE plpgsql;
Note: the entire function body is a single SQL string ($$
$$
❖ PLpgSQL Examples |
Example: function to compute x / y "safely"
create or replace function div(x integer, y integer) returns integer as $$ declare result integer; -- variable begin if (y <> 0) then -- conditional result := x/y; -- assignment else result := 0; -- assignment end if; return result; end; $$ language plpgsql;
❖ PLpgSQL Examples (cont) |
Example: function to compute n!
create or replace function factorial(n integer) returns integer as $$ declare i integer; fac integer := 1; begin for i in 1..n loop fac := fac * i; end loop; return fac; end; $$ language plpgsql;
❖ PLpgSQL Examples (cont) |
Example: function to compute n! recursively
create function factorial(n integer) returns integer as $$ begin if n < 2 then return 1; else return n * factorial(n-1); end if; end; $$ language plpgsql;
Usage: select factorial(5);
❖ PLpgSQL Examples (cont) |
Example: handle withdrawl from account and return status message
create function withdraw(acctNum text, amount integer) returns text as $$ declare bal integer; begin select balance into bal from Accounts where acctNo = acctNum; if bal < amount then return 'Insufficient Funds'; else update Accounts set balance = balance - amount where acctNo = acctNum; select balance into bal from Accounts where acctNo = acctNum; return 'New Balance: ' || bal; end if; end; $$ language plpgsql;
❖ PLpgSQL Gotchas |
Some things to beware of:
RAISE NOTICE
Summary: debugging PLpgSQL can sometimes be tricky.
❖ Data Types |
PLpgSQL constants and variables can be defined using:
CHAR, DATE, NUMBER, ...
Point
RECORD
Branches%ROWTYPE
Branches
Branches.location%TYPE
CURSOR
❖ Data Types (cont) |
Variables can also be defined in terms of:
RECORD
quantity INTEGER;
start_qty quantity%TYPE;
employee Employees%ROWTYPE;
-- or
employee Employees;
name Employees.name%TYPE;
❖ Syntax/Control Structures |
Typical set of control structures, with extensions:
var := SELECT INTO |
||
IF Cond1 THEN S1 ELSIF Cond2 THEN S2 ... ELSE S END IF
|
||
LOOP S END LOOP WHILE Cond LOOP S END LOOP FOR rec_var IN Query LOOP ... FOR int_var IN lo..hi LOOP ...
|
Si = list of PLpgSQL statements, each terminated by semi-colon
❖ SELECT...INTO |
Can capture query results via:
SELECT Exp1,Exp2,...,Expn INTO Var1,Var2,...,Varn FROM TableList WHERE Condition ...
The semantics:
❖ SELECT...INTO (cont) |
Assigning a simple value via SELECT...INTO
-- cost is local var, price is attr
select price into cost
from StockList
where item = 'Cricket Bat';
cost := cost * (1+tax_rate);
total := total + cost;
The current PostgreSQL parser also allows this syntax:
select into cost price from StockList where item = 'Cricket Bat';
❖ SELECT...INTO (cont) |
Assigning whole rows via SELECT...INTO
declare
emp Employees%ROWTYPE;
-- alternatively, emp RECORD;
eName text;
pay real;
begin
select * into emp
from Employees where id = 966543;
eName := emp.name;
...
select name,salary into eName,pay
from Employees where id = 966543;
end;
❖ SELECT...INTO (cont) |
In the case of a PLpgSQL statement like
select a into b from R where ...
If the selection returns no tuples
b
NULL
b
❖ SELECT...INTO (cont) |
An alternative to check for "no data found"
Use the special variable FOUND
SELECT
INSERT/DELETE/UPDATE
FALSE
select a into b from R where ...
if (not found) then
-- handle case where no matching tuples b
Produced: 6 Oct 2020