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

Commit0ff384f

Browse files
committed
Fix the implicit-RTE code to be able to handle implicit RTEs for CTEs, as
well as regular tables. Per discussion, this seems necessary to meet theprinciple of least astonishment.In passing, simplify the error messages in warnAutoRange(). Now that wehave parser error position info for these errors, it doesn't seem veryuseful to word the error message differently depending on whether we areinside a sub-select or not.
1 parentaf88c9b commit0ff384f

File tree

3 files changed

+87
-49
lines changed

3 files changed

+87
-49
lines changed

‎src/backend/parser/parse_clause.c

Lines changed: 6 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.180 2008/10/04 21:56:54 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.181 2008/10/06 02:12:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -631,34 +631,15 @@ transformFromClauseItem(ParseState *pstate, Node *n,
631631
RangeTblEntry*rte=NULL;
632632
intrtindex;
633633

634-
/*
635-
* If it is an unqualified name, it might be a reference to some
636-
* CTE visible in this or a parent query.
637-
*/
634+
/* if it is an unqualified name, it might be a CTE reference */
638635
if (!rv->schemaname)
639636
{
640-
ParseState*ps;
637+
CommonTableExpr*cte;
641638
Indexlevelsup;
642639

643-
for (ps=pstate,levelsup=0;
644-
ps!=NULL;
645-
ps=ps->parentParseState,levelsup++)
646-
{
647-
ListCell*lc;
648-
649-
foreach(lc,ps->p_ctenamespace)
650-
{
651-
CommonTableExpr*cte= (CommonTableExpr*)lfirst(lc);
652-
653-
if (strcmp(rv->relname,cte->ctename)==0)
654-
{
655-
rte=transformCTEReference(pstate,rv,cte,levelsup);
656-
break;
657-
}
658-
}
659-
if (rte)
660-
break;
661-
}
640+
cte=scanNameSpaceForCTE(pstate,rv->relname,&levelsup);
641+
if (cte)
642+
rte=transformCTEReference(pstate,rv,cte,levelsup);
662643
}
663644

664645
/* if not found as a CTE, must be a table reference */

‎src/backend/parser/parse_relation.c

Lines changed: 77 additions & 23 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.136 2008/10/04 21:56:54 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_relation.c,v 1.137 2008/10/06 02:12:56 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -182,6 +182,38 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
182182
returnresult;
183183
}
184184

185+
/*
186+
* Search the query's CTE namespace for a CTE matching the given unqualified
187+
* refname. Return the CTE (and its levelsup count) if a match, or NULL
188+
* if no match. We need not worry about multiple matches, since parse_cte.c
189+
* rejects WITH lists containing duplicate CTE names.
190+
*/
191+
CommonTableExpr*
192+
scanNameSpaceForCTE(ParseState*pstate,constchar*refname,
193+
Index*ctelevelsup)
194+
{
195+
Indexlevelsup;
196+
197+
for (levelsup=0;
198+
pstate!=NULL;
199+
pstate=pstate->parentParseState,levelsup++)
200+
{
201+
ListCell*lc;
202+
203+
foreach(lc,pstate->p_ctenamespace)
204+
{
205+
CommonTableExpr*cte= (CommonTableExpr*)lfirst(lc);
206+
207+
if (strcmp(cte->ctename,refname)==0)
208+
{
209+
*ctelevelsup=levelsup;
210+
returncte;
211+
}
212+
}
213+
}
214+
returnNULL;
215+
}
216+
185217
/*
186218
* searchRangeTable
187219
* See if any RangeTblEntry could possibly match the RangeVar.
@@ -194,32 +226,51 @@ scanNameSpaceForRelid(ParseState *pstate, Oid relid, int location)
194226
* valid matches, but only one will be returned). This must be used ONLY
195227
* as a heuristic in giving suitable error messages. See warnAutoRange.
196228
*
197-
* Notice that we consider both matches on actual relationname and matches
198-
* on alias.
229+
* Notice that we consider both matches on actual relation(or CTE) name
230+
*and matcheson alias.
199231
*/
200232
staticRangeTblEntry*
201233
searchRangeTable(ParseState*pstate,RangeVar*relation)
202234
{
203-
OidrelId=RangeVarGetRelid(relation, true);
204-
char*refname=relation->relname;
235+
constchar*refname=relation->relname;
236+
OidrelId=InvalidOid;
237+
CommonTableExpr*cte=NULL;
238+
Indexctelevelsup=0;
239+
Indexlevelsup;
205240

206-
while (pstate!=NULL)
241+
/*
242+
* If it's an unqualified name, check for possible CTE matches.
243+
* A CTE hides any real relation matches. If no CTE, look for
244+
* a matching relation.
245+
*/
246+
if (!relation->schemaname)
247+
cte=scanNameSpaceForCTE(pstate,refname,&ctelevelsup);
248+
if (!cte)
249+
relId=RangeVarGetRelid(relation, true);
250+
251+
/* Now look for RTEs matching either the relation/CTE or the alias */
252+
for (levelsup=0;
253+
pstate!=NULL;
254+
pstate=pstate->parentParseState,levelsup++)
207255
{
208256
ListCell*l;
209257

210258
foreach(l,pstate->p_rtable)
211259
{
212260
RangeTblEntry*rte= (RangeTblEntry*)lfirst(l);
213261

214-
if (OidIsValid(relId)&&
215-
rte->rtekind==RTE_RELATION&&
262+
if (rte->rtekind==RTE_RELATION&&
263+
OidIsValid(relId)&&
216264
rte->relid==relId)
217265
returnrte;
266+
if (rte->rtekind==RTE_CTE&&
267+
cte!=NULL&&
268+
rte->ctelevelsup+levelsup==ctelevelsup&&
269+
strcmp(rte->ctename,refname)==0)
270+
returnrte;
218271
if (strcmp(rte->eref->aliasname,refname)==0)
219272
returnrte;
220273
}
221-
222-
pstate=pstate->parentParseState;
223274
}
224275
returnNULL;
225276
}
@@ -1293,18 +1344,27 @@ addRTEtoQuery(ParseState *pstate, RangeTblEntry *rte,
12931344
RangeTblEntry*
12941345
addImplicitRTE(ParseState*pstate,RangeVar*relation)
12951346
{
1347+
CommonTableExpr*cte=NULL;
1348+
Indexlevelsup=0;
12961349
RangeTblEntry*rte;
12971350

12981351
/* issue warning or error as needed */
12991352
warnAutoRange(pstate,relation);
13001353

1354+
/* if it is an unqualified name, it might be a CTE reference */
1355+
if (!relation->schemaname)
1356+
cte=scanNameSpaceForCTE(pstate,relation->relname,&levelsup);
1357+
13011358
/*
13021359
* Note that we set inFromCl true, so that the RTE will be listed
13031360
* explicitly if the parsetree is ever decompiled by ruleutils.c. This
13041361
* provides a migration path for views/rules that were originally written
13051362
* with implicit-RTE syntax.
13061363
*/
1307-
rte=addRangeTableEntry(pstate,relation,NULL, false, true);
1364+
if (cte)
1365+
rte=addRangeTableEntryForCTE(pstate,cte,levelsup,NULL, true);
1366+
else
1367+
rte=addRangeTableEntry(pstate,relation,NULL, false, true);
13081368
/* Add to joinlist and relnamespace, but not varnamespace */
13091369
addRTEtoQuery(pstate,rte, true, true, false);
13101370

@@ -2194,8 +2254,8 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
21942254
if (rte)
21952255
ereport(ERROR,
21962256
(errcode(ERRCODE_UNDEFINED_TABLE),
2197-
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
2198-
relation->relname),
2257+
errmsg("invalid reference to FROM-clause entry for table \"%s\"",
2258+
relation->relname),
21992259
(badAlias ?
22002260
errhint("Perhaps you meant to reference the table alias \"%s\".",
22012261
badAlias) :
@@ -2205,23 +2265,17 @@ warnAutoRange(ParseState *pstate, RangeVar *relation)
22052265
else
22062266
ereport(ERROR,
22072267
(errcode(ERRCODE_UNDEFINED_TABLE),
2208-
(pstate->parentParseState ?
2209-
errmsg("missing FROM-clause entry in subquery for table \"%s\"",
2210-
relation->relname) :
2211-
errmsg("missing FROM-clause entry for table \"%s\"",
2212-
relation->relname)),
2268+
errmsg("missing FROM-clause entry for table \"%s\"",
2269+
relation->relname),
22132270
parser_errposition(pstate,relation->location)));
22142271
}
22152272
else
22162273
{
22172274
/* just issue a warning */
22182275
ereport(NOTICE,
22192276
(errcode(ERRCODE_UNDEFINED_TABLE),
2220-
(pstate->parentParseState ?
2221-
errmsg("adding missing FROM-clause entry in subquery for table \"%s\"",
2222-
relation->relname) :
2223-
errmsg("adding missing FROM-clause entry for table \"%s\"",
2224-
relation->relname)),
2277+
errmsg("adding missing FROM-clause entry for table \"%s\"",
2278+
relation->relname),
22252279
(badAlias ?
22262280
errhint("Perhaps you meant to reference the table alias \"%s\".",
22272281
badAlias) :

‎src/include/parser/parse_relation.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2008, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.59 2008/10/04 21:56:55 tgl Exp $
10+
* $PostgreSQL: pgsql/src/include/parser/parse_relation.h,v 1.60 2008/10/06 02:12:56 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -23,6 +23,9 @@ extern RangeTblEntry *refnameRangeTblEntry(ParseState *pstate,
2323
constchar*refname,
2424
intlocation,
2525
int*sublevels_up);
26+
externCommonTableExpr*scanNameSpaceForCTE(ParseState*pstate,
27+
constchar*refname,
28+
Index*ctelevelsup);
2629
externvoidcheckNameSpaceConflicts(ParseState*pstate,List*namespace1,
2730
List*namespace2);
2831
externintRTERangeTablePosn(ParseState*pstate,

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp