Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit399437a

Browse files
committed
Improve error messages for missing-FROM-entry cases, as per recent discussion.
1 parent8ea91ba commit399437a

File tree

2 files changed

+98
-18
lines changed

2 files changed

+98
-18
lines changed

‎src/backend/parser/parse_relation.c

Lines changed: 97 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.117 2005/11/22 18:17:16 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.118 2006/01/10 21:59:59 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -161,7 +161,7 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid)
161161
{
162162
RangeTblEntry*rte= (RangeTblEntry*)lfirst(l);
163163

164-
/* yes, the test for alias==NULL should be there... */
164+
/* yes, the test for alias ==NULL should be there... */
165165
if (rte->rtekind==RTE_RELATION&&
166166
rte->relid==relid&&
167167
rte->alias==NULL)
@@ -177,6 +177,48 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid)
177177
returnresult;
178178
}
179179

180+
/*
181+
* searchRangeTable
182+
* See if any RangeTblEntry could possibly match the RangeVar.
183+
* If so, return a pointer to the RangeTblEntry; else return NULL.
184+
*
185+
* This is different from refnameRangeTblEntry in that it considers every
186+
* entry in the ParseState's rangetable(s), not only those that are currently
187+
* visible in the p_relnamespace lists. This behavior is invalid per the SQL
188+
* spec, and it may give ambiguous results (there might be multiple equally
189+
* valid matches, but only one will be returned). This must be used ONLY
190+
* as a heuristic in giving suitable error messages. See warnAutoRange.
191+
*
192+
* Notice that we consider both matches on actual relation name and matches
193+
* on alias.
194+
*/
195+
staticRangeTblEntry*
196+
searchRangeTable(ParseState*pstate,RangeVar*relation)
197+
{
198+
OidrelId=RangeVarGetRelid(relation, true);
199+
char*refname=relation->relname;
200+
201+
while (pstate!=NULL)
202+
{
203+
ListCell*l;
204+
205+
foreach(l,pstate->p_rtable)
206+
{
207+
RangeTblEntry*rte= (RangeTblEntry*)lfirst(l);
208+
209+
if (OidIsValid(relId)&&
210+
rte->rtekind==RTE_RELATION&&
211+
rte->relid==relId)
212+
returnrte;
213+
if (strcmp(rte->eref->aliasname,refname)==0)
214+
returnrte;
215+
}
216+
217+
pstate=pstate->parentParseState;
218+
}
219+
returnNULL;
220+
}
221+
180222
/*
181223
* Check for relation-name conflicts between two relnamespace lists.
182224
* Raise an error if any is found.
@@ -1005,6 +1047,8 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation)
10051047
{
10061048
RangeTblEntry*rte;
10071049

1050+
/* issue warning or error as needed */
1051+
warnAutoRange(pstate,relation);
10081052
/*
10091053
* Note that we set inFromCl true, so that the RTE will be listed
10101054
* explicitly if the parsetree is ever decompiled by ruleutils.c. This
@@ -1014,7 +1058,6 @@ addImplicitRTE(ParseState *pstate, RangeVar *relation)
10141058
rte=addRangeTableEntry(pstate,relation,NULL, false, true);
10151059
/* Add to joinlist and relnamespace, but not varnamespace */
10161060
addRTEtoQuery(pstate,rte, true, true, false);
1017-
warnAutoRange(pstate,relation);
10181061

10191062
returnrte;
10201063
}
@@ -1761,31 +1804,68 @@ attnumTypeId(Relation rd, int attid)
17611804
staticvoid
17621805
warnAutoRange(ParseState*pstate,RangeVar*relation)
17631806
{
1807+
RangeTblEntry*rte;
1808+
intsublevels_up;
1809+
constchar*badAlias=NULL;
1810+
1811+
/*
1812+
* Check to see if there are any potential matches in the query's
1813+
* rangetable. This affects the message we provide.
1814+
*/
1815+
rte=searchRangeTable(pstate,relation);
1816+
1817+
/*
1818+
* If we found a match that has an alias and the alias is visible in
1819+
* the namespace, then the problem is probably use of the relation's
1820+
* real name instead of its alias, ie "SELECT foo.* FROM foo f".
1821+
* This mistake is common enough to justify a specific hint.
1822+
*
1823+
* If we found a match that doesn't meet those criteria, assume the
1824+
* problem is illegal use of a relation outside its scope, as in the
1825+
* MySQL-ism "SELECT ... FROM a, b LEFT JOIN c ON (a.x = c.y)".
1826+
*/
1827+
if (rte&&rte->alias&&
1828+
strcmp(rte->eref->aliasname,relation->relname)!=0&&
1829+
refnameRangeTblEntry(pstate,NULL,rte->eref->aliasname,
1830+
&sublevels_up)==rte)
1831+
badAlias=rte->eref->aliasname;
1832+
17641833
if (!add_missing_from)
17651834
{
1766-
if (pstate->parentParseState!=NULL)
1835+
if (rte)
17671836
ereport(ERROR,
17681837
(errcode(ERRCODE_UNDEFINED_TABLE),
1769-
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
1770-
relation->relname)));
1838+
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
1839+
relation->relname),
1840+
(badAlias ?
1841+
errhint("Perhaps you meant to reference the table alias \"%s\".",
1842+
badAlias) :
1843+
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
1844+
rte->eref->aliasname))));
17711845
else
17721846
ereport(ERROR,
17731847
(errcode(ERRCODE_UNDEFINED_TABLE),
1774-
errmsg("missing FROM-clause entry for table \"%s\"",
1775-
relation->relname)));
1848+
(pstate->parentParseState ?
1849+
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
1850+
relation->relname) :
1851+
errmsg("missing FROM-clause entry for table \"%s\"",
1852+
relation->relname))));
17761853
}
17771854
else
17781855
{
17791856
/* just issue a warning */
1780-
if (pstate->parentParseState!=NULL)
1781-
ereport(NOTICE,
1782-
(errcode(ERRCODE_UNDEFINED_TABLE),
1783-
errmsg("adding missing FROM-clause entry in subquery for table \"%s\"",
1784-
relation->relname)));
1785-
else
1786-
ereport(NOTICE,
1787-
(errcode(ERRCODE_UNDEFINED_TABLE),
1857+
ereport(NOTICE,
1858+
(errcode(ERRCODE_UNDEFINED_TABLE),
1859+
(pstate->parentParseState ?
1860+
errmsg("adding missing FROM-clause entry in subquery for table \"%s\"",
1861+
relation->relname) :
17881862
errmsg("adding missing FROM-clause entry for table \"%s\"",
1789-
relation->relname)));
1863+
relation->relname)),
1864+
(badAlias ?
1865+
errhint("Perhaps you meant to reference the table alias \"%s\".",
1866+
badAlias) :
1867+
(rte ?
1868+
errhint("There is an entry for table \"%s\", but it cannot be referenced from this part of the query.",
1869+
rte->eref->aliasname) :0))));
17901870
}
17911871
}

‎src/test/regress/expected/rowtypes.out

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ select * from quadtable;
6060
(2 rows)
6161

6262
select f1, q.c1 from quadtable;-- fails, q is a table reference
63-
ERROR:relation "q" does not exist
63+
ERROR:missing FROM-clause entry for table "q"
6464
select f1, (q).c1, (qq.q).c1.i from quadtable qq;
6565
f1 | c1 | i
6666
----+-----------+-----

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp