【发布时间】:2011-07-17 03:43:38
【问题描述】:
在 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"
从输出中可以看出,问题在于子查询(又名“内部”)是在 foo_update_rule 中的 2 个 SELECT 查询中的引用(又名“外部”)查询之后执行的。结果,在评估外部查询时尚未定义 _value 列(在子查询中定义),导致 debug('update_outer_2 -> '::text || _value::text) 静默失败(并且不打印通知)。
奇怪的是,ON INSERT 规则中的相同 SQL 可以正常工作(打印出两个 'outer_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"
【问题讨论】:
-
使用说明查看语句的执行顺序。
-
对于“mu 太短”,通知来自代码块顶部定义的 debug() 函数。 'update2_outer_2' 在代码块中被调用,开头为: ROW(FALSE,FALSE) IN ( SELECT... 而且,是的,'debug('update_inner'::text)' 在 2 个不同的地方被调用,但这就是目的.
-
对于“丹尼斯”,我无法在规则中使用 EXPLAIN,因为 pgsql 会丢弃这些行。独立 SELECT 上的 EXPLAIN 表明它以正确的顺序执行。但最初的问题是 pgsql 以错误的顺序执行规则中的查询,而独立 SELECT 中的执行顺序很好。
标签: postgresql subquery rules