Skip to content

Commit 158594f

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 7e03e3f commit 158594f

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
@@ -3436,15 +3436,29 @@ RewriteQuery(Query *parsetree, List *rewrite_events)
34363436

34373437
/*
34383438
* Currently we can only handle unconditional, single-statement DO
3439-
* INSTEAD rules correctly; we have to get exactly one Query out of
3440-
* the rewrite operation to stuff back into the CTE node.
3439+
* INSTEAD rules correctly; we have to get exactly one non-utility
3440+
* Query out of the rewrite operation to stuff back into the CTE node.
34413441
*/
34423442
if (list_length(newstuff) == 1)
34433443
{
3444-
/* Push the single Query back into the CTE node */
3444+
/* Must check it's not a utility command */
34453445
ctequery = linitial_node(Query, newstuff);
3446+
if (!(ctequery->commandType == CMD_SELECT ||
3447+
ctequery->commandType == CMD_UPDATE ||
3448+
ctequery->commandType == CMD_INSERT ||
3449+
ctequery->commandType == CMD_DELETE))
3450+
{
3451+
/*
3452+
* Currently it could only be NOTIFY; this error message will
3453+
* need work if we ever allow other utility commands in rules.
3454+
*/
3455+
ereport(ERROR,
3456+
(errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
3457+
errmsg("DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH")));
3458+
}
34463459
/* WITH queries should never be canSetTag */
34473460
Assert(!ctequery->canSetTag);
3461+
/* Push the single Query back into the CTE node */
34483462
cte->ctequery = (Node *) ctequery;
34493463
}
34503464
else if (newstuff == NIL)

src/test/regress/expected/with.out

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2256,6 +2256,31 @@ WITH t AS (
22562256
)
22572257
VALUES(FALSE);
22582258
ERROR: conditional DO INSTEAD rules are not supported for data-modifying statements in WITH
2259+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
2260+
WITH t AS (
2261+
INSERT INTO y VALUES(0)
2262+
)
2263+
VALUES(FALSE);
2264+
ERROR: DO INSTEAD NOTHING rules are not supported for data-modifying statements in WITH
2265+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
2266+
WITH t AS (
2267+
INSERT INTO y VALUES(0)
2268+
)
2269+
VALUES(FALSE);
2270+
ERROR: DO INSTEAD NOTIFY rules are not supported for data-modifying statements in WITH
2271+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
2272+
WITH t AS (
2273+
INSERT INTO y VALUES(0)
2274+
)
2275+
VALUES(FALSE);
2276+
ERROR: DO ALSO rules are not supported for data-modifying statements in WITH
2277+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
2278+
DO INSTEAD (NOTIFY foo; NOTIFY bar);
2279+
WITH t AS (
2280+
INSERT INTO y VALUES(0)
2281+
)
2282+
VALUES(FALSE);
2283+
ERROR: multi-statement DO INSTEAD rules are not supported for data-modifying statements in WITH
22592284
DROP RULE y_rule ON y;
22602285
-- check that parser lookahead for WITH doesn't cause any odd behavior
22612286
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
@@ -1022,6 +1022,27 @@ WITH t AS (
10221022
INSERT INTO y VALUES(0)
10231023
)
10241024
VALUES(FALSE);
1025+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTHING;
1026+
WITH t AS (
1027+
INSERT INTO y VALUES(0)
1028+
)
1029+
VALUES(FALSE);
1030+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO INSTEAD NOTIFY foo;
1031+
WITH t AS (
1032+
INSERT INTO y VALUES(0)
1033+
)
1034+
VALUES(FALSE);
1035+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y DO ALSO NOTIFY foo;
1036+
WITH t AS (
1037+
INSERT INTO y VALUES(0)
1038+
)
1039+
VALUES(FALSE);
1040+
CREATE OR REPLACE RULE y_rule AS ON INSERT TO y
1041+
DO INSTEAD (NOTIFY foo; NOTIFY bar);
1042+
WITH t AS (
1043+
INSERT INTO y VALUES(0)
1044+
)
1045+
VALUES(FALSE);
10251046
DROP RULE y_rule ON y;
10261047

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

0 commit comments

Comments
 (0)