Better error message for a small problem with WITH RECURSIVE

Started by Tom Laneover 17 years ago5 messages
#1Tom Lane
tgl@sss.pgh.pa.us

Quick, what's wrong with this query?

regression=# with q(x) as (select 1 union all select x+1 from q where x<10)
regression-# select * from q;
ERROR: relation "q" does not exist
LINE 1: with q(x) as (select 1 union all select x+1 from q where x<1...
^

The problem is that I forgot to say RECURSIVE. But the error message
is certainly pretty unhelpful. The code is following the SQL spec rule,
which says that for a non-recursive WITH query, the query's name isn't
in scope until after you've parsed it. So you get "does not exist"
rather than something that would clue you in.

I've made this same mistake at least once a day for the past week,
and taken an unreasonable amount of time to figure it out each time :-(
So I think we need a better error message here.

We can't just monkey with the scope rules, because that could change
the meaning of queries that *are* valid, eg a query name could be a
reference to some outer-level WITH. (Of course you'd have to be pretty
nuts to use the same query name at multiple levels of a single SELECT,
and even more nuts to arrange things so that the intended reference is
not the most closely nested one, but spec is spec.) What we can do is
keep a list of "not yet parsed WITH-names" in ParseState, and check
through that list when about to fail for relation-not-found, and issue
a suitable message hinting that maybe you forgot RECURSIVE if we find
a match.

I would think this is overkill, except I've made the same darn mistake
one time too many. It seems clear to me that a lot of other people will
make it too, and if the error message isn't more helpful a lot of time
will get wasted. Barring loud objections, I'm gonna go change it.

regards, tom lane

#2Gregory Stark
stark@enterprisedb.com
In reply to: Tom Lane (#1)
Re: Better error message for a small problem with WITH RECURSIVE

Tom Lane <tgl@sss.pgh.pa.us> writes:

What we can do is keep a list of "not yet parsed WITH-names" in ParseState,
and check through that list when about to fail for relation-not-found, and
issue a suitable message hinting that maybe you forgot RECURSIVE if we find
a match.

I would think this is overkill, except I've made the same darn mistake
one time too many. It seems clear to me that a lot of other people will
make it too, and if the error message isn't more helpful a lot of time
will get wasted. Barring loud objections, I'm gonna go change it.

Perhaps it would be sufficient to just check if we're inside a non-recursive
WITH without bothering to check if the name matches?

--
Gregory Stark
EnterpriseDB http://www.enterprisedb.com
Ask me about EnterpriseDB's Slony Replication support!

#3Heikki Linnakangas
heikki.linnakangas@enterprisedb.com
In reply to: Tom Lane (#1)
Re: Better error message for a small problem with WITH RECURSIVE

Tom Lane wrote:

I would think this is overkill, except I've made the same darn mistake
one time too many. It seems clear to me that a lot of other people will
make it too, and if the error message isn't more helpful a lot of time
will get wasted. Barring loud objections, I'm gonna go change it.

Yes, please. At least DB2 allows recursive queries without the
"RECURSIVE" keyword, just "WITH" is enough. Without a hint, anyone
migrating from such a system will spend hours looking at the query,
seeing nothing wrong.

--
Heikki Linnakangas
EnterpriseDB http://www.enterprisedb.com

#4Tom Lane
tgl@sss.pgh.pa.us
In reply to: Gregory Stark (#2)
Re: Better error message for a small problem with WITH RECURSIVE

Gregory Stark <stark@enterprisedb.com> writes:

Tom Lane <tgl@sss.pgh.pa.us> writes:

What we can do is keep a list of "not yet parsed WITH-names" in ParseState,
and check through that list when about to fail for relation-not-found, and
issue a suitable message hinting that maybe you forgot RECURSIVE if we find
a match.

Perhaps it would be sufficient to just check if we're inside a non-recursive
WITH without bothering to check if the name matches?

Even knowing that would require most of the same changes I made to do
the full nine yards, I think. The previous ParseState info didn't
record anything at all that would allow parserOpenTable to know that
a non-recursive WITH is being examined.

regards, tom lane

#5Tom Lane
tgl@sss.pgh.pa.us
In reply to: Heikki Linnakangas (#3)
Re: Better error message for a small problem with WITH RECURSIVE

Heikki Linnakangas <heikki.linnakangas@enterprisedb.com> writes:

Yes, please. At least DB2 allows recursive queries without the
"RECURSIVE" keyword, just "WITH" is enough. Without a hint, anyone
migrating from such a system will spend hours looking at the query,
seeing nothing wrong.

Huh, interesting ... so they're violating the letter of the spec
as to WITH name scope.

Anyway, here's what we do as of last night:

regression=# with q(x) as (select 1 union all select x+1 from q where x<10)
select * from q;
ERROR: relation "q" does not exist
LINE 1: with q(x) as (select 1 union all select x+1 from q where x<1...
^
DETAIL: There is a WITH item named "q", but it cannot be referenced from this part of the query.
HINT: Use WITH RECURSIVE, or re-order the WITH items to remove forward references.

regards, tom lane