PostgreSQL Functions by Example
PostgreSQL Functions by Example
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Arguments
Base, composite, or combinations Scalar or array Pseudo or polymorphic VARIADIC IN/OUT/INOUT
Return
Singleton or set (SETOF) Base or composite type Pseudo or polymorphic
http://www.postgresql.org/docs/9.1/interactive/sql-createfunction.html Joe Conway SCALE10X-PGDay
SQL Functions
Behavior
Executes an arbitrary list of SQL statements separated by semicolons Last statement may be INSERT, UPDATE, or DELETE with RETURNING clause
Arguments
Referenced by function body using $n: $1 is rst arg, etc. . . If composite type, then dot notation $1.name used to access Only used as data values, not as identiers
Return
If singleton, rst row of last query result returned, NULL on no result If SETOF, all rows of last query result returned, empty set on no result
http://www.postgresql.org/docs/9.1/interactive/xfunc-sql.html Joe Conway SCALE10X-PGDay
Procedural Languages
Joe Conway
SCALE10X-PGDay
Internal Functions
http://www.postgresql.org/docs/9.1/interactive/xfunc-internal.html
Joe Conway
SCALE10X-PGDay
C Language Functions
Joe Conway
SCALE10X-PGDay
Language Availability
PostgreSQL includes the following server-side procedural languages:
http://www.postgresql.org/docs/9.1/interactive/xplang.html
Creation Attributes
CREATE [ OR REPLACE ] FUNCTION name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } defexpr ] [, ... [ RETURNS rettype | RETURNS TABLE ( colname coltype [, ...] ) ] { LANGUAGE langname | WINDOW | IMMUTABLE | STABLE | VOLATILE | CALLED ON NULL INPUT | RETURNS NULL ON NULL INPUT | STRICT | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | COST execution_cost | ROWS result_rows | SET configuration_parameter { TO value | = value | FROM CURRENT } | AS definition | AS obj_file, link_symbol } ... [ WITH ( attribute [, ...] ) ]
Creation Attributes
Dollar Quoting
Works for all character strings Particularly useful for function bodies
CREATE OR REPLACE FUNCTION dummy () RETURNS text AS $Q$ DECLARE result text; BEGIN PERFORM SELECT 1+1; RETURN ok; END; $Q$ LANGUAGE plpgsql;
http://www.postgresql.org/docs/9.1/static/sql-syntax-lexical.html#SQL-SYNTAX-DOLLAR-QUOTING
Joe Conway
SCALE10X-PGDay
Creation Attributes
Function Overloading
IN argument signature used Avoid ambiguities:
Type (e.g. REAL vs. DOUBLE PRECISION) Function name same as IN composite eld name VARIADIC vs same type scalar
CREATE OR REPLACE FUNCTION foo (text) RETURNS text AS $$ SELECT $1 $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION foo (int) RETURNS text AS $$ SELECT ($1 + 1)::text $$ LANGUAGE sql; SELECT foo(42), foo(41); foo | foo -----+----42 | 42 (1 row)
Creation Attributes
Joe Conway
SCALE10X-PGDay
Creation Attributes
Volatility
VOLATILE (default)
Each call can return a dierent result Example: random() or timeofday() Functions modifying table contents must be declared volatile
STABLE
Returns same result for same arguments within single query Example: now() Consider conguration settings that aect output
IMMUTABLE
Always returns the same result for the same arguments Example: lower(ABC) Unaected by conguration settings Not dependent on table contents
select lower(ABC), now(), timeofday() from generate_series(1,3);
Joe Conway
SCALE10X-PGDay
Creation Attributes
Joe Conway
SCALE10X-PGDay
Creation Attributes
Security Attributes
SECURITY INVOKER (default)
Function executed with the rights of the current user
SECURITY DEFINER
Executed with rights of creator, like setuid
CREATE TABLE foo (f1 int); REVOKE ALL ON foo FROM public; CREATE FUNCTION see_foo() RETURNS SETOF foo AS $$ SELECT * FROM foo $$ LANGUAGE SQL SECURITY DEFINER; \c - guest You are now connected to database "postgres" as user "guest". SELECT * FROM foo; ERROR: permission denied for relation foo SELECT * FROM see_foo(); f1 ---(0 rows)
Joe Conway
SCALE10X-PGDay
Simple
CREATE FUNCTION sum (text, text) RETURNS text AS $$ SELECT $1 || || $2 $$ LANGUAGE SQL; SELECT sum(hello, world); sum ------------hello world (1 row)
Joe Conway
SCALE10X-PGDay
Custom Operator
CREATE OPERATOR + ( procedure = sum, leftarg = text, rightarg = text ); SELECT hello + world; ?column? ------------hello world (1 row)
Joe Conway
SCALE10X-PGDay
Custom Aggregate
CREATE OR REPLACE FUNCTION concat_ws_comma(text, ANYELEMENT) RETURNS text AS $$ SELECT concat_ws(,, $1, $2) $$ LANGUAGE sql; CREATE AGGREGATE str_agg (ANYELEMENT) ( sfunc = concat_ws_comma, stype = text); SELECT str_agg(f1) FROM foo; str_agg --------41,42 (1 row)
Joe Conway
SCALE10X-PGDay
CREATE OR REPLACE FUNCTION sql_with_rows(OUT a int, OUT b text) RETURNS SETOF RECORD AS $$ values (1,a),(2,b) $$ LANGUAGE SQL; select * from sql_with_rows(); a | b ---+--1 | a 2 | b (2 rows)
Joe Conway
SCALE10X-PGDay
INSERT RETURNING
CREATE TABLE foo (f0 serial, f1 int, f2 text); CREATE OR REPLACE FUNCTION sql_insert_returning(INOUT f1 int, INOUT f2 text, OUT id int) AS $$ INSERT INTO foo(f1, f2) VALUES ($1,$2) RETURNING f1, f2, f0 $$ LANGUAGE SQL; SELECT * FROM sql_insert_returning(1,a); f1 | f2 | id ----+----+---1 | a | 1 (1 row)
Joe Conway
SCALE10X-PGDay
Composite Argument
CREATE FUNCTION double_salary(emp) RETURNS numeric AS $$ SELECT $1.salary * 2 AS salary; $$ LANGUAGE SQL; SELECT name, double_salary(emp.*) AS dream FROM emp WHERE emp.cubicle ~= point (2,1); SELECT name, double_salary(ROW(name, salary*1.1, age, cubicle)) AS dream FROM emp;
Joe Conway
SCALE10X-PGDay
Polymorphic
CREATE FUNCTION myappend(anyarray, anyelement) RETURNS anyarray AS $$ SELECT $1 || $2; $$ LANGUAGE SQL; SELECT myappend(ARRAY[42,6], 21), myappend(ARRAY[abc,def], xyz); myappend | myappend -----------+--------------{42,6,21} | {abc,def,xyz} (1 row)
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
VARIADIC
CREATE FUNCTION mleast(VARIADIC numeric[]) RETURNS numeric AS $$ SELECT min($1[i]) FROM generate_subscripts($1, 1) g(i); $$ LANGUAGE SQL; SELECT mleast(10, -1, 5, 4.4); mleast --------1 (1 row) SELECT mleast(42, 6, 42.42); mleast -------6 (1 row)
Joe Conway
SCALE10X-PGDay
DEFAULT Arguments
CREATE FUNCTION foo(a int, b int DEFAULT 2, c int DEFAULT 3) RETURNS int LANGUAGE SQL AS $$SELECT $1 + $2 + $3$$; SELECT foo(10, 20, 30); foo ----60 (1 row) SELECT foo(10, 20); foo ----33 (1 row)
Joe Conway
SCALE10X-PGDay
PL/pgSQL
http://www.postgresql.org/docs/9.1/interactive/plpgsql.html
Joe Conway
SCALE10X-PGDay
Simple
CREATE OR REPLACE FUNCTION sum (text, text) RETURNS text AS $$ BEGIN RETURN $1 || || $2; END; $$ LANGUAGE plpgsql; SELECT sum(hello, world); sum ------------hello world (1 row)
Joe Conway
SCALE10X-PGDay
Parameter ALIAS
CREATE OR REPLACE FUNCTION sum (int, int) RETURNS int AS $$ DECLARE i ALIAS FOR $1; j ALIAS FOR $2; sum int; BEGIN sum := i + j; RETURN sum; END; $$ LANGUAGE plpgsql; SELECT sum(41, 1); sum ----42 (1 row)
Joe Conway
SCALE10X-PGDay
Named Parameters
CREATE OR REPLACE FUNCTION sum (i int, j int) RETURNS int AS $$ DECLARE sum int; BEGIN sum := i + j; RETURN sum; END; $$ LANGUAGE plpgsql; SELECT sum(41, 1); sum ----42 (1 row)
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Recursive
CREATE OR REPLACE FUNCTION factorial (i numeric) RETURNS numeric AS $$ BEGIN IF i = 0 THEN RETURN 1; ELSIF i = 1 THEN RETURN 1; ELSE RETURN i * factorial(i - 1); END IF; END; $$ LANGUAGE plpgsql; SELECT factorial(42::numeric); factorial -----------------------------------------------------1405006117752879898543142606244511569936384000000000 (1 row)
Joe Conway
SCALE10X-PGDay
Record types
CREATE OR REPLACE FUNCTION format () RETURNS text AS $$ DECLARE tmp RECORD; BEGIN SELECT INTO tmp 1 + 1 AS a, 2 + 2 AS b; RETURN a = || tmp.a || ; b = || tmp.b; END; $$ LANGUAGE plpgsql; select format(); format -------------a = 2; b = 4 (1 row)
Joe Conway
SCALE10X-PGDay
PERFORM
CREATE OR REPLACE FUNCTION func_w_side_fx() RETURNS void AS $$ INSERT INTO foo VALUES (41),(42) $$ LANGUAGE sql; CREATE OR REPLACE FUNCTION dummy () RETURNS text AS $$ BEGIN PERFORM func_w_side_fx(); RETURN OK; END; $$ LANGUAGE plpgsql; SELECT dummy(); SELECT * FROM foo; f1 ---41 42 (2 rows)
Joe Conway
SCALE10X-PGDay
Dynamic SQL
CREATE OR REPLACE FUNCTION get_foo(i int) RETURNS foo AS $$ DECLARE rec RECORD; BEGIN EXECUTE SELECT * FROM foo WHERE f1 = || i INTO rec; RETURN rec; END; $$ LANGUAGE plpgsql; SELECT * FROM get_foo(42); f1 ---42 (1 row)
Joe Conway
SCALE10X-PGDay
Cursors
CREATE OR REPLACE FUNCTION totalbalance() RETURNS numeric AS $$ DECLARE tmp RECORD; result numeric; BEGIN result := 0.00; FOR tmp IN SELECT * FROM foo LOOP result := result + tmp.f1; END LOOP; RETURN result; END; $$ LANGUAGE plpgsql; SELECT totalbalance(); totalbalance -------------83.00 (1 row)
Joe Conway
SCALE10X-PGDay
Error Handling
CREATE OR REPLACE FUNCTION safe_add(a integer, b integer) RETURNS integer AS $$ BEGIN RETURN a + b; EXCEPTION WHEN numeric_value_out_of_range THEN -- do some important stuff RETURN -1; WHEN OTHERS THEN -- do some other important stuff RETURN -1; END; $$ LANGUAGE plpgsql;
http://www.postgresql.org/docs/9.1/interactive/errcodes-appendix.html
Joe Conway
SCALE10X-PGDay
Joe Conway
SCALE10X-PGDay
Thank You
Questions?
Joe Conway
SCALE10X-PGDay