DEV Community

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

Posted on • Edited on

A PL/pgSQL function in PostgreSQL

Buy Me a Coffee

A PL/pgSQL function:

*The doc explains a PL/pgSQL function.
*My post explains a SQL function.
*My post explains a PL/pgSQL procedure.
*My post explains a SOL procedure.
*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_func() function which adds value to num and returns value to the caller as shown below:

CREATE FUNCTION my_func(value INT) RETURNS INT AS $$ BEGIN UPDATE test SET num = num + value; SELECT num INTO value FROM test; RETURN value; END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

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

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

*Memos:

  • You must set RETURNS <type> clause or OUT or INOUT parameters which I explain later otherwise there is error.

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

  • RETURNS <type> clause can have VOID type to return nothing.

  • You can also use other delimiter ' instead of $$ to create the body of a PL/pgSQL function. *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 RETURNS <type> clause or OUT or INOUT parameters, there is error.

  • If you unset RETURN statement when RETURNS <type> clause is not VOID and an OUT or INOUT parameter is not used, there is the error.

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

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

Then, you can call my_func(3) with SELECT statement, then 5 is returned and 3 is added to num as shown below:

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

And, you can use VOID type with or without RETURN; to return nothing as shown below. *Using VOID type with RETURN <some-value>; in a PL/pgSQL function gets the error while a SQL function doesn't get the error:

CREATE FUNCTION my_func(value INT) RETURNS VOID AS $$ -- ↑ Here BEGIN UPDATE test SET num = num + value; SELECT num INTO value FROM test; RETURN; -- Here END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

Or:

CREATE FUNCTION my_func(value INT) RETURNS VOID AS $$ -- ↑ Here BEGIN UPDATE test SET num = num + value; SELECT num INTO value FROM test; -- RETURN; -- Here END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

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

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

And, you can use PERFORM statement as shown below:

CREATE FUNCTION my_func(value INT) RETURNS INT AS $$ BEGIN UPDATE test SET num = num + value; PERFORM num FROM test; -- Here RETURN 10; END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

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

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

In addition, you can use IN, OUT and INOUT parameters in a PL/pgSQL function as shown below.

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

CREATE FUNCTION my_func(IN value INT) RETURNS INT AS $$ -- ↑↑ Here BEGIN UPDATE test SET num = num + value; SELECT num INTO value FROM test; RETURN value; END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

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

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

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

CREATE FUNCTION my_func(OUT value INT) RETURNS INT AS $$ -- ↑ Here BEGIN UPDATE test SET num = num + 3; SELECT num INTO value FROM test; RETURN; END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

Or:

CREATE FUNCTION my_func(OUT value INT) /* RETURNS INT */ AS $$ -- ↑ Here -- ↑ Unset ↑ BEGIN UPDATE test SET num = num + 3; SELECT num INTO value FROM test; -- RETURN; -- Unset END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

*Memos:

  • An OUT parameter and RETURNS <type> clause are the same except that an OUT parameter cannot have VOID type in a PL/pgSQL function while an OUT parameter can in a SQL function.

  • When you set an OUT parameter, you can unset RETURNS <type> clause and RETURN statement.

  • You can still set RETURNS <type> clause and RETURN statement with an OUT parameter but the types of an OUT parameter and RETURNS <type> clause must be the same otherwise there is the error and RETURN statement must be RETURN; to return nothing otherwise there is the error.

  • Passing a value to an OUT parameter gets the error.

  • Setting VOID type to an OUT parameter gets error.

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

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

An INOUT parameter is the combination of IN and OUT parameters to get a value from the caller and to return a value to the caller:

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

Or:

CREATE FUNCTION my_func(INOUT value INT) /* RETURNS INT */ AS $$ -- ↑ Here -- ↑ Unset ↑ BEGIN UPDATE test SET num = num + value; SELECT num INTO value FROM test; -- RETURN; -- Unset END; $$ LANGUAGE plpgsql; 
Enter fullscreen mode Exit fullscreen mode

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

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

Top comments (0)