Skip to content

Commit 6edccac

Browse files
committed
Reject cases where a query in WITH rewrites to just NOTIFY.
Since the executor can't cope with a utility statement appearing as a node of a plan tree, we can't support cases where a rewrite rule inserts a NOTIFY into an INSERT/UPDATE/DELETE command appearing in a WITH clause of a larger query. (One can imagine ways around that, but it'd be a new feature not a bug fix, and so far there's been no demand for it.) RewriteQuery checked for this, but it missed the case where the DML command rewrites to *only* a NOTIFY. That'd lead to crashes later on in planning. Add the missed check, and improve the level of testing of this area. Per bug #17094 from Yaoguang Chen. It's been busted since WITH was introduced, so back-patch to all supported branches. Discussion: https://postgr.es/m/17094-bf15dff55eaf2e28@postgresql.org
1 parent 7dd2379 commit 6edccac

File tree

3 files changed

+63
-3
lines changed

3 files changed

+63
-3
lines changed

src/backend/rewrite/rewriteHandler.c

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3516,15 +3516,29 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
35163516

35173517
/*
35183518
* Currently we can only handle unconditional, single-statement DO
3519-
* INSTEAD rules correctly; we have to get exactly one Query out of
3520-
* the rewrite operation to stuff back into the CTE node.
3519+
* INSTEAD rules correctly; we have to get exactly one non-utility
3520+
* Query out of the rewrite operation to stuff back into the CTE node.
35213521
*/
35223522
if (list_length(newstuff) == 1)
35233523
{
3524-
/* Push the single Query back into the CTE node */
3524+
/* Must check it's not a utility command */
35253525
ctequery = linitial_node(Query, newstuff);
3526+
if (!(ctequery->commandType == CMD_SELECT ||
3527+
ctequery->commandType == CMD_UPDATE ||
3528+
ctequery->commandType == CMD_INSERT ||
3529+
ctequery->commandType == CMD_DELETE))
3530+
{
3531+
/*
3532+
* Currently it could only be NOTIFY; this error message will
3533+
* need work if we ever allow other utility commands in rules.
3534+
*/
3535+
ereport(ERROR,
3536+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3537+
errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3538+
}
35263539
/* WITH queries should never be canSetTag */
35273540
Assert(!ctequery->canSetTag);
3541+
/* Push the single Query back into the CTE node */
35283542
cte->ctequery = (Node *) ctequery;
35293543
}
35303544
else if (newstuff == NIL)

src/test/regress/expected/with.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2315,6 +2315,31 @@ WITH t AS (
23152315
)
23162316
VALUES(FALSE);
23172317
ERROR: conditional DO INSTEAD rules are not supported for data-modifying statements in WITH
2318+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
2319+
WITH t AS (
2320+
INSERT INTO y VALUES(0)
2321+
)
2322+
VALUES(FALSE);
2323+
ERROR: DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH
2324+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
2325+
WITH t AS (
2326+
INSERT INTO y VALUES(0)
2327+
)
2328+
VALUES(FALSE);
2329+
ERROR: DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH
2330+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
2331+
WITH t AS (
2332+
INSERT INTO y VALUES(0)
2333+
)
2334+
VALUES(FALSE);
2335+
ERROR: DO ALSO rules are not supported for data-modifying statements in WITH
2336+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
2337+
DO INSTEAD (NOTIFY foo; NOTIFY bar);
2338+
WITH t AS (
2339+
INSERT INTO y VALUES(0)
2340+
)
2341+
VALUES(FALSE);
2342+
ERROR: multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH
23182343
DROP RULE y_rule ON y;
23192344
-- check that parser lookahead for WITH doesn't cause any odd behavior
23202345
create table foo (with baz); -- fail, WITH is a reserved word

src/test/regress/sql/with.sql

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1066,6 +1066,27 @@ WITH t AS (
10661066
INSERT INTO y VALUES(0)
10671067
)
10681068
VALUES(FALSE);
1069+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
1070+
WITH t AS (
1071+
INSERT INTO y VALUES(0)
1072+
)
1073+
VALUES(FALSE);
1074+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
1075+
WITH t AS (
1076+
INSERT INTO y VALUES(0)
1077+
)
1078+
VALUES(FALSE);
1079+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
1080+
WITH t AS (
1081+
INSERT INTO y VALUES(0)
1082+
)
1083+
VALUES(FALSE);
1084+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
1085+
DO INSTEAD (NOTIFY foo; NOTIFY bar);
1086+
WITH t AS (
1087+
INSERT INTO y VALUES(0)
1088+
)
1089+
VALUES(FALSE);
10691090
DROP RULE y_rule ON y;
10701091

10711092
-- check that parser lookahead for WITH doesn't cause any odd behavior

0 commit comments

Comments
 (0)