Обсуждение: Possible Bug in 9.2beta3

Поиск
Список
Период
Сортировка

Possible Bug in 9.2beta3

От
Adam Mackler
Дата:
Hi:

I think I might have found a bug in the 9.2beta3 version.  I'm kind of
new to SQL, so forgive me if I'm just misinterpreting correct
behavior.  Given the query below, execute it.  You should get a
seven-row result.

Next, uncomment the final UNION four lines from the end.  When I do
that I then get a two row result.  I'm not an expert on recursive
CTEs, but I don't believe a UNION should decrease the number of rows
returned.

Next, change the condition in the final WHERE clause (seven lines from
the end) from "e.row_type='false'" to just "false".  Again, I'm not an
expert but my understanding is that any boolean expression returning
false should be equivalent in a given WHERE clause, and you can see
there's no row_type column with value 'false'.

If this is not a bug and I'm just confused, then I apologize and would
greatly appreciate any suggestions as to what I could read that would
unconfuse me.  Otherwise, let me know if you need any other details
about my environment.  Thanks very much.  -Adam Mackler

 -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --

WITH RECURSIVE
tab(id_key,link) AS ( VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17) ),
iter (id_key, row_type, link) AS (
    SELECT 0, 'base', 17
  UNION(
    WITH remaining(id_key, row_type, link, min) AS (
      SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
      FROM tab INNER JOIN iter USING (link)
      WHERE tab.id_key > iter.id_key
    ),
    first_remaining AS (
      SELECT id_key, row_type, link
      FROM remaining
      WHERE id_key=min
    ),
    effect AS (
      SELECT tab.id_key, 'new'::text, tab.link
      FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
      /* Try changing this WHERE clause to other false expressions */
      WHERE e.row_type='false'
    )
    SELECT * FROM first_remaining
    /* Try uncommenting the next line */
    --UNION SELECT * FROM effect
  )
)
SELECT DISTINCT * FROM iter

Re: Possible Bug in 9.2beta3

От
Greg Stark
Дата:
On Mon, Aug 13, 2012 at 7:17 PM, Adam Mackler <AdamMackler@gmail.com> wrote:
>
> Next, uncomment the final UNION four lines from the end.  When I do
> that I then get a two row result.  I'm not an expert on recursive
> CTEs, but I don't believe a UNION should decrease the number of rows
> returned.

I haven't dug through all of it yet but it's definitely the case that
UNION can reduce the number of rows returned. If there are any
duplicates in one side of the union they'll be eliminated by the
UNION.

That said your input set doesn't have any duplicates so that shouldn't
be relevant. For some reason I'm getting a syntax error trying to
reproduce your problem but I have an old build of Postgres lying
around so I'm going to update and try again.

--
greg

Re: Possible Bug in 9.2beta3

От
Tom Lane
Дата:
Adam Mackler <AdamMackler@gmail.com> writes:
> WITH RECURSIVE
> tab(id_key,link) AS ( VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17) ),
> iter (id_key, row_type, link) AS (
>     SELECT 0, 'base', 17
>   UNION(
>     WITH remaining(id_key, row_type, link, min) AS (
>       SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
>       FROM tab INNER JOIN iter USING (link)
>       WHERE tab.id_key > iter.id_key
>     ),
>     first_remaining AS (
>       SELECT id_key, row_type, link
>       FROM remaining
>       WHERE id_key=min
>     ),
>     effect AS (
>       SELECT tab.id_key, 'new'::text, tab.link
>       FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
>       /* Try changing this WHERE clause to other false expressions */
>       WHERE e.row_type='false'
>     )
>     SELECT * FROM first_remaining
>     /* Try uncommenting the next line */
>     --UNION SELECT * FROM effect
>   )
> )
> SELECT DISTINCT * FROM iter

Right offhand I'm inclined to think that the reference to "iter"
inside the first sub-WITH ought to be disallowed.  I don't recall
the exact rules about where a recursive reference can appear, but
it sure doesn't seem like that ought to be OK, does it?

            regards, tom lane

Re: Possible Bug in 9.2beta3

От
Adam Mackler
Дата:
Are you asking me or the other experts?  I had not even heard of a
common table expression a few weeks ago, so I doubt I'm qualified to
opine what ought to be possible; I just know what I'm trying to do.
Basically I've got a recursive CTE with rows, some of which have
information that I want to be split between two rows in a result
table.  I couldn't see a way to do that except to "copy" the working
table of the outer recursive CTE to an intermediary inner CTE, so that
then I could refer to that intermediary CTE twice, once for each row
that I want to result from one row in the outer recursive CTE.  If
that makes sense.

It wouldn't surprise me at all to learn of a better way to do what I
want, but to answer your question: on the one hand yes, I was
obviously trying to "get around" a limitation that was expressed to me
in a specific error message about only referring to a recursive CTE
working-table variable in one location.  On the other hand, I don't
see why I shouldn't be able to look at that working table more than
once on each iteration.

I imagine the "optimal" answer requires more knowledge of what's going
on under the covers than I have, as well as familiarity with the SQL
standard and more experience & expertise than I have in how to solve
problems using SQL.  As far as facility with SQL, I'm still pretty
much stumbling in the dark and learning by trial-and-error and reading
whatever I can find that seems on point, so, again, my current idea of
what ought to be possible is based on a rather uninformed foundation.

Adam Mackler

On Wed, Aug 15, 2012 at 12:53 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
> Adam Mackler <AdamMackler@gmail.com> writes:
>> WITH RECURSIVE
>> tab(id_key,link) AS ( VALUES (1,17), (2,17), (3,17), (4,17), (6,17), (5,17) ),
>> iter (id_key, row_type, link) AS (
>>     SELECT 0, 'base', 17
>>   UNION(
>>     WITH remaining(id_key, row_type, link, min) AS (
>>       SELECT tab.id_key, 'true'::text, iter.link, MIN(tab.id_key) OVER ()
>>       FROM tab INNER JOIN iter USING (link)
>>       WHERE tab.id_key > iter.id_key
>>     ),
>>     first_remaining AS (
>>       SELECT id_key, row_type, link
>>       FROM remaining
>>       WHERE id_key=min
>>     ),
>>     effect AS (
>>       SELECT tab.id_key, 'new'::text, tab.link
>>       FROM first_remaining e INNER JOIN tab ON e.id_key=tab.id_key
>>       /* Try changing this WHERE clause to other false expressions */
>>       WHERE e.row_type='false'
>>     )
>>     SELECT * FROM first_remaining
>>     /* Try uncommenting the next line */
>>     --UNION SELECT * FROM effect
>>   )
>> )
>> SELECT DISTINCT * FROM iter
>
> Right offhand I'm inclined to think that the reference to "iter"
> inside the first sub-WITH ought to be disallowed.  I don't recall
> the exact rules about where a recursive reference can appear, but
> it sure doesn't seem like that ought to be OK, does it?
>
>                         regards, tom lane



--
Adam Mackler

Re: Possible Bug in 9.2beta3

От
Tom Lane
Дата:
Adam Mackler <adammackler@gmail.com> writes:
> On Wed, Aug 15, 2012 at 12:53 PM, Tom Lane <tgl@sss.pgh.pa.us> wrote:
>> Right offhand I'm inclined to think that the reference to "iter"
>> inside the first sub-WITH ought to be disallowed.  I don't recall
>> the exact rules about where a recursive reference can appear, but
>> it sure doesn't seem like that ought to be OK, does it?

> Are you asking me or the other experts?

More the latter.  The verbiage in SQL:2008 7.13 <query expression>
syntax rule 2) g) is sufficiently dense that it's not easy to tell
what they're forbidding, and as usual with the SQL committee, no word
of rationale shall escape their lips.  So I have no idea whether these
restrictions are really logically necessary to ensure a predictable
result, or they just represent the lowest common denominator of the
implementations written by the companies with seats on the committee.
But it sort of looks like subrule iii) 3) restricts the recursive
reference to appear in the main body of the subquery, not in a WITH
attached to it.

Be that as it may, our implementation seems to be able to cope with it;
the issue that we had here was pretty easily resolvable once I'd traced
through the execution.  Patch is committed, though too late for this
week's releases.

            regards, tom lane