SlideShare a Scribd company logo
1 of 44
The Lost Art
of
PLPGSQL
pgcon 2019
Robert Treat (@robtreat2) the lost art of plpgsql
NOTE: There Will Be Code!
Robert Treat (@robtreat2) the lost art of plpgsql
whoami?
occasional
dev | ops | dba
currently
lead u.s. operations
at credativ
open source services and support
we build and run world class applications and
infrastructure to empower our clients
Robert Treat (@robtreat2) the lost art of plpgsql
whoami?
@robtreat2
robert.treat@credativ.us
https://www.linkedin.com/company/credativ-llc
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of postgres functions
how many of you have used a postgres function?
Robert Treat (@robtreat2) the lost art of plpgsql
why plpgsql
server side / round trips
stable api
simplify portability*
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of postgres functions
four types of postgres functions:
• internal functions
• query language functions (functions written in SQL)
• procedural language functions (functions written in PL/pgSQL)
• C-language functions
they all work similarly and have overlapping bits,
today we only care about
procedural language functions
specifically plpgsql ones
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of postgres functions
https://www.postgresql.org/docs/current/sql-createfunction.html
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of plpgsql
Chapter 42
“PL/pgSQL - SQL Procedural Language”
note: you can write stored procedures
in pure SQL, but this is not that
Robert Treat (@robtreat2) the lost art of plpgsql
a very brief overview of plpgsql
originally added in 6.4
(pl/tcl added in 6.3)
installed by default in 9.0
minimal language for creating triggers and user defined functions
add basic control structures to SQL
“trusted” language for server side computation
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of plpgsql
get diagnostics
when doing dynamic query execution
“get diagnostics” can be used for finding
row count and call stack information
additionally, /FOUND/ variable can be used
to determine query outcomes
42.5.5 Obtaining the Result Status
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of plpgsql
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of plpgsql
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
a brief overview of plpgsql
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql function
CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer)
RETURNS boolean
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RETURN TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RETURN FALSE;
ELSE
RETURN TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
postgres@pagila=# select inventory_in_stock(42);
inventory_in_stock
--------------------
t
(1 row)
Robert Treat (@robtreat2) the lost art of plpgsql
how to plpgsql
user defined functions
do scripts
stored procedures
postgres@pagila=#
DO $$
DECLARE
v_row record;
BEGIN
FOR v_row IN
SELECT film_id, title, rating FROM film WHERE film_id < 10
LOOP
IF v_row.rating ='G'::mpaa_rating THEN
RAISE NOTICE '% is safe for tv',v_row.title;
END IF;
END LOOP;
END$$
;
NOTICE: ACE GOLDFINGER is safe for tv
NOTICE: AFFAIR PREJUDICE is safe for tv
NOTICE: AFRICAN EGG is safe for tv
DO
Robert Treat (@robtreat2) the lost art of plpgsql
at least one slide on DO scripts
https://www.postgresql.org/docs/current/sql-do.html
postgres@pagila=#
DO$$
BEGIN
vacuum actor;
vacuum film;
END
$$;
ERROR: VACUUM cannot be executed from a function
CONTEXT: SQL statement "vacuum actor"
PL/pgSQL function inline_code_block line 1 at SQL statement
Robert Treat (@robtreat2) the lost art of plpgsql
at least one slide on DO scripts
Robert Treat (@robtreat2) the lost art of plpgsql
what even is a procedure?
enter stored procedures
Robert Treat (@robtreat2) the lost art of plpgsql
what even is a procedure?
but first a history
Robert Treat (@robtreat2) the lost art of plpgsql
what even is a procedure?
“other databases say”
functions: user defined code that executes some
set of commands and returns a result
stored procedures: user defined code that
executes some set of commands returning no
result
Robert Treat (@robtreat2) the lost art of plpgsql
what even is a procedure?
create function
smored_promedure()
returns void as $$
begin
return;
end
$$ language plpgsql;
postgres@pagila=#
select smored_promedure();
smored_promedure
------------------
(1 row)
Robert Treat (@robtreat2) the lost art of plpgsql
what even is a procedure?
“in postgres, functions are equivalent to stored
procedures, and can be used interchangeably”
Robert Treat (@robtreat2) the lost art of plpgsql
stored procedures, turned up to 11
sql standard based
allow transaction control
Robert Treat (@robtreat2) the lost art of plpgsql
stored procedures, turned up to 11
postgres@pagila=# h create procedure
Command: CREATE PROCEDURE
Description: define a new procedure
Syntax:
CREATE [ OR REPLACE ] PROCEDURE
name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = }
default_expr ] [, ...] ] )
{ LANGUAGE lang_name
| TRANSFORM { FOR TYPE type_name } [, ... ]
| [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER
| SET configuration_parameter { TO value | = value | FROM CURRENT }
| AS 'definition'
| AS 'obj_file', 'link_symbol'
} ...
Robert Treat (@robtreat2) the lost art of plpgsql
stored procedures, turned up to 11
postgres@pagila=# h call
Command: CALL
Description: invoke a procedure
Syntax:
CALL name ( [ argument ] [, ...] )
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
CREATE OR REPLACE PROCEDURE inventory_in_sproc(p_inventory_id integer)
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RAISE NOTICE ‘TRUE’;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RAISE NOTICE ‘FALSE’;
ELSE
RAISE NOTICE ‘TRUE’;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
CREATE OR REPLACE PROCEDURE inventory_in_sproc(p_inventory_id integer)
LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
RAISE NOTICE ‘TRUE’;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
RAISE NOTICE ‘FALSE’;
ELSE
RAISE NOTICE ‘TRUE’;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
postgres@pagila=# call inventory_in_sproc(42);
NOTICE: TRUE
CALL
postgres@pagila=# select inventory_in_stock(42);
inventory_in_stock
--------------------
t
(1 row)
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
CREATE OR REPLACE PROCEDURE inventory_in_shock(
IN p_inventory_id integer,
INOUT p_instock boolean DEFAULT false
) LANGUAGE plpgsql
AS $$
DECLARE
v_rentals INTEGER;
v_out INTEGER;
BEGIN
-- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE
-- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED
SELECT count(*) INTO v_rentals
FROM rental
WHERE inventory_id = p_inventory_id;
IF v_rentals = 0 THEN
p_instock := TRUE;
END IF;
SELECT COUNT(rental_id) INTO v_out
FROM inventory LEFT JOIN rental USING(inventory_id)
WHERE inventory.inventory_id = p_inventory_id
AND rental.return_date IS NULL;
IF v_out > 0 THEN
p_instock := FALSE;
ELSE
p_instock := TRUE;
END IF;
END $$;
Robert Treat (@robtreat2) the lost art of plpgsql
an example plpgsql procedure
postgres@pagila=# call inventory_in_sproc(42);
NOTICE: TRUE
CALL
postgres@pagila=# select inventory_in_stock(42);
inventory_in_stock
--------------------
t
(1 row)
postgres@pagila=# call inventory_in_shock(42);
p_instock
-----------
t
(1 row)
Robert Treat (@robtreat2) the lost art of plpgsql
plpgsql procedure transaction control
postgres@pagila=# create table xx (xx int);
CREATE TABLE
postgres@pagila=#
create or replace procedure xx()
as $$
begin
insert into xx select 1; rollback;
insert into xx select 2; commit;
insert into xx select 3; rollback;
end $$
language plpgsql;
CREATE PROCEDURE
postgres@pagila=# call xx();
CALL
postgres@pagila=# select * from xx;
xx
----
2
(1 row)
Robert Treat (@robtreat2) the lost art of plpgsql
plpgsql procedure transaction control
postgres@pagila=# create or replace procedure merry_maids() as $$
begin vacuum actor; end $$ language plpgsql;
CREATE PROCEDURE
postgres@pagila=# call merry_maids();
ERROR: VACUUM cannot be executed from a function
CONTEXT: SQL statement "vacuum actor”
* fyi, you can do this with analyze
Robert Treat (@robtreat2) the lost art of plpgsql
more to do!
certain ddl - create index concurrently
vacuum support
multiple result-sets
#thankyou
Robert Treat (@robtreat2) the lost art of plpgsql

More Related Content

What's hot

ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6 1
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6  1ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6  1
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6 1Little Tukta Lita
 
Function overloading(C++)
Function overloading(C++)Function overloading(C++)
Function overloading(C++)Ritika Sharma
 
Lambda Expressions in C++
Lambda Expressions in C++Lambda Expressions in C++
Lambda Expressions in C++Patrick Viafore
 
GC in C++0x [eng]
GC in C++0x [eng]GC in C++0x [eng]
GC in C++0x [eng]yak1ex
 
TypeScriptのすゝめ
TypeScriptのすゝめTypeScriptのすゝめ
TypeScriptのすゝめCASAREAL, Inc.
 
Debugging Your PHP Cake Application
Debugging Your PHP Cake ApplicationDebugging Your PHP Cake Application
Debugging Your PHP Cake ApplicationJose Diaz-Gonzalez
 
Functions in C++ (OOP)
Functions in C++ (OOP)Functions in C++ (OOP)
Functions in C++ (OOP)Faizan Janjua
 
C++17 introduction - Meetup @EtixLabs
C++17 introduction - Meetup @EtixLabsC++17 introduction - Meetup @EtixLabs
C++17 introduction - Meetup @EtixLabsStephane Gleizes
 
Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Fernando Daciuk
 
46630497 fun-pointer-1
46630497 fun-pointer-146630497 fun-pointer-1
46630497 fun-pointer-1AmIt Prasad
 
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime
 

What's hot (19)

Functions in C++
Functions in C++Functions in C++
Functions in C++
 
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6 1
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6  1ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6  1
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม. 6 1
 
Function overloading(C++)
Function overloading(C++)Function overloading(C++)
Function overloading(C++)
 
Lambda Expressions in C++
Lambda Expressions in C++Lambda Expressions in C++
Lambda Expressions in C++
 
Function
FunctionFunction
Function
 
Oop in java script
Oop in java scriptOop in java script
Oop in java script
 
GC in C++0x [eng]
GC in C++0x [eng]GC in C++0x [eng]
GC in C++0x [eng]
 
TypeScriptのすゝめ
TypeScriptのすゝめTypeScriptのすゝめ
TypeScriptのすゝめ
 
Debugging Your PHP Cake Application
Debugging Your PHP Cake ApplicationDebugging Your PHP Cake Application
Debugging Your PHP Cake Application
 
Function in c
Function in cFunction in c
Function in c
 
Functions in C++ (OOP)
Functions in C++ (OOP)Functions in C++ (OOP)
Functions in C++ (OOP)
 
C++17 introduction - Meetup @EtixLabs
C++17 introduction - Meetup @EtixLabsC++17 introduction - Meetup @EtixLabs
C++17 introduction - Meetup @EtixLabs
 
Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015Javascript Secrets - Front in Floripa 2015
Javascript Secrets - Front in Floripa 2015
 
Function in c
Function in cFunction in c
Function in c
 
46630497 fun-pointer-1
46630497 fun-pointer-146630497 fun-pointer-1
46630497 fun-pointer-1
 
C++ functions
C++ functionsC++ functions
C++ functions
 
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java scriptCodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
CodiLime Tech Talk - Grzegorz Rozdzialik: What the java script
 
C++ functions
C++ functionsC++ functions
C++ functions
 
Function lecture
Function lectureFunction lecture
Function lecture
 

Similar to the-lost-art-of-plpgsql

The Ring programming language version 1.2 book - Part 58 of 84
The Ring programming language version 1.2 book - Part 58 of 84The Ring programming language version 1.2 book - Part 58 of 84
The Ring programming language version 1.2 book - Part 58 of 84Mahmoud Samir Fayed
 
C++ Advanced
C++ AdvancedC++ Advanced
C++ AdvancedVivek Das
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...Kirill Chebunin
 
Writing Node.js Bindings - General Principles - Gabriel Schulhof
Writing Node.js Bindings - General Principles - Gabriel SchulhofWriting Node.js Bindings - General Principles - Gabriel Schulhof
Writing Node.js Bindings - General Principles - Gabriel SchulhofWithTheBest
 
The Ring programming language version 1.5.4 book - Part 81 of 185
The Ring programming language version 1.5.4 book - Part 81 of 185The Ring programming language version 1.5.4 book - Part 81 of 185
The Ring programming language version 1.5.4 book - Part 81 of 185Mahmoud Samir Fayed
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in JavascriptKnoldus Inc.
 
The Ring programming language version 1.10 book - Part 96 of 212
The Ring programming language version 1.10 book - Part 96 of 212The Ring programming language version 1.10 book - Part 96 of 212
The Ring programming language version 1.10 book - Part 96 of 212Mahmoud Samir Fayed
 
The secret of PHP7's Performance
The secret of PHP7's Performance The secret of PHP7's Performance
The secret of PHP7's Performance Xinchen Hui
 
The Ring programming language version 1.9 book - Part 94 of 210
The Ring programming language version 1.9 book - Part 94 of 210The Ring programming language version 1.9 book - Part 94 of 210
The Ring programming language version 1.9 book - Part 94 of 210Mahmoud Samir Fayed
 
02 Php Vars Op Control Etc
02 Php Vars Op Control Etc02 Php Vars Op Control Etc
02 Php Vars Op Control EtcGeshan Manandhar
 

Similar to the-lost-art-of-plpgsql (12)

stack.pptx
stack.pptxstack.pptx
stack.pptx
 
The Ring programming language version 1.2 book - Part 58 of 84
The Ring programming language version 1.2 book - Part 58 of 84The Ring programming language version 1.2 book - Part 58 of 84
The Ring programming language version 1.2 book - Part 58 of 84
 
C++ Advanced
C++ AdvancedC++ Advanced
C++ Advanced
 
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
ZFConf 2010: Zend Framework & MVC, Model Implementation (Part 2, Dependency I...
 
The STL
The STLThe STL
The STL
 
Writing Node.js Bindings - General Principles - Gabriel Schulhof
Writing Node.js Bindings - General Principles - Gabriel SchulhofWriting Node.js Bindings - General Principles - Gabriel Schulhof
Writing Node.js Bindings - General Principles - Gabriel Schulhof
 
The Ring programming language version 1.5.4 book - Part 81 of 185
The Ring programming language version 1.5.4 book - Part 81 of 185The Ring programming language version 1.5.4 book - Part 81 of 185
The Ring programming language version 1.5.4 book - Part 81 of 185
 
Functional programming in Javascript
Functional programming in JavascriptFunctional programming in Javascript
Functional programming in Javascript
 
The Ring programming language version 1.10 book - Part 96 of 212
The Ring programming language version 1.10 book - Part 96 of 212The Ring programming language version 1.10 book - Part 96 of 212
The Ring programming language version 1.10 book - Part 96 of 212
 
The secret of PHP7's Performance
The secret of PHP7's Performance The secret of PHP7's Performance
The secret of PHP7's Performance
 
The Ring programming language version 1.9 book - Part 94 of 210
The Ring programming language version 1.9 book - Part 94 of 210The Ring programming language version 1.9 book - Part 94 of 210
The Ring programming language version 1.9 book - Part 94 of 210
 
02 Php Vars Op Control Etc
02 Php Vars Op Control Etc02 Php Vars Op Control Etc
02 Php Vars Op Control Etc
 

More from Robert Treat

Advanced Int->Bigint Conversions
Advanced Int->Bigint ConversionsAdvanced Int->Bigint Conversions
Advanced Int->Bigint ConversionsRobert Treat
 
Explaining Explain
Explaining ExplainExplaining Explain
Explaining ExplainRobert Treat
 
Managing Chaos In Production: Testing vs Monitoring
Managing Chaos In Production: Testing vs MonitoringManaging Chaos In Production: Testing vs Monitoring
Managing Chaos In Production: Testing vs MonitoringRobert Treat
 
Managing Databases In A DevOps Environment 2016
Managing Databases In A DevOps Environment 2016Managing Databases In A DevOps Environment 2016
Managing Databases In A DevOps Environment 2016Robert Treat
 
Less Alarming Alerts - SRECon 2016
Less Alarming Alerts - SRECon 2016 Less Alarming Alerts - SRECon 2016
Less Alarming Alerts - SRECon 2016 Robert Treat
 
What Ops Can Learn From Design
What Ops Can Learn From DesignWhat Ops Can Learn From Design
What Ops Can Learn From DesignRobert Treat
 
Postgres 9.4 First Look
Postgres 9.4 First LookPostgres 9.4 First Look
Postgres 9.4 First LookRobert Treat
 
Less Alarming Alerts!
Less Alarming Alerts!Less Alarming Alerts!
Less Alarming Alerts!Robert Treat
 
Past, Present, and Pachyderm - All Things Open - 2013
Past, Present, and Pachyderm - All Things Open - 2013Past, Present, and Pachyderm - All Things Open - 2013
Past, Present, and Pachyderm - All Things Open - 2013Robert Treat
 
Big Bad "Upgraded" Postgres
Big Bad "Upgraded" PostgresBig Bad "Upgraded" Postgres
Big Bad "Upgraded" PostgresRobert Treat
 
Managing Databases In A DevOps Environment
Managing Databases In A DevOps EnvironmentManaging Databases In A DevOps Environment
Managing Databases In A DevOps EnvironmentRobert Treat
 
The Essential PostgreSQL.conf
The Essential PostgreSQL.confThe Essential PostgreSQL.conf
The Essential PostgreSQL.confRobert Treat
 
Advanced WAL File Management With OmniPITR
Advanced WAL File Management With OmniPITRAdvanced WAL File Management With OmniPITR
Advanced WAL File Management With OmniPITRRobert Treat
 
Scaling with Postgres (Highload++ 2010)
Scaling with Postgres (Highload++ 2010)Scaling with Postgres (Highload++ 2010)
Scaling with Postgres (Highload++ 2010)Robert Treat
 
Intro to Postgres 9 Tutorial
Intro to Postgres 9 TutorialIntro to Postgres 9 Tutorial
Intro to Postgres 9 TutorialRobert Treat
 
Database Scalability Patterns
Database Scalability PatternsDatabase Scalability Patterns
Database Scalability PatternsRobert Treat
 
A Guide To PostgreSQL 9.0
A Guide To PostgreSQL 9.0A Guide To PostgreSQL 9.0
A Guide To PostgreSQL 9.0Robert Treat
 
Scaling With Postgres
Scaling With PostgresScaling With Postgres
Scaling With PostgresRobert Treat
 

More from Robert Treat (20)

Advanced Int->Bigint Conversions
Advanced Int->Bigint ConversionsAdvanced Int->Bigint Conversions
Advanced Int->Bigint Conversions
 
Explaining Explain
Explaining ExplainExplaining Explain
Explaining Explain
 
Managing Chaos In Production: Testing vs Monitoring
Managing Chaos In Production: Testing vs MonitoringManaging Chaos In Production: Testing vs Monitoring
Managing Chaos In Production: Testing vs Monitoring
 
Managing Databases In A DevOps Environment 2016
Managing Databases In A DevOps Environment 2016Managing Databases In A DevOps Environment 2016
Managing Databases In A DevOps Environment 2016
 
Less Alarming Alerts - SRECon 2016
Less Alarming Alerts - SRECon 2016 Less Alarming Alerts - SRECon 2016
Less Alarming Alerts - SRECon 2016
 
What Ops Can Learn From Design
What Ops Can Learn From DesignWhat Ops Can Learn From Design
What Ops Can Learn From Design
 
Postgres 9.4 First Look
Postgres 9.4 First LookPostgres 9.4 First Look
Postgres 9.4 First Look
 
Less Alarming Alerts!
Less Alarming Alerts!Less Alarming Alerts!
Less Alarming Alerts!
 
Past, Present, and Pachyderm - All Things Open - 2013
Past, Present, and Pachyderm - All Things Open - 2013Past, Present, and Pachyderm - All Things Open - 2013
Past, Present, and Pachyderm - All Things Open - 2013
 
Big Bad "Upgraded" Postgres
Big Bad "Upgraded" PostgresBig Bad "Upgraded" Postgres
Big Bad "Upgraded" Postgres
 
Managing Databases In A DevOps Environment
Managing Databases In A DevOps EnvironmentManaging Databases In A DevOps Environment
Managing Databases In A DevOps Environment
 
The Essential PostgreSQL.conf
The Essential PostgreSQL.confThe Essential PostgreSQL.conf
The Essential PostgreSQL.conf
 
Pro Postgres 9
Pro Postgres 9Pro Postgres 9
Pro Postgres 9
 
Advanced WAL File Management With OmniPITR
Advanced WAL File Management With OmniPITRAdvanced WAL File Management With OmniPITR
Advanced WAL File Management With OmniPITR
 
Scaling with Postgres (Highload++ 2010)
Scaling with Postgres (Highload++ 2010)Scaling with Postgres (Highload++ 2010)
Scaling with Postgres (Highload++ 2010)
 
Intro to Postgres 9 Tutorial
Intro to Postgres 9 TutorialIntro to Postgres 9 Tutorial
Intro to Postgres 9 Tutorial
 
Check Please!
Check Please!Check Please!
Check Please!
 
Database Scalability Patterns
Database Scalability PatternsDatabase Scalability Patterns
Database Scalability Patterns
 
A Guide To PostgreSQL 9.0
A Guide To PostgreSQL 9.0A Guide To PostgreSQL 9.0
A Guide To PostgreSQL 9.0
 
Scaling With Postgres
Scaling With PostgresScaling With Postgres
Scaling With Postgres
 

Recently uploaded

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking MenDelhi Call girls
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking MenDelhi Call girls
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Allon Mureinik
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphNeo4j
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure servicePooja Nehwal
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 3652toLead Limited
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreternaman860154
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationSafe Software
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonetsnaman860154
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationRidwan Fadjar
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxMalak Abu Hammad
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Alan Dix
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):comworks
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxOnBoard
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxnull - The Open Security Community
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...HostedbyConfluent
 

Recently uploaded (20)

08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men08448380779 Call Girls In Friends Colony Women Seeking Men
08448380779 Call Girls In Friends Colony Women Seeking Men
 
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
08448380779 Call Girls In Diplomatic Enclave Women Seeking Men
 
Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)Injustice - Developers Among Us (SciFiDevCon 2024)
Injustice - Developers Among Us (SciFiDevCon 2024)
 
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge GraphSIEMENS: RAPUNZEL – A Tale About Knowledge Graph
SIEMENS: RAPUNZEL – A Tale About Knowledge Graph
 
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure serviceWhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
WhatsApp 9892124323 ✓Call Girls In Kalyan ( Mumbai ) secure service
 
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
Tech-Forward - Achieving Business Readiness For Copilot in Microsoft 365
 
Presentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreterPresentation on how to chat with PDF using ChatGPT code interpreter
Presentation on how to chat with PDF using ChatGPT code interpreter
 
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry InnovationBeyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
Beyond Boundaries: Leveraging No-Code Solutions for Industry Innovation
 
The transition to renewables in India.pdf
The transition to renewables in India.pdfThe transition to renewables in India.pdf
The transition to renewables in India.pdf
 
How to convert PDF to text with Nanonets
How to convert PDF to text with NanonetsHow to convert PDF to text with Nanonets
How to convert PDF to text with Nanonets
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
My Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 PresentationMy Hashitalk Indonesia April 2024 Presentation
My Hashitalk Indonesia April 2024 Presentation
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
The Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptxThe Codex of Business Writing Software for Real-World Solutions 2.pptx
The Codex of Business Writing Software for Real-World Solutions 2.pptx
 
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...Swan(sea) Song – personal research during my six years at Swansea ... and bey...
Swan(sea) Song – personal research during my six years at Swansea ... and bey...
 
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
Neo4j - How KGs are shaping the future of Generative AI at AWS Summit London ...
 
CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):CloudStudio User manual (basic edition):
CloudStudio User manual (basic edition):
 
Maximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptxMaximizing Board Effectiveness 2024 Webinar.pptx
Maximizing Board Effectiveness 2024 Webinar.pptx
 
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptxMaking_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
Making_way_through_DLL_hollowing_inspite_of_CFG_by_Debjeet Banerjee.pptx
 
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
Transforming Data Streams with Kafka Connect: An Introduction to Single Messa...
 

the-lost-art-of-plpgsql

  • 1. The Lost Art of PLPGSQL pgcon 2019 Robert Treat (@robtreat2) the lost art of plpgsql NOTE: There Will Be Code!
  • 2. Robert Treat (@robtreat2) the lost art of plpgsql whoami? occasional dev | ops | dba currently lead u.s. operations at credativ open source services and support we build and run world class applications and infrastructure to empower our clients
  • 3. Robert Treat (@robtreat2) the lost art of plpgsql whoami? @robtreat2 robert.treat@credativ.us https://www.linkedin.com/company/credativ-llc
  • 4. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of postgres functions how many of you have used a postgres function?
  • 5. Robert Treat (@robtreat2) the lost art of plpgsql why plpgsql server side / round trips stable api simplify portability*
  • 6. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of postgres functions four types of postgres functions: • internal functions • query language functions (functions written in SQL) • procedural language functions (functions written in PL/pgSQL) • C-language functions they all work similarly and have overlapping bits, today we only care about procedural language functions specifically plpgsql ones
  • 7. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of postgres functions https://www.postgresql.org/docs/current/sql-createfunction.html
  • 8. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of plpgsql Chapter 42 “PL/pgSQL - SQL Procedural Language” note: you can write stored procedures in pure SQL, but this is not that
  • 9. Robert Treat (@robtreat2) the lost art of plpgsql a very brief overview of plpgsql originally added in 6.4 (pl/tcl added in 6.3) installed by default in 9.0 minimal language for creating triggers and user defined functions add basic control structures to SQL “trusted” language for server side computation
  • 10. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of plpgsql get diagnostics when doing dynamic query execution “get diagnostics” can be used for finding row count and call stack information additionally, /FOUND/ variable can be used to determine query outcomes 42.5.5 Obtaining the Result Status
  • 11. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 12. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of plpgsql CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 13. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of plpgsql CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 14. Robert Treat (@robtreat2) the lost art of plpgsql a brief overview of plpgsql CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 15. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 16. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 17. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 18. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 19. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 20. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 21. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 22. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 23. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql function CREATE OR REPLACE FUNCTION inventory_in_stock(p_inventory_id integer) RETURNS boolean LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RETURN TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RETURN FALSE; ELSE RETURN TRUE; END IF; END $$;
  • 24. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure postgres@pagila=# select inventory_in_stock(42); inventory_in_stock -------------------- t (1 row)
  • 25. Robert Treat (@robtreat2) the lost art of plpgsql how to plpgsql user defined functions do scripts stored procedures
  • 26. postgres@pagila=# DO $$ DECLARE v_row record; BEGIN FOR v_row IN SELECT film_id, title, rating FROM film WHERE film_id < 10 LOOP IF v_row.rating ='G'::mpaa_rating THEN RAISE NOTICE '% is safe for tv',v_row.title; END IF; END LOOP; END$$ ; NOTICE: ACE GOLDFINGER is safe for tv NOTICE: AFFAIR PREJUDICE is safe for tv NOTICE: AFRICAN EGG is safe for tv DO Robert Treat (@robtreat2) the lost art of plpgsql at least one slide on DO scripts https://www.postgresql.org/docs/current/sql-do.html
  • 27. postgres@pagila=# DO$$ BEGIN vacuum actor; vacuum film; END $$; ERROR: VACUUM cannot be executed from a function CONTEXT: SQL statement "vacuum actor" PL/pgSQL function inline_code_block line 1 at SQL statement Robert Treat (@robtreat2) the lost art of plpgsql at least one slide on DO scripts
  • 28. Robert Treat (@robtreat2) the lost art of plpgsql what even is a procedure? enter stored procedures
  • 29. Robert Treat (@robtreat2) the lost art of plpgsql what even is a procedure? but first a history
  • 30. Robert Treat (@robtreat2) the lost art of plpgsql what even is a procedure? “other databases say” functions: user defined code that executes some set of commands and returns a result stored procedures: user defined code that executes some set of commands returning no result
  • 31. Robert Treat (@robtreat2) the lost art of plpgsql what even is a procedure? create function smored_promedure() returns void as $$ begin return; end $$ language plpgsql; postgres@pagila=# select smored_promedure(); smored_promedure ------------------ (1 row)
  • 32. Robert Treat (@robtreat2) the lost art of plpgsql what even is a procedure? “in postgres, functions are equivalent to stored procedures, and can be used interchangeably”
  • 33. Robert Treat (@robtreat2) the lost art of plpgsql stored procedures, turned up to 11 sql standard based allow transaction control
  • 34. Robert Treat (@robtreat2) the lost art of plpgsql stored procedures, turned up to 11 postgres@pagila=# h create procedure Command: CREATE PROCEDURE Description: define a new procedure Syntax: CREATE [ OR REPLACE ] PROCEDURE name ( [ [ argmode ] [ argname ] argtype [ { DEFAULT | = } default_expr ] [, ...] ] ) { LANGUAGE lang_name | TRANSFORM { FOR TYPE type_name } [, ... ] | [ EXTERNAL ] SECURITY INVOKER | [ EXTERNAL ] SECURITY DEFINER | SET configuration_parameter { TO value | = value | FROM CURRENT } | AS 'definition' | AS 'obj_file', 'link_symbol' } ...
  • 35. Robert Treat (@robtreat2) the lost art of plpgsql stored procedures, turned up to 11 postgres@pagila=# h call Command: CALL Description: invoke a procedure Syntax: CALL name ( [ argument ] [, ...] )
  • 36. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure CREATE OR REPLACE PROCEDURE inventory_in_sproc(p_inventory_id integer) LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RAISE NOTICE ‘TRUE’; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RAISE NOTICE ‘FALSE’; ELSE RAISE NOTICE ‘TRUE’; END IF; END $$;
  • 37. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure CREATE OR REPLACE PROCEDURE inventory_in_sproc(p_inventory_id integer) LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN RAISE NOTICE ‘TRUE’; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN RAISE NOTICE ‘FALSE’; ELSE RAISE NOTICE ‘TRUE’; END IF; END $$;
  • 38. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure postgres@pagila=# call inventory_in_sproc(42); NOTICE: TRUE CALL postgres@pagila=# select inventory_in_stock(42); inventory_in_stock -------------------- t (1 row)
  • 39. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure CREATE OR REPLACE PROCEDURE inventory_in_shock( IN p_inventory_id integer, INOUT p_instock boolean DEFAULT false ) LANGUAGE plpgsql AS $$ DECLARE v_rentals INTEGER; v_out INTEGER; BEGIN -- AN ITEM IS IN-STOCK IF THERE ARE EITHER NO ROWS IN THE rental TABLE -- FOR THE ITEM OR ALL ROWS HAVE return_date POPULATED SELECT count(*) INTO v_rentals FROM rental WHERE inventory_id = p_inventory_id; IF v_rentals = 0 THEN p_instock := TRUE; END IF; SELECT COUNT(rental_id) INTO v_out FROM inventory LEFT JOIN rental USING(inventory_id) WHERE inventory.inventory_id = p_inventory_id AND rental.return_date IS NULL; IF v_out > 0 THEN p_instock := FALSE; ELSE p_instock := TRUE; END IF; END $$;
  • 40. Robert Treat (@robtreat2) the lost art of plpgsql an example plpgsql procedure postgres@pagila=# call inventory_in_sproc(42); NOTICE: TRUE CALL postgres@pagila=# select inventory_in_stock(42); inventory_in_stock -------------------- t (1 row) postgres@pagila=# call inventory_in_shock(42); p_instock ----------- t (1 row)
  • 41. Robert Treat (@robtreat2) the lost art of plpgsql plpgsql procedure transaction control postgres@pagila=# create table xx (xx int); CREATE TABLE postgres@pagila=# create or replace procedure xx() as $$ begin insert into xx select 1; rollback; insert into xx select 2; commit; insert into xx select 3; rollback; end $$ language plpgsql; CREATE PROCEDURE postgres@pagila=# call xx(); CALL postgres@pagila=# select * from xx; xx ---- 2 (1 row)
  • 42. Robert Treat (@robtreat2) the lost art of plpgsql plpgsql procedure transaction control postgres@pagila=# create or replace procedure merry_maids() as $$ begin vacuum actor; end $$ language plpgsql; CREATE PROCEDURE postgres@pagila=# call merry_maids(); ERROR: VACUUM cannot be executed from a function CONTEXT: SQL statement "vacuum actor” * fyi, you can do this with analyze
  • 43. Robert Treat (@robtreat2) the lost art of plpgsql more to do! certain ddl - create index concurrently vacuum support multiple result-sets
  • 44. #thankyou Robert Treat (@robtreat2) the lost art of plpgsql