@ -17,7 +17,7 @@
* Portions Copyright ( c ) 1996 - 2009 , PostgreSQL Global Development Group
* Portions Copyright ( c ) 1994 , Regents of the University of California
*
* $ PostgreSQL : pgsql / src / backend / parser / analyze . c , v 1.390 2009 / 08 / 27 20 : 08 : 0 2 tgl Exp $
* $ PostgreSQL : pgsql / src / backend / parser / analyze . c , v 1.391 2009 / 09 / 09 03 : 32 : 5 2 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -50,7 +50,9 @@ static Query *transformSelectStmt(ParseState *pstate, SelectStmt *stmt);
static Query * transformValuesClause ( ParseState * pstate , SelectStmt * stmt ) ;
static Query * transformSetOperationStmt ( ParseState * pstate , SelectStmt * stmt ) ;
static Node * transformSetOperationTree ( ParseState * pstate , SelectStmt * stmt ,
List * * colInfo ) ;
bool isTopLevel , List * * colInfo ) ;
static void determineRecursiveColTypes ( ParseState * pstate ,
Node * larg , List * lcolinfo ) ;
static void applyColumnNames ( List * dst , List * src ) ;
static Query * transformUpdateStmt ( ParseState * pstate , UpdateStmt * stmt ) ;
static List * transformReturningList ( ParseState * pstate , List * returningList ) ;
@ -135,11 +137,14 @@ parse_analyze_varparams(Node *parseTree, const char *sourceText,
* Entry point for recursively analyzing a sub - statement .
*/
Query *
parse_sub_analyze ( Node * parseTree , ParseState * parentParseState )
parse_sub_analyze ( Node * parseTree , ParseState * parentParseState ,
CommonTableExpr * parentCTE )
{
ParseState * pstate = make_parsestate ( parentParseState ) ;
Query * query ;
pstate - > p_parent_cte = parentCTE ;
query = transformStmt ( pstate , parseTree ) ;
free_parsestate ( pstate ) ;
@ -1199,6 +1204,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
* Recursively transform the components of the tree .
*/
sostmt = ( SetOperationStmt * ) transformSetOperationTree ( pstate , stmt ,
true ,
& socolinfo ) ;
Assert ( sostmt & & IsA ( sostmt , SetOperationStmt ) ) ;
qry - > setOperations = ( Node * ) sostmt ;
@ -1359,7 +1365,7 @@ transformSetOperationStmt(ParseState *pstate, SelectStmt *stmt)
*/
static Node *
transformSetOperationTree ( ParseState * pstate , SelectStmt * stmt ,
List * * colInfo )
bool isTopLevel , List * * colInfo )
{
bool isLeaf ;
@ -1418,7 +1424,7 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
* of this sub - query , because they are not in the toplevel pstate ' s
* namespace list .
*/
selectQuery = parse_sub_analyze ( ( Node * ) stmt , pstate ) ;
selectQuery = parse_sub_analyze ( ( Node * ) stmt , pstate , NULL ) ;
/*
* Check for bogus references to Vars on the current query level ( but
@ -1485,11 +1491,28 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
op - > all = stmt - > all ;
/*
* Recursively transform the child nodes .
* Recursively transform the left child node .
*/
op - > larg = transformSetOperationTree ( pstate , stmt - > larg ,
false ,
& lcolinfo ) ;
/*
* If we are processing a recursive union query , now is the time
* to examine the non - recursive term ' s output columns and mark the
* containing CTE as having those result columns . We should do this
* only at the topmost setop of the CTE , of course .
*/
if ( isTopLevel & &
pstate - > p_parent_cte & &
pstate - > p_parent_cte - > cterecursive )
determineRecursiveColTypes ( pstate , op - > larg , lcolinfo ) ;
/*
* Recursively transform the right child node .
*/
op - > rarg = transformSetOperationTree ( pstate , stmt - > rarg ,
false ,
& rcolinfo ) ;
/*
@ -1584,6 +1607,61 @@ transformSetOperationTree(ParseState *pstate, SelectStmt *stmt,
}
}
/*
* Process the outputs of the non - recursive term of a recursive union
* to set up the parent CTE ' s columns
*/
static void
determineRecursiveColTypes ( ParseState * pstate , Node * larg , List * lcolinfo )
{
Node * node ;
int leftmostRTI ;
Query * leftmostQuery ;
List * targetList ;
ListCell * left_tlist ;
ListCell * lci ;
int next_resno ;
/*
* Find leftmost leaf SELECT
*/
node = larg ;
while ( node & & IsA ( node , SetOperationStmt ) )
node = ( ( SetOperationStmt * ) node ) - > larg ;
Assert ( node & & IsA ( node , RangeTblRef ) ) ;
leftmostRTI = ( ( RangeTblRef * ) node ) - > rtindex ;
leftmostQuery = rt_fetch ( leftmostRTI , pstate - > p_rtable ) - > subquery ;
Assert ( leftmostQuery ! = NULL ) ;
/*
* Generate dummy targetlist using column names of leftmost select
* and dummy result expressions of the non - recursive term .
*/
targetList = NIL ;
left_tlist = list_head ( leftmostQuery - > targetList ) ;
next_resno = 1 ;
foreach ( lci , lcolinfo )
{
Expr * lcolexpr = ( Expr * ) lfirst ( lci ) ;
TargetEntry * lefttle = ( TargetEntry * ) lfirst ( left_tlist ) ;
char * colName ;
TargetEntry * tle ;
Assert ( ! lefttle - > resjunk ) ;
colName = pstrdup ( lefttle - > resname ) ;
tle = makeTargetEntry ( lcolexpr ,
next_resno + + ,
colName ,
false ) ;
targetList = lappend ( targetList , tle ) ;
left_tlist = lnext ( left_tlist ) ;
}
/* Now build CTE's output column info using dummy targetlist */
analyzeCTETargetList ( pstate , pstate - > p_parent_cte , targetList ) ;
}
/*
* Attach column names from a ColumnDef list to a TargetEntry list
* ( for CREATE TABLE AS )