PostgresBuild2021 is currently ongoing and as usual, I had questions after my talk I could not immediately answer. One of the best ways to learn, is to present a topic. There are for sure questions you never thought about. The topic of my talk was “An introduction to server side programming” and I wanted to give people easy examples about how to write procedures and functions in PostgreSQL. It was not about control structures like IF/THEN/ELSE/CASE/LOOP but more about the general concepts like parameters, returning values, using exceptions, or giving more information about your functions and procedures to the optimizer.

Question 1: Can I use setof with in parameters?

The example in the talk is this one:

This is a simple function returning a setof t2, that is, all the rows in the table t2 at once. Can we use setof as a in parameters as well? Let’s try:

postgres=# create table t ( a int, b text );
CREATE TABLE
postgres=# create function f ( a setof t ) returns void as $$ select 1; $$ language sql;
ERROR:  functions cannot accept set arguments

The answer is: No.

Question 2: When I commit inside a loop, does that generate a new transaction ID with each commit?

The example in the talk is this one:

It doesn’t really matter if the commit is executed in a loop or like in the example above: Do we get a new transaction ID for each commit or not? Let’s try:

postgres=# create table t ( a xid );
CREATE TABLE
postgres=# create procedure p() as 
           $$ 
           begin 
             insert into t values (pg_current_xact_id()::xid); 
             commit; 
             begin 
               insert into t values (pg_current_xact_id()::xid); 
               commit; 
             end; 
           end; 
           $$ language plpgsql;
CREATE PROCEDURE
postgres=# call p();
CALL
postgres=# select * from t;
  a  
-----
 719
 720
(2 rows)

The answer is: Yes. The same, of course, applies for loops:

postgres=# drop procedure p();
DROP PROCEDURE
postgres=# truncate t;
TRUNCATE TABLE
postgres=# create or replace procedure p() as 
           $$ 
           begin 
             for i in 1..10 
             loop 
               insert into t values (pg_current_xact_id()::xid); 
             end loop; 
           end; 
           $$ language plpgsql;
CREATE PROCEDURE
postgres=# call p();
CALL
postgres=# select * from t;
  a  
-----
 724
 724
 724
 724
 724
 724
 724
 724
 724
 724
(10 rows)

postgres=# call p();
CALL
postgres=# select * from t;
  a  
-----
 724
 724
 724
 724
 724
 724
 724
 724
 724
 724
 726
 727
 728
 729
 730
 731
 732
 733
 734
 735
(20 rows)
postgres=# create or replace procedure p() as 
           $$ 
           begin 
             for i in 1..10 
             loop 
               insert into t values (pg_current_xact_id()::xid); 
               commit;
             end loop; 
           end; 
           $$ language plpgsql;
CREATE PROCEDURE

The answer, again is: Yes.

More to come as soon as I have the whole list of all the questions.