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

Commit255f66e

Browse files
committed
Fix bug with WITH RECURSIVE immediately inside WITH RECURSIVE. 99% of the
code was already okay with this, but the hack that obtained the outputcolumn types of a recursive union in advance of doing real parse analysisof the recursive union forgot to handle the case where there was an innerWITH clause available to the non-recursive term. Best fix seems to be torefactor so that we don't need the "throwaway" parse analysis step at all.Instead, teach the transformSetOperationStmt code to set up the CTE's outputcolumn information after it's processed the non-recursive term normally.Per report from David Fetter.
1 parentd69a419 commit255f66e

File tree

9 files changed

+203
-44
lines changed

9 files changed

+203
-44
lines changed

‎src/backend/parser/analyze.c‎

Lines changed: 84 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
1818
* Portions Copyright (c) 1994, Regents of the University of California
1919
*
20-
*$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.390 2009/08/27 20:08:02 tgl Exp $
20+
*$PostgreSQL: pgsql/src/backend/parser/analyze.c,v 1.391 2009/09/09 03:32:52 tgl Exp $
2121
*
2222
*-------------------------------------------------------------------------
2323
*/
@@ -50,7 +50,9 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
5050
staticQuery*transformValuesClause(ParseState*pstate,SelectStmt*stmt);
5151
staticQuery*transformSetOperationStmt(ParseState*pstate,SelectStmt*stmt);
5252
staticNode*transformSetOperationTree(ParseState*pstate,SelectStmt*stmt,
53-
List**colInfo);
53+
boolisTopLevel,List**colInfo);
54+
staticvoiddetermineRecursiveColTypes(ParseState*pstate,
55+
Node*larg,List*lcolinfo);
5456
staticvoidapplyColumnNames(List*dst,List*src);
5557
staticQuery*transformUpdateStmt(ParseState*pstate,UpdateStmt*stmt);
5658
staticList*transformReturningList(ParseState*pstate,List*returningList);
@@ -135,11 +137,14 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
135137
*Entry point for recursively analyzing a sub-statement.
136138
*/
137139
Query*
138-
parse_sub_analyze(Node*parseTree,ParseState*parentParseState)
140+
parse_sub_analyze(Node*parseTree,ParseState*parentParseState,
141+
CommonTableExpr*parentCTE)
139142
{
140143
ParseState*pstate=make_parsestate(parentParseState);
141144
Query*query;
142145

146+
pstate->p_parent_cte=parentCTE;
147+
143148
query=transformStmt(pstate,parseTree);
144149

145150
free_parsestate(pstate);
@@ -1199,6 +1204,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
11991204
* Recursively transform the components of the tree.
12001205
*/
12011206
sostmt= (SetOperationStmt*)transformSetOperationTree(pstate,stmt,
1207+
true,
12021208
&socolinfo);
12031209
Assert(sostmt&&IsA(sostmt,SetOperationStmt));
12041210
qry->setOperations= (Node*)sostmt;
@@ -1359,7 +1365,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
13591365
*/
13601366
staticNode*
13611367
transformSetOperationTree(ParseState*pstate,SelectStmt*stmt,
1362-
List**colInfo)
1368+
boolisTopLevel,List**colInfo)
13631369
{
13641370
boolisLeaf;
13651371

@@ -1418,7 +1424,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
14181424
* of this sub-query, because they are not in the toplevel pstate's
14191425
* namespace list.
14201426
*/
1421-
selectQuery=parse_sub_analyze((Node*)stmt,pstate);
1427+
selectQuery=parse_sub_analyze((Node*)stmt,pstate,NULL);
14221428

14231429
/*
14241430
* Check for bogus references to Vars on the current query level (but
@@ -1485,11 +1491,28 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
14851491
op->all=stmt->all;
14861492

14871493
/*
1488-
* Recursively transform the childnodes.
1494+
* Recursively transform theleftchildnode.
14891495
*/
14901496
op->larg=transformSetOperationTree(pstate,stmt->larg,
1497+
false,
14911498
&lcolinfo);
1499+
1500+
/*
1501+
* If we are processing a recursive union query, now is the time
1502+
* to examine the non-recursive term's output columns and mark the
1503+
* containing CTE as having those result columns. We should do this
1504+
* only at the topmost setop of the CTE, of course.
1505+
*/
1506+
if (isTopLevel&&
1507+
pstate->p_parent_cte&&
1508+
pstate->p_parent_cte->cterecursive)
1509+
determineRecursiveColTypes(pstate,op->larg,lcolinfo);
1510+
1511+
/*
1512+
* Recursively transform the right child node.
1513+
*/
14921514
op->rarg=transformSetOperationTree(pstate,stmt->rarg,
1515+
false,
14931516
&rcolinfo);
14941517

14951518
/*
@@ -1584,6 +1607,61 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
15841607
}
15851608
}
15861609

1610+
/*
1611+
* Process the outputs of the non-recursive term of a recursive union
1612+
* to set up the parent CTE's columns
1613+
*/
1614+
staticvoid
1615+
determineRecursiveColTypes(ParseState*pstate,Node*larg,List*lcolinfo)
1616+
{
1617+
Node*node;
1618+
intleftmostRTI;
1619+
Query*leftmostQuery;
1620+
List*targetList;
1621+
ListCell*left_tlist;
1622+
ListCell*lci;
1623+
intnext_resno;
1624+
1625+
/*
1626+
* Find leftmost leaf SELECT
1627+
*/
1628+
node=larg;
1629+
while (node&&IsA(node,SetOperationStmt))
1630+
node= ((SetOperationStmt*)node)->larg;
1631+
Assert(node&&IsA(node,RangeTblRef));
1632+
leftmostRTI= ((RangeTblRef*)node)->rtindex;
1633+
leftmostQuery=rt_fetch(leftmostRTI,pstate->p_rtable)->subquery;
1634+
Assert(leftmostQuery!=NULL);
1635+
1636+
/*
1637+
* Generate dummy targetlist using column names of leftmost select
1638+
* and dummy result expressions of the non-recursive term.
1639+
*/
1640+
targetList=NIL;
1641+
left_tlist=list_head(leftmostQuery->targetList);
1642+
next_resno=1;
1643+
1644+
foreach(lci,lcolinfo)
1645+
{
1646+
Expr*lcolexpr= (Expr*)lfirst(lci);
1647+
TargetEntry*lefttle= (TargetEntry*)lfirst(left_tlist);
1648+
char*colName;
1649+
TargetEntry*tle;
1650+
1651+
Assert(!lefttle->resjunk);
1652+
colName=pstrdup(lefttle->resname);
1653+
tle=makeTargetEntry(lcolexpr,
1654+
next_resno++,
1655+
colName,
1656+
false);
1657+
targetList=lappend(targetList,tle);
1658+
left_tlist=lnext(left_tlist);
1659+
}
1660+
1661+
/* Now build CTE's output column info using dummy targetlist */
1662+
analyzeCTETargetList(pstate,pstate->p_parent_cte,targetList);
1663+
}
1664+
15871665
/*
15881666
* Attach column names from a ColumnDef list to a TargetEntry list
15891667
* (for CREATE TABLE AS)

‎src/backend/parser/parse_clause.c‎

Lines changed: 2 additions & 2 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.191 2009/08/27 20:08:02 tgl Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_clause.c,v 1.192 2009/09/09 03:32:52 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -479,7 +479,7 @@ transformRangeSubselect(ParseState *pstate, RangeSubselect *r)
479479
/*
480480
* Analyze and transform the subquery.
481481
*/
482-
query=parse_sub_analyze(r->subquery,pstate);
482+
query=parse_sub_analyze(r->subquery,pstate,NULL);
483483

484484
/*
485485
* Check that we got something reasonable.Many of these conditions are

‎src/backend/parser/parse_cte.c‎

Lines changed: 15 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.6 2009/06/11 14:49:00 momjian Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_cte.c,v 2.7 2009/09/09 03:32:52 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -58,8 +58,6 @@ typedef struct CteItem
5858
{
5959
CommonTableExpr*cte;/* One CTE to examine */
6060
intid;/* Its ID number for dependencies */
61-
Node*non_recursive_term;/* Its nonrecursive part, if
62-
* identified */
6361
Bitmapset*depends_on;/* CTEs depended on (not including self) */
6462
}CteItem;
6563

@@ -80,7 +78,6 @@ typedef struct CteState
8078

8179

8280
staticvoidanalyzeCTE(ParseState*pstate,CommonTableExpr*cte);
83-
staticvoidanalyzeCTETargetList(ParseState*pstate,CommonTableExpr*cte,List*tlist);
8481

8582
/* Dependency processing functions */
8683
staticvoidmakeDependencyGraph(CteState*cstate);
@@ -191,25 +188,6 @@ transformWithClause(ParseState *pstate, WithClause *withClause)
191188
{
192189
CommonTableExpr*cte=cstate.items[i].cte;
193190

194-
/*
195-
* If it's recursive, we have to do a throwaway parse analysis of
196-
* the non-recursive term in order to determine the set of output
197-
* columns for the recursive CTE.
198-
*/
199-
if (cte->cterecursive)
200-
{
201-
Node*nrt;
202-
Query*nrq;
203-
204-
if (!cstate.items[i].non_recursive_term)
205-
elog(ERROR,"could not find non-recursive term for %s",
206-
cte->ctename);
207-
/* copy the term to be sure we don't modify original query */
208-
nrt=copyObject(cstate.items[i].non_recursive_term);
209-
nrq=parse_sub_analyze(nrt,pstate);
210-
analyzeCTETargetList(pstate,cte,nrq->targetList);
211-
}
212-
213191
analyzeCTE(pstate,cte);
214192
}
215193
}
@@ -251,7 +229,7 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
251229
/* Analysis not done already */
252230
Assert(IsA(cte->ctequery,SelectStmt));
253231

254-
query=parse_sub_analyze(cte->ctequery,pstate);
232+
query=parse_sub_analyze(cte->ctequery,pstate,cte);
255233
cte->ctequery= (Node*)query;
256234

257235
/*
@@ -325,14 +303,26 @@ analyzeCTE(ParseState *pstate, CommonTableExpr *cte)
325303

326304
/*
327305
* Compute derived fields of a CTE, given the transformed output targetlist
306+
*
307+
* For a nonrecursive CTE, this is called after transforming the CTE's query.
308+
* For a recursive CTE, we call it after transforming the non-recursive term,
309+
* and pass the targetlist emitted by the non-recursive term only.
310+
*
311+
* Note: in the recursive case, the passed pstate is actually the one being
312+
* used to analyze the CTE's query, so it is one level lower down than in
313+
* the nonrecursive case. This doesn't matter since we only use it for
314+
* error message context anyway.
328315
*/
329-
staticvoid
316+
void
330317
analyzeCTETargetList(ParseState*pstate,CommonTableExpr*cte,List*tlist)
331318
{
332319
intnumaliases;
333320
intvarattno;
334321
ListCell*tlistitem;
335322

323+
/* Not done already ... */
324+
Assert(cte->ctecolnames==NIL);
325+
336326
/*
337327
* We need to determine column names and types. The alias column names
338328
* override anything coming from the query itself.(Note: the SQL spec
@@ -668,11 +658,6 @@ checkWellFormedRecursion(CteState *cstate)
668658
errmsg("FOR UPDATE/SHARE in a recursive query is not implemented"),
669659
parser_errposition(cstate->pstate,
670660
exprLocation((Node*)stmt->lockingClause))));
671-
672-
/*
673-
* Save non_recursive_term.
674-
*/
675-
cstate->items[i].non_recursive_term= (Node*)stmt->larg;
676661
}
677662
}
678663

‎src/backend/parser/parse_expr.c‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.242 2009/07/16 06:33:43 petere Exp $
11+
* $PostgreSQL: pgsql/src/backend/parser/parse_expr.c,v 1.243 2009/09/09 03:32:52 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -1251,7 +1251,7 @@ transformSubLink(ParseState *pstate, SubLink *sublink)
12511251
returnresult;
12521252

12531253
pstate->p_hasSubLinks= true;
1254-
qtree=parse_sub_analyze(sublink->subselect,pstate);
1254+
qtree=parse_sub_analyze(sublink->subselect,pstate,NULL);
12551255

12561256
/*
12571257
* Check that we got something reasonable.Many of these conditions are

‎src/include/parser/analyze.h‎

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.40 2009/01/01 17:24:00 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/parser/analyze.h,v 1.41 2009/09/09 03:32:52 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -22,7 +22,8 @@ extern Query *parse_analyze(Node *parseTree, const char *sourceText,
2222
externQuery*parse_analyze_varparams(Node*parseTree,constchar*sourceText,
2323
Oid**paramTypes,int*numParams);
2424

25-
externQuery*parse_sub_analyze(Node*parseTree,ParseState*parentParseState);
25+
externQuery*parse_sub_analyze(Node*parseTree,ParseState*parentParseState,
26+
CommonTableExpr*parentCTE);
2627
externQuery*transformStmt(ParseState*pstate,Node*parseTree);
2728

2829
externboolanalyze_requires_snapshot(Node*parseTree);

‎src/include/parser/parse_cte.h‎

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/parser/parse_cte.h,v 1.2 2009/01/01 17:24:00 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/parser/parse_cte.h,v 1.3 2009/09/09 03:32:52 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -18,4 +18,7 @@
1818

1919
externList*transformWithClause(ParseState*pstate,WithClause*withClause);
2020

21+
externvoidanalyzeCTETargetList(ParseState*pstate,CommonTableExpr*cte,
22+
List*tlist);
23+
2124
#endif/* PARSE_CTE_H */

‎src/include/parser/parse_node.h‎

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
* Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.62 2009/06/11 14:49:11 momjian Exp $
10+
* $PostgreSQL: pgsql/src/include/parser/parse_node.h,v 1.63 2009/09/09 03:32:52 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
@@ -61,6 +61,9 @@
6161
* p_future_ctes: list of CommonTableExprs (WITH items) that are not yet
6262
* visible due to scope rules.This is used to help improve error messages.
6363
*
64+
* p_parent_cte: CommonTableExpr that immediately contains the current query,
65+
* if any.
66+
*
6467
* p_windowdefs: list of WindowDefs representing WINDOW and OVER clauses.
6568
* We collect these while transforming expressions and then transform them
6669
* afterwards (so that any resjunk tlist items needed for the sort/group
@@ -88,6 +91,7 @@ typedef struct ParseState
8891
List*p_varnamespace;/* current namespace for columns */
8992
List*p_ctenamespace;/* current namespace for common table exprs */
9093
List*p_future_ctes;/* common table exprs not yet in namespace */
94+
CommonTableExpr*p_parent_cte;/* this query's containing CTE */
9195
List*p_windowdefs;/* raw representations of window clauses */
9296
Oid*p_paramtypes;/* OIDs of types for $n parameter symbols */
9397
intp_numparams;/* allocated size of p_paramtypes[] */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp