A SQL procedure:
can have zero or more queries with or without
ASclause or BEGIN ATOMIC ... END clause getting zero or more values with zero or more parameters from the caller. *BEGIN ATOMIC ENDclause works only forLANGUAGE SQLaccording to the doc.can have
IN,OUT,INOUTandVARIADICparameters. *My answer explains aVARIADICparameter.cannot have DECLARE clause otherwise there is error.
cannot have RETURN NEXT and RETURN QUERY statement.
can have type-only parameters. *My post explains it.
can have the aliases of parameters e.g.
$1,$2, etc. *My post explains it.cannot have SELECT INTO statement otherwise there is error.
cannot have PERFORM statement otherwise there is error.
cannot have EXECUTE statement otherwise there is error. *My post explains how to use
EXECUTEstatement in a function.cannot have
RETURNS <type>clause otherwise there is error.can return a value with the last statement to the caller with SELECT statement or INSERT, UPDATE or DELETE statement with RETURNING clause using
ASclause orBEGIN ATOMIC ... ENDclause.can return a value with the last statement to the caller with RETURN statement not using
ASclause or usingBEGIN ATOMIC ... ENDclause.cannot have
BEGIN ... ENDclause which can have multiple queries otherwise there is error while a PL/pgSQL procedure can have it. *Be careful,BEGIN ... ENDclause is not transaction.is atomic by default running in a single transaction so if there is error, it is rollbacked automatically. *My answer explains it.
cannot control transaction with
START TRANSACTION,BEGIN,ROLLBACK,COMMIT, etc otherwise there is the error.
*The doc explains a SOL procedure.
*My post explains a PL/pgSQL procedure.
*My post explains a SQL function.
*My post explains a PL/pgSQL 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
);
Then, you insert the row whose num is 2 into test table as shown below:
INSERT INTO test (num) VALUES (2);
Now, you can create my_proc() procedure which adds value to num and returns value to the caller as shown below:
CREATE PROCEDURE my_proc(IN value INT, OUT result INT)
LANGUAGE SQL
AS $$
UPDATE test SET num = num + value;
SELECT num FROM test;
$$;
Or, you can change the position of LANGUAGE SQL as shown below:
CREATE PROCEDURE my_proc(IN value INT, OUT result INT)
AS $$
UPDATE test SET num = num + value;
SELECT num FROM test;
$$
LANGUAGE SQL; -- Here
Or, you can use UPDATE statement with RETURNING num instead of SELECT num FROM test; as shown below:
CREATE PROCEDURE my_proc(IN value INT, OUT result INT)
LANGUAGE SQL
AS $$
UPDATE test SET num = num + value RETURNING num;
-- SELECT num FROM test; -- ↑ Here ↑
$$;
*Memos:
An
INparameter can get a value from the caller but cannot return a value to the caller and the parameter with and withoutINis the same somy_proc(IN value INT)andmy_proc(value INT)are the same:An
OUTparameter can return a value to the caller but cannot get a value from the caller.An
OUTparameter can haveVOIDtype in a SQL function while an OUT parameter cannot in a PL/pgSQL function.The default value of an
OUTparameter isNULL.You must set
ASclause with delimiter to a SQL procedure otherwise there is error.You can also use other delimiter ' instead of $$ to create the body of a SQL procedure. *My answer explains it.
Using
BEGIN ... ENDstatement in a SQL procedure gets error while a PL/pgSQL procedure doesn't get error:In a SQL procedure, the result of the last statement is the return value whose type must match
OUTorINOUTparameters so in the example above, the result ofSELECT num FROM test;is the return value whose type actually matchesOUT result INTbecausenumvalue is alsoINTso if the type doesn't matchOUT result INT, there is error.You must set
LANGUAGE SQLto create a SQL procedure otherwise there is the error.You can set
LANGUAGE SQLin 2 positions as shown above.
Then, you can call my_proc(3) 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)
And, you can use VOID type to return nothing as shown below. *Type conversion is needed to VOID type and my answer explains how to convert type:
CREATE PROCEDURE my_proc(IN value INT, OUT result VOID)
LANGUAGE SQL -- ↑ Here
AS $$
UPDATE test SET num = num + value RETURNING 'world'::VOID;
-- SELECT num FROM test; -- ↑ Here ↑
$$;
Then, calling my_proc(3, 'hello'::VOID) returns nothing which is VOID type and 3 is added to num as shown below. *Type conversion is needed to VOID type and you can use pg_typeof() to check the type 'Hello'::VOID which is VOID:
postgres=# CALL my_proc(3, 'hello'::VOID);
result
--------
(1 row)
postgres=# SELECT num FROM test;
num
-----
5
(1 row)
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 SQL
AS $$
UPDATE test SET num = num + value;
SELECT num FROM test;
$$;
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)
And, you can return a value with RETURN statement not using AS clause as shown below. *Using RETURN statement with AS clause gets the error:
CREATE PROCEDURE my_proc(INOUT value INT)
BEGIN ATOMIC
LANGUAGE SQL
RETURN 2 + value;
END;
Or, you can unset LANGUAGE SQL when returning a value with RETURN statement not using AS clause as shown below but it is still a SQL procedure:
CREATE PROCEDURE my_proc(INOUT value INT)
-- LANGUAGE SQL
RETURN 2 + value;
Then, calling my_proc(3) adds returns 5 as shown below:
postgres=# CALL my_proc(3);
value
-------
5
(1 row)
And, you can use BEGIN ATOMIC ... END clause as shown below. *In BEGIN ATOMIC ... END clause, you can return a value with SELECT statement, RETURNING clause or RETURN statement and you can use both BEGIN ATOMIC and BEGIN ATOMIC;:
CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE SQL
BEGIN ATOMIC
UPDATE test SET num = num + value;
SELECT num FROM test;
END;
Or:
CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE SQL
BEGIN ATOMIC -- ↓ Here
UPDATE test SET num = num + value RETURNING num;
END;
Or:
CREATE PROCEDURE my_proc(INOUT value INT)
LANGUAGE SQL
BEGIN ATOMIC
UPDATE test SET num = num + value;
RETURN (SELECT num FROM test);
END;
Or, you can unset LANGUAGE SQL when using BEGIN ATOMIC ... END clause as shown below but it is still a SQL procedure:
CREATE PROCEDURE my_proc(INOUT value INT)
-- LANGUAGE SQL
BEGIN ATOMIC
UPDATE test SET num = num + value;
SELECT num FROM test;
END;
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)
Top comments (0)