Я сталкиваюсь со странным поведением (или это ошибка в postgresql?) В порядке выполнения подзапросов postgresql в правилах. Рассмотрим следующий 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;
Приведенный выше код генерирует следующий вывод:
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"
Из выходных данных видно, что проблема заключается в том, что подзапрос (он же «внутренний») выполняется ПОСЛЕ его ссылочного (он же «внешнего») запроса в пределах 2 запросов SELECT в foo_update_rule. В результате столбец _value (который определен в подзапросе) еще не определен при оценке внешнего запроса, в результате чего отладка ('update_outer_2 ->' :: text || _value :: text) завершается с ошибкой (и не распечатывать уведомление).
Странно то, что тот же SQL в правиле ON INSERT будет работать нормально (распечатка обоих уведомлений 'external_2 -> ...'). Но по какой-то причине SQL не работает в рамках правила ON UPDATE.
Как можно исправить вышеуказанный запрос, чтобы напечатать следующие 2 уведомления?
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"