Thread: BUG #6051: wCTE query fail with wrong error text on a table with rules

BUG #6051: wCTE query fail with wrong error text on a table with rules

From
"Jehan-Guillaume (ioguix) de Rorthais"
Date:
The following bug has been logged online:

Bug reference:      6051
Logged by:          Jehan-Guillaume (ioguix) de Rorthais
Email address:      jgdr@dalibo.com
PostgreSQL version: 9.1beta1
Operating system:   Linux x86_64
Description:        wCTE query fail with wrong error text on a table with
rules
Details:

While testing wCTE, I tried to empty a parent table, feeding its child using
rules with this kind of query:

  WITH t1 AS (
    DELETE FROM ONLY test RETURNING *
  )
  INSERT INTO test SELECT * FROM t1;

It works perfectly on a table without rules, but fail with what seems like a
non related error message if there is a rule on INSERT on this table:

  test=# WITH t1 AS (
    DELETE FROM ONLY test RETURNING *
  )
  INSERT INTO test SELECT * FROM t1;
  ERROR:  could not find CTE "t1"

I was expecting this query either to work or raise a comprehensive error
message.

Here is a simple script to reproduce this behaviour:

======================>
$ createdb test

$ psql test
psql (9.1beta1)
Type "help" for help.

test=# SELECT version();
                                                  version

----------------------------------------------------------------------------
--------------------------------
 PostgreSQL 9.1beta1 on x86_64-unknown-linux-gnu, compiled by gcc (GCC)
4.6.0 20110513 (prerelease), 64-bit
(1 row)

test=# CREATE table test AS select i from generate_series(1,3) as t(i);
SELECT 3
test=# SELECT * FROM test;
 i
---
 1
 2
 3
(3 rows)

test=# WITH t1 AS (
test(# DELETE FROM ONLY test RETURNING *
test(# )
test-# INSERT INTO test SELECT * FROM t1;
INSERT 0 3
test=# SELECT * FROM test;
 i
---
 1
 2
 3
(3 rows)

test=# CREATE TABLE test2 () inherits (test);
CREATE TABLE
test=# CREATE RULE test_ins AS ON INSERT TO test DO INSTEAD INSERT INTO
test2 VALUES (NEW.i);
CREATE RULE
test=# WITH t1 AS (
DELETE FROM ONLY test RETURNING *
)
INSERT INTO test SELECT * FROM t1;
ERROR:  could not find CTE "t1"
<======================

Re: BUG #6051: wCTE query fail with wrong error text on a table with rules

From
Merlin Moncure
Date:
On Fri, Jun 3, 2011 at 10:42 AM, Jehan-Guillaume (ioguix) de Rorthais
<jgdr@dalibo.com> wrote:
>
> The following bug has been logged online:
>
> Bug reference: =A0 =A0 =A06051
> Logged by: =A0 =A0 =A0 =A0 =A0Jehan-Guillaume (ioguix) de Rorthais
> Email address: =A0 =A0 =A0jgdr@dalibo.com
> PostgreSQL version: 9.1beta1
> Operating system: =A0 Linux x86_64
> Description: =A0 =A0 =A0 =A0wCTE query fail with wrong error text on a ta=
ble with
> rules
> Details:
>
> While testing wCTE, I tried to empty a parent table, feeding its child us=
ing
> rules with this kind of query:
>
> =A0WITH t1 AS (
> =A0 =A0DELETE FROM ONLY test RETURNING *
> =A0)
> =A0INSERT INTO test SELECT * FROM t1;
>
> It works perfectly on a table without rules, but fail with what seems lik=
e a
> non related error message if there is a rule on INSERT on this table:
>
> =A0test=3D# WITH t1 AS (
> =A0 =A0DELETE FROM ONLY test RETURNING *
> =A0)
> =A0INSERT INTO test SELECT * FROM t1;
> =A0ERROR: =A0could not find CTE "t1"
>
> I was expecting this query either to work or raise a comprehensive error
> message.
>
> Here is a simple script to reproduce this behaviour:
>
> =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D>
> $ createdb test
>
> $ psql test
> psql (9.1beta1)
> Type "help" for help.
>
> test=3D# SELECT version();
> =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =A0 =
=A0 =A0 =A0 =A0 =A0 =A0 =A0version
>
> -------------------------------------------------------------------------=
---
> --------------------------------
> =A0PostgreSQL 9.1beta1 on x86_64-unknown-linux-gnu, compiled by gcc (GCC)
> 4.6.0 20110513 (prerelease), 64-bit
> (1 row)
>
> test=3D# CREATE table test AS select i from generate_series(1,3) as t(i);
> SELECT 3
> test=3D# SELECT * FROM test;
> =A0i
> ---
> =A01
> =A02
> =A03
> (3 rows)
>
> test=3D# WITH t1 AS (
> test(# DELETE FROM ONLY test RETURNING *
> test(# )
> test-# INSERT INTO test SELECT * FROM t1;
> INSERT 0 3
> test=3D# SELECT * FROM test;
> =A0i
> ---
> =A01
> =A02
> =A03
> (3 rows)
>
> test=3D# CREATE TABLE test2 () inherits (test);
> CREATE TABLE
> test=3D# CREATE RULE test_ins AS ON INSERT TO test DO INSTEAD INSERT INTO
> test2 VALUES (NEW.i);
> CREATE RULE
> test=3D# WITH t1 AS (
> DELETE FROM ONLY test RETURNING *
> )
> INSERT INTO test SELECT * FROM t1;
> ERROR: =A0could not find CTE "t1"
> <=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D

IIRC the fact that rules don't play nice with wCTE was brought up
several times during the implementation discussions.  I'm not saying
the error message is great, but you can pretty much add this to the
giant pile of reasons not to use rules at all (particularly in 9.1
with the view triggers).

merlin
Merlin Moncure <mmoncure@gmail.com> writes:
> On Fri, Jun 3, 2011 at 10:42 AM, Jehan-Guillaume (ioguix) de Rorthais
> <jgdr@dalibo.com> wrote:
>> test=# CREATE RULE test_ins AS ON INSERT TO test DO INSTEAD INSERT INTO
>> test2 VALUES (NEW.i);
>> CREATE RULE
>> test=# WITH t1 AS (
>> DELETE FROM ONLY test RETURNING *
>> )
>> INSERT INTO test SELECT * FROM t1;
>> ERROR:  could not find CTE "t1"

> IIRC the fact that rules don't play nice with wCTE was brought up
> several times during the implementation discussions.  I'm not saying
> the error message is great, but you can pretty much add this to the
> giant pile of reasons not to use rules at all (particularly in 9.1
> with the view triggers).

There are definitely cases that don't work, but I had thought we at
least threw an intelligible "not implemented" error for all of them.
This one seems to be an oversight: specifically, rewriteRuleAction()
isn't considering the possibility that the rewritten rule action will
need to make use of CTEs from the original query.

We could paste a copy of the original's cteList into the rule action,
but there are still issues:

* If there's more than one rule action, we could end up executing
multiple copies of the same CTE query; which breaks the expectation
of single evaluation for a CTE.

* If there are CTEs attached to the rule action, as well as to the
original query, and there is a conflict of CTE names between them,
we can't handle that AFAICS.  (The planner expects to look up entries
in a cteList by name...)

* Maybe some other things that aren't obvious yet.

I don't particularly mind throwing a not-implemented error for the first
case (ie, just say multiple rule actions don't mix with CTE queries);
but the second case seems seriously annoying, since there's no way for
someone to write a CTE-containing rule action without risking a
conflict.  Ideas anybody?

            regards, tom lane

Re: BUG #6051: wCTE query fail with wrong error text on a table with rules

From
David Fetter
Date:
On Sat, Jun 04, 2011 at 05:24:22PM -0400, Tom Lane wrote:
> Merlin Moncure <mmoncure@gmail.com> writes:
> > On Fri, Jun 3, 2011 at 10:42 AM, Jehan-Guillaume (ioguix) de Rorthais
> > <jgdr@dalibo.com> wrote:
> >> test=# CREATE RULE test_ins AS ON INSERT TO test DO INSTEAD INSERT INTO
> >> test2 VALUES (NEW.i);
> >> CREATE RULE
> >> test=# WITH t1 AS (
> >> DELETE FROM ONLY test RETURNING *
> >> )
> >> INSERT INTO test SELECT * FROM t1;
> >> ERROR:  could not find CTE "t1"
>
> > IIRC the fact that rules don't play nice with wCTE was brought up
> > several times during the implementation discussions.  I'm not saying
> > the error message is great, but you can pretty much add this to the
> > giant pile of reasons not to use rules at all (particularly in 9.1
> > with the view triggers).
>
> There are definitely cases that don't work, but I had thought we at
> least threw an intelligible "not implemented" error for all of them.
> This one seems to be an oversight: specifically, rewriteRuleAction()
> isn't considering the possibility that the rewritten rule action will
> need to make use of CTEs from the original query.
>
> We could paste a copy of the original's cteList into the rule action,
> but there are still issues:
>
> * If there's more than one rule action, we could end up executing
> multiple copies of the same CTE query; which breaks the expectation
> of single evaluation for a CTE.
>
> * If there are CTEs attached to the rule action, as well as to the
> original query, and there is a conflict of CTE names between them,
> we can't handle that AFAICS.  (The planner expects to look up entries
> in a cteList by name...)
>
> * Maybe some other things that aren't obvious yet.
>
> I don't particularly mind throwing a not-implemented error for the first
> case (ie, just say multiple rule actions don't mix with CTE queries);

Great :)

> but the second case seems seriously annoying, since there's no way
> for someone to write a CTE-containing rule action without risking a
> conflict.  Ideas anybody?

Is there some way to throw "not implemented" there, too?  It seems to
me that making accommodations for the user-modifiable part of our
rewrite rules isn't the right direction to go, as we're well on our
way to phasing the user-modifiable part out.

Cheers,
David.
--
David Fetter <david@fetter.org> http://fetter.org/
Phone: +1 415 235 3778  AIM: dfetter666  Yahoo!: dfetter
Skype: davidfetter      XMPP: david.fetter@gmail.com
iCal: webcal://www.tripit.com/feed/ical/people/david74/tripit.ics

Remember to vote!
Consider donating to Postgres: http://www.postgresql.org/about/donate
David Fetter <david@fetter.org> writes:
> On Sat, Jun 04, 2011 at 05:24:22PM -0400, Tom Lane wrote:
>> We could paste a copy of the original's cteList into the rule action,
>> but there are still issues:
>>
>> * If there's more than one rule action, we could end up executing
>> multiple copies of the same CTE query; which breaks the expectation
>> of single evaluation for a CTE.
>>
>> * If there are CTEs attached to the rule action, as well as to the
>> original query, and there is a conflict of CTE names between them,
>> we can't handle that AFAICS.  (The planner expects to look up entries
>> in a cteList by name...)
>>
>> * Maybe some other things that aren't obvious yet.
>>
>> I don't particularly mind throwing a not-implemented error for the first
>> case (ie, just say multiple rule actions don't mix with CTE queries);

> Great :)

>> but the second case seems seriously annoying, since there's no way
>> for someone to write a CTE-containing rule action without risking a
>> conflict.  Ideas anybody?

> Is there some way to throw "not implemented" there, too?  It seems to
> me that making accommodations for the user-modifiable part of our
> rewrite rules isn't the right direction to go, as we're well on our
> way to phasing the user-modifiable part out.

Yes, we certainly can throw an error for that, it's just going to be a
pain from a usability standpoint.  But I agree that the number of people
affected might be small, so it's not worth doing a significant rewrite
for right now.

I've committed a patch along these lines.

            regards, tom lane