Thread: BUG #18664: Assert in BeginCopyTo() fails when source DML query rewritten with notifying rule
BUG #18664: Assert in BeginCopyTo() fails when source DML query rewritten with notifying rule
From
PG Bug reporting form
Date:
The following bug has been logged on the website: Bug reference: 18664 Logged by: Alexander Lakhin Email address: exclusion@gmail.com PostgreSQL version: 17.0 Operating system: Ubuntu 22.04 Description: The following script: CREATE TABLE t(i int); CREATE RULE r AS ON INSERT TO t DO INSTEAD NOTIFY c; COPY (INSERT INTO t VALUES (1)) TO stdout; triggers an Assert in BeginCopyTo(): TRAP: failed Assert("query->utilityStmt == NULL"), File: "copyto.c", Line: 495, PID: 1689825 ExceptionalCondition at assert.c:52:13 BeginCopyTo at copyto.c:501:12 DoCopy at copy.c:313:12 standard_ProcessUtility at utility.c:738:8 ProcessUtility at utility.c:523:3 PortalRunUtility at pquery.c:1158:2 PortalRunMulti at pquery.c:1315:5 PortalRun at pquery.c:795:5 ... Reproduced starting from 92e38182d.
Re: BUG #18664: Assert in BeginCopyTo() fails when source DML query rewritten with notifying rule
From
Tom Lane
Date:
Tender Wang <tndrwang@gmail.com> writes: > PG Bug reporting form <noreply@postgresql.org> 于2024年10月21日周一 19:32写道: >> The following script: >> CREATE TABLE t(i int); >> CREATE RULE r AS ON INSERT TO t DO INSTEAD NOTIFY c; >> COPY (INSERT INTO t VALUES (1)) TO stdout; >> >> triggers an Assert in BeginCopyTo(): > I take a quick look. It seems 92e38182d ignored this case. > I gave a fix that remove the Assert and add an Assert in another if blocks. > Any thoughts? I don't like this fix, because the error message is just completely misleading for this case. "COPY query must have a RETURNING clause" makes it look like your mistake was to not write COPY (INSERT INTO t VALUES (1) RETURNING *) TO stdout; Of course doing that will fix nothing, and you'd still get the exact same error message, leaving the user quite confused. So I think it's worth issuing a more specific message. I also noted somebody's faulty grammar in the nearby message "DO ALSO rules are not supported for the COPY". So I think we want the attached. I went back and forth about whether to make the new message be specifically "COPY query must not be NOTIFY", but decided that we'd surely forget to update it if we ever allow any other sort of utility command in rules. So better to word it generically. regards, tom lane diff --git a/src/backend/commands/copyto.c b/src/backend/commands/copyto.c index 463083e645..f55e6d9675 100644 --- a/src/backend/commands/copyto.c +++ b/src/backend/commands/copyto.c @@ -475,7 +475,7 @@ BeginCopyTo(ParseState *pstate, if (q->querySource == QSRC_NON_INSTEAD_RULE) ereport(ERROR, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("DO ALSO rules are not supported for the COPY"))); + errmsg("DO ALSO rules are not supported for COPY"))); } ereport(ERROR, @@ -492,7 +492,11 @@ BeginCopyTo(ParseState *pstate, (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), errmsg("COPY (SELECT INTO) is not supported"))); - Assert(query->utilityStmt == NULL); + /* The only other utility command we could see is NOTIFY */ + if (query->utilityStmt != NULL) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("COPY query must not be a utility command"))); /* * Similarly the grammar doesn't enforce the presence of a RETURNING diff --git a/src/test/regress/expected/copydml.out b/src/test/regress/expected/copydml.out index b5a225628f..e91e83260a 100644 --- a/src/test/regress/expected/copydml.out +++ b/src/test/regress/expected/copydml.out @@ -38,7 +38,7 @@ ERROR: DO INSTEAD NOTHING rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on insert to copydml_test do also delete from copydml_test; copy (insert into copydml_test default values) to stdout; -ERROR: DO ALSO rules are not supported for the COPY +ERROR: DO ALSO rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on insert to copydml_test do instead (delete from copydml_test; delete from copydml_test); copy (insert into copydml_test default values) to stdout; @@ -54,7 +54,7 @@ ERROR: DO INSTEAD NOTHING rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on update to copydml_test do also delete from copydml_test; copy (update copydml_test set t = 'f') to stdout; -ERROR: DO ALSO rules are not supported for the COPY +ERROR: DO ALSO rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on update to copydml_test do instead (delete from copydml_test; delete from copydml_test); copy (update copydml_test set t = 'f') to stdout; @@ -70,7 +70,7 @@ ERROR: DO INSTEAD NOTHING rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on delete to copydml_test do also insert into copydml_test default values; copy (delete from copydml_test) to stdout; -ERROR: DO ALSO rules are not supported for the COPY +ERROR: DO ALSO rules are not supported for COPY drop rule qqq on copydml_test; create rule qqq as on delete to copydml_test do instead (insert into copydml_test default values; insert into copydml_testdefault values); copy (delete from copydml_test) to stdout; @@ -80,6 +80,10 @@ create rule qqq as on delete to copydml_test where old.t <> 'f' do instead inser copy (delete from copydml_test) to stdout; ERROR: conditional DO INSTEAD rules are not supported for COPY drop rule qqq on copydml_test; +create rule qqq as on insert to copydml_test do instead notify copydml_test; +copy (insert into copydml_test default values) to stdout; +ERROR: COPY query must not be a utility command +drop rule qqq on copydml_test; -- triggers create function qqq_trig() returns trigger as $$ begin diff --git a/src/test/regress/sql/copydml.sql b/src/test/regress/sql/copydml.sql index 4578342253..b7eeb0eed8 100644 --- a/src/test/regress/sql/copydml.sql +++ b/src/test/regress/sql/copydml.sql @@ -66,6 +66,10 @@ create rule qqq as on delete to copydml_test where old.t <> 'f' do instead inser copy (delete from copydml_test) to stdout; drop rule qqq on copydml_test; +create rule qqq as on insert to copydml_test do instead notify copydml_test; +copy (insert into copydml_test default values) to stdout; +drop rule qqq on copydml_test; + -- triggers create function qqq_trig() returns trigger as $$ begin
Re: BUG #18664: Assert in BeginCopyTo() fails when source DML query rewritten with notifying rule
From
Tender Wang
Date:
Tom Lane <tgl@sss.pgh.pa.us> 于2024年10月22日周二 01:30写道:
Tender Wang <tndrwang@gmail.com> writes:
> PG Bug reporting form <noreply@postgresql.org> 于2024年10月21日周一 19:32写道:
>> The following script:
>> CREATE TABLE t(i int);
>> CREATE RULE r AS ON INSERT TO t DO INSTEAD NOTIFY c;
>> COPY (INSERT INTO t VALUES (1)) TO stdout;
>>
>> triggers an Assert in BeginCopyTo():
> I take a quick look. It seems 92e38182d ignored this case.
> I gave a fix that remove the Assert and add an Assert in another if blocks.
> Any thoughts?
I don't like this fix, because the error message is just completely
misleading for this case. "COPY query must have a RETURNING clause"
makes it look like your mistake was to not write
COPY (INSERT INTO t VALUES (1) RETURNING *) TO stdout;
Of course doing that will fix nothing, and you'd still get the exact
same error message, leaving the user quite confused. So I think
it's worth issuing a more specific message.
Agree.
I also noted somebody's faulty grammar in the nearby message
"DO ALSO rules are not supported for the COPY".
So I think we want the attached. I went back and forth about
whether to make the new message be specifically "COPY query must
not be NOTIFY", but decided that we'd surely forget to update it
if we ever allow any other sort of utility command in rules.
So better to word it generically.
LGTM
Thanks,
Tender Wang