❖ 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 NOTICESummary: debugging PLpgSQL can sometimes be tricky.
❖ Data Types |
PLpgSQL constants and variables can be defined using:
CHAR, DATE, NUMBER, ...PointRECORDBranches%ROWTYPEBranchesBranches.location%TYPECURSOR❖ 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 :=SELECTINTO |
||
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
bNULLb❖ SELECT...INTO (cont) |
An alternative to check for "no data found"
Use the special variable FOUND
SELECTINSERT/DELETE/UPDATEFALSE
select a into b from R where ...
if (not found) then
-- handle case where no matching tuples b
Produced: 6 Oct 2020