DEV Community

Super Kai (Kazuya Ito)
Super Kai (Kazuya Ito)

Posted on • Edited on

A PL/pgSQL procedure in PostgreSQL

Buy Me a Coffee

A PL/pgSQL procedure:

  • can have zero or more queries with BEGIN ... END clause getting zero or more values with zero or more parameters from the caller. *Be careful, BEGIN ... END clause is not transaction.

  • can have IN, OUT, INOUT and VARIADIC parameters. *My answer explains a VARIADIC parameter.

  • can have DECLARE clause. *My post explains it.

  • can have type-only-parameters. *My post explains it.

  • can have the aliases of parameters e.g. $1, $2, etc. *My post explains it.

  • can have SELECT INTO statement.

  • cannot have RETURN NEXT and RETURN QUERY statement.

  • can have PERFORM statement.

  • can have EXECUTE statement. *My post explains how to use EXECUTE statement in a function.

  • can have RETURN statement without a value which is RETURN;.

  • cannot have RETURN statement with a value e.g. RETURN 2; otherwise there is error.

  • cannot have SELECT statement without INTO or INSERT, UPDATE or DELETE statement with RETURNING clause as a non-substatement otherwise there is the error.

  • cannot have RETURNS <type> clause otherwise there is error.

  • is atomic by default running in a single transaction so if there is error, it is rollbacked automatically. *My answer explains it.

  • can control transaction with ROLLBACK and COMMIT.

  • cannot control transaction with START TRANSACTION and BEGIN otherwise there is error.

  • is similar to a MySQL procedure.

*The doc explains a PL/pgSQL procedure.
*My post explains a SQL procedure.
*My post explains a PL/pgSQL function.
*My post explains a SQL function.
*My post explains DO statement.

*You should use PL/pgSQL language because you can do much more things with it compared with SQL language.

For example, you create test table as shown below:

CREATE TABLE test (
  num INT
);
Enter fullscreen mode Exit fullscreen mode

Then, you insert the row whose num is 2 into test table as shown below:

INSERT INTO test (num) VALUES (2);
Enter fullscreen mode Exit fullscreen mode

Now, you can create my_proc() procedure which adds value to num and returns result to the caller as shown below:

CREATE PROCEDURE my_proc(IN value INT, OUT result INT)
LANGUAGE plpgsql
AS $$
BEGIN
  UPDATE test SET num = num + value;
  SELECT num INTO result FROM test;
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Or, you can change the position of LANGUAGE plpgsql as shown below:

CREATE PROCEDURE my_proc(IN value INT, OUT result INT)
AS $$
BEGIN
  UPDATE test SET num = num + value;
  SELECT num INTO result FROM test;
END;
$$
LANGUAGE plpgsql;
Enter fullscreen mode Exit fullscreen mode

*Memos:

  • An IN parameter can get a value from the caller but cannot return a value to the caller and the parameter with and without IN is the same so my_proc(IN value INT) and my_proc(value INT) are the same:

  • An OUT parameter can return a value to the caller but cannot get a value from the caller

  • An OUT parameter cannot have VOID type in a SQL function otherwise there is error while an OUT parameter cannot have VOID type in a PL/pgSQL function:

  • You must set AS <delimiter> clause and BEGIN ... END clause to a PL/pgSQL procedure otherwise there is error.

  • You can also use other delimiter '' instead of $$ to create the body of a PL/pgSQL procedure. *My answer explains it.

  • You can use SELECT INTO statement to put a retrieved value into a variable.

  • If a return value type doesn't match OUT or INOUT parameters, there is error.

  • You must set LANGUAGE plpgsql to create a PL/pgSQL procedure otherwise there is the error.

  • You can set LANGUAGE plpgsql in 2 positions as shown above.

Then, you can call my_proc(3, 10) with CALL statement, then 5 is returned and 3 is added to num as shown below. *my_proc() without the 2nd argument or the 2nd argument whose type is not INT get the error:

postgres=# CALL my_proc(3, 10);
 result
--------
      5
(1 row)

postgres=# SELECT num FROM test;
 num
-----
   5
(1 row)
Enter fullscreen mode Exit fullscreen mode

And, you can use the INOUT parameter which is the combination of IN and OUT parameters to get a value from the caller and to return a value to the caller as shown below:

CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE plpgsql
AS $$
BEGIN
  UPDATE test SET num = num + value;
  SELECT num INTO value FROM test;
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_proc(3) returns 5 and 3 is added to num as shown below:

postgres=# CALL my_proc(3);
 value
-------
     5
(1 row)

postgres=# SELECT num FROM test;
 num
-----
   5
(1 row)
Enter fullscreen mode Exit fullscreen mode

And, you can use RETURN statement without a value which is RETURN; to exit my_proc() as shown below:

CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE plpgsql
AS $$
BEGIN
  RETURN; -- Here
  UPDATE test SET num = num + value;
  SELECT num INTO value FROM test;
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_proc(3) returns 3 and nothing is added to num as shown below. *The INOUT parameter value is not changed from 3 to 5:

postgres=# CALL my_proc(3);
 value
-------
     3
(1 row)

postgres=# SELECT num FROM test;
 num
-----
   2
(1 row)
Enter fullscreen mode Exit fullscreen mode

And, you can use PERFORM statement as shown below:

CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE plpgsql
AS $$
BEGIN
  UPDATE test SET num = num + value;
  PERFORM num FROM test; -- Here
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_proc(3) returns 3 and 2 is added to num as shown below. *The INOUT parameter value is not changed from 3 to 5:

postgres=# CALL my_proc(3);
 value
-------
     3
(1 row)

postgres=# SELECT num FROM test;
 num
-----
   5
(1 row)
Enter fullscreen mode Exit fullscreen mode

And, you can control transaction with ROLLBACK and COMMIT as shown below. *Using START TRANSACTION and BEGIN gets error:

CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE plpgsql
AS $$
BEGIN
  UPDATE test SET num = num + value;
  ROLLBACK;
  SELECT num INTO value FROM test;
  COMMIT;
END;
$$;
Enter fullscreen mode Exit fullscreen mode

Then, calling my_proc(3) returns 2 and 3 is not added to num as shown below:

postgres=# CALL my_proc(3);
 value
-------
     2
(1 row)

postgres=# SELECT num FROM test;
 num
-----
   2
(1 row)
Enter fullscreen mode Exit fullscreen mode

Heroku

This site is built on Heroku

Join the ranks of developers at Salesforce, Airbase, DEV, and more who deploy their mission critical applications on Heroku. Sign up today and launch your first app!

Get Started

Top comments (0)

Billboard image

The Next Generation Developer Platform

Coherence is the first Platform-as-a-Service you can control. Unlike "black-box" platforms that are opinionated about the infra you can deploy, Coherence is powered by CNC, the open-source IaC framework, which offers limitless customization.

Learn more

👋 Kindness is contagious

Please leave a ❤️ or a friendly comment on this post if you found it helpful!

Okay