I am running into a wierd issue with the execution (or non-execution) of certain queries within postgresql RULES. This is a companion (but different) question to Postgresql subquery execution within ON UPDATE rule (maybe bug in postgresql?) – but as it turns out, there is a related issue of certain queries not executing at all within postgresql RULEs, versus just the issue of query execution order.
Consider the following code block:
DROP TABLE foo_table;
DROP TABLE bar_table;
--------------
CREATE TABLE foo_table (c1 text, c2 int);
CREATE TABLE bar_table (c1 text, c2 int);
--------------
CREATE OR REPLACE FUNCTION debug_immutable(anyelement) RETURNS integer AS $$
pg_raise('notice', 'debug(): ' . json_encode($args[0]));
return rand(1, 10000);
$$ LANGUAGE PLPHP IMMUTABLE;
CREATE OR REPLACE FUNCTION debug_volatile(anyelement) RETURNS integer AS $$
pg_raise('notice', 'debug(): ' . json_encode($args[0]));
return rand(1, 10000);
$$ LANGUAGE PLPHP VOLATILE;
-------------
CREATE OR REPLACE RULE foo_update_rule AS ON UPDATE TO foo_table DO INSTEAD
(
SELECT debug_immutable('debug_immutable call 1'::text); -- Query #1
SELECT debug_volatile('debug_volatile call 1'::text); -- Query #2
INSERT INTO foo_table (c1, c2) values ('foo', 123456); -- Query #3
INSERT INTO bar_table (c1, c2) values ('bar', 123456); -- Query #4
SELECT debug_immutable('debug_immutable call 2'::text); -- Query #5
SELECT debug_volatile('debug_volatile call 2'::text); -- Query #6
);
-----------------------------------------------
UPDATE foo_table SET c1 = NULL where c1 = 'aaa';
SELECT * FROM foo_table;
SELECT * FROM bar_table;
The output only displays the following:
NOTICE: plphp: debug(): "debug_immutable call 1"
NOTICE: plphp: debug(): "debug_immutable call 2"
Total query runtime: 46 ms.
0 rows retrieved.
And both foo_table and bar_table shows to be empty after the code block is executed:
# select * from foo_table;
c1 | c2
----+----
(0 rows)
# select * from bar_table;
c1 | c2
----+----
(0 rows)
The output implies that only queries #1 and #5 are executed, and queries #2, 3, 4 and 6 are never executed. Why is this? How can the above code block be changed so that queries #2, 3, 4 and 6 are executed?
The immutable functions are evaluated at the planning stage, before the query is executed. The volatile ones are evaluated on a per need basis. You’ve zero rows returned, so they’re never called.