PL/pgSQL perform vs execute
I recently had a case where I needed to set specific constraints to DEFERRED and found something interesting.
- EXECUTE 'SET CONSTRAINTS fk_a DEFERRED';
- PERFORM 'SET CONSTRAINTS fk_a DEFERRED';
Both EXECUTE
and PERFORM
executed the statements without error but only EXECUTE persisted the action for the rest of the code.
Somehow, it looks like PERFORM runs in it's own transaction "bubble"
.
In my case I had two tables a and b and a FK (the real stuation is much more complex). There was a need to insert the data out of the parent/child order and for that we needed the constraint DEFERRED
.
Using the PERFORM
we had a foreign key violation, with EXECUTE
we didn't.
Further next line in docs you quote:
This executes query and discards the result. Write the query the same way you would write an SQL SELECT command, but replace the initial keyword SELECT with PERFORM.
Emphasis mine
execute
in its turn executes dynamic query (same docs above)
PERFORM
is plpgsql command used for calls of void functions. PLpgSQL is careful about useless SELECT
statements - the SELECT
without INTO
clause is not allowed. But sometimes you need to call a function and you don't need to store result (or functions has no result). The function in SQL
is called with SELECT
statement. But it is not possible in PLpgSQL - so the command PERFORM
was introduced.
CREATE OR REPLACE FUNCTION foo()
RETURNS void AS $$
BEGIN
RAISE NOTICE 'Hello from void function';
END;
$$ LANGUAGE plpgsql;
-- direct call from SQL
SELECT foo();
-- in PLpgSQL
DO $$
BEGIN
SELECT foo(); -- is not allowed
PERFORM foo(); -- is ok
END;
$$;
The PERFORM
statements execute a parameter and forgot result.
Your example perform 'create table foo as (select 1)';
is same like SELECT 'create table foo as (select 1)'
. It returns a string "create table foo as (select 1)" and this string is discarded.
The EXECUTE
statement evaluate a expression to get string. In next step this string is executed.
So EXECUTE 'create table ' || some_var || '(a int)';
has two steps
- evaluate expression
'create table ' || some_var || '(a int)'
- if
some_var
is mytab for example, then execute a commandcreate table mytab(a int)
The PERFORM
statement is used for function calls, when functions are not used in assignment statement. The EXECUTE
is used for evaluation of dynamic SQL - when a form of SQL command is known in runtime.