I am running into a strange behavior (or is this a bug within postgresql?) within postgresql's execution order of subqueries within rules. Consider the following SQL:
BEGIN;
CREATE OR REPLACE FUNCTION debug(anyelement) RETURNS bool AS $$
pg_raise('notice', 'debug(): ' . json_encode($args[0]));
RETURN TRUE;
$$ LANGUAGE PLPHP IMMUTABLE STRICT;
CREATE TABLE foo_table (c1 text);
CREATE OR REPLACE RULE foo_update_rule AS ON UPDATE TO foo_table DO INSTEAD
(
WITH foobar_update AS
(
SELECT unnest('{a,b}'::text[]) AS _value, debug('update_inner'::text)
)
SELECT *, debug('update_outer_1'::text), debug('update_outer_2 -> '::text || _value::text) FROM foobar_update;
SELECT
( ROW(FALSE,FALSE) IN ( SELECT
debug('update2_outer_1'::text), debug('update2_outer_2 -> '::text || _value::text)
FROM ( SELECT unnest('{a,b}'::text[]) AS _value, debug('update_inner'::text) ) AS foobar_update2 ))
);
-----------------------------------------------
WITH foobar_select AS
(
SELECT unnest('{a,b}'::text[]) AS _value, debug('select_inner'::text)
)
SELECT *, debug('select_outer_1'::text), debug('select_outer_2 -> '::text || _value::text), debug('select_outer_3'::text) FROM foobar_select;
UPDATE foo_table SET c1 = NULL where c1 = 'aaa';
ROLLBACK;
The above code when executed generates the following output:
NOTICE: plphp: debug(): "select_inner"
NOTICE: plphp: debug(): "select_outer_1"
NOTICE: plphp: debug(): "select_outer_3"
NOTICE: plphp: debug(): "select_outer_2 -> a"
NOTICE: plphp: debug(): "select_outer_2 -> b"
NOTICE: plphp: debug(): "update_inner"
NOTICE: plphp: debug(): "update_outer_1"
NOTICE: plphp: debug(): "update2_outer_1"
NOTICE: plphp: debug(): "update_inner"
From the output, it shows that the problem is the subquery (aka 'inner') is executed AFTER its referencing (aka 'outer') query within the 2 SELECT queries in the foo_update_rule. As a result, the _value column (which is defined within the subquery) is not yet defined when the outer query is evaluated, causing the debug('update_outer_2 -> '::text || _value::text) to silently fail (and not print out a notice).
The wierd thing is, the same SQL within an ON INSERT rule will work fine (printing out both of the 'outer_2 -> ...' notices). But for some reason the SQL does not work within an ON UPDATE rule.
How can the above query be fixed so that the following 2 notices are printed?
NOTICE: plphp: debug(): "update_outer_2 -> a"
NOTICE: plphp: debug(): "update_outer_2 -> b"
NOTICE: plphp: debug(): "update2_outer_2 -> a"
NOTICE: plphp: debug(): "update2_outer_2 -> b"