@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
* $ Header : / cvsroot / pgsql / src / backend / optimizer / prep / prepunion . c , v 1.69 2001 / 11 / 12 20 : 04 : 20 tgl Exp $
* $ Header : / cvsroot / pgsql / src / backend / optimizer / prep / prepunion . c , v 1.69 .2 .1 2002 / 03 / 05 05 : 13 : 36 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -63,7 +63,9 @@ static List *generate_setop_tlist(List *colTypes, int flag,
bool hack_constants ,
List * input_tlist ,
List * refnames_tlist ) ;
static void merge_tlist_typmods ( List * tlist , List * planlist ) ;
static List * generate_append_tlist ( List * colTypes , bool flag ,
List * input_plans ,
List * refnames_tlist ) ;
static bool tlist_same_datatypes ( List * tlist , List * colTypes , bool junkOK ) ;
static Node * adjust_inherited_attrs_mutator ( Node * node ,
adjust_inherited_attrs_context * context ) ;
@ -169,13 +171,11 @@ recurse_set_operations(Node *setOp, Query *parse,
*
* XXX you don ' t really want to know about this : setrefs . c will apply
* replace_vars_with_subplan_refs ( ) to the Result node ' s tlist .
* This would fail if the input plan ' s non - resjunk tlist entries
* were not all simple Vars equal ( ) to the referencing Vars
* generated by generate_setop_tlist ( ) . However , since the input
* plan was generated by generate_union_plan ( ) or
* generate_nonunion_plan ( ) , the referencing Vars will equal the
* tlist entries they reference . Ugly but I don ' t feel like making
* that code more general right now .
* This would fail if the Vars generated by generate_setop_tlist ( )
* were not exactly equal ( ) to the corresponding tlist entries of
* the subplan . However , since the subplan was generated by
* generate_union_plan ( ) or generate_nonunion_plan ( ) , and hence its
* tlist was generated by generate_append_tlist ( ) , this will work .
*/
if ( flag > = 0 | |
! tlist_same_datatypes ( plan - > targetlist , colTypes , junkOK ) )
@ -226,10 +226,8 @@ generate_union_plan(SetOperationStmt *op, Query *parse,
* concerned , but we must make it look real anyway for the benefit of
* the next plan level up .
*/
tlist = generate_setop_tlist ( op - > colTypes , - 1 , false ,
( ( Plan * ) lfirst ( planlist ) ) - > targetlist ,
refnames_tlist ) ;
merge_tlist_typmods ( tlist , planlist ) ;
tlist = generate_append_tlist ( op - > colTypes , false ,
planlist , refnames_tlist ) ;
/*
* Append the child results together .
@ -285,10 +283,8 @@ generate_nonunion_plan(SetOperationStmt *op, Query *parse,
* flag column is shown as a variable not a constant , else setrefs . c
* will get confused .
*/
tlist = generate_setop_tlist ( op - > colTypes , 2 , false ,
lplan - > targetlist ,
refnames_tlist ) ;
merge_tlist_typmods ( tlist , planlist ) ;
tlist = generate_append_tlist ( op - > colTypes , true ,
planlist , refnames_tlist ) ;
/*
* Append the child results together .
@ -368,8 +364,7 @@ recurse_union_children(Node *setOp, Query *parse,
* Generate targetlist for a set - operation plan node
*
* colTypes : column datatypes for non - junk columns
* flag : - 1 if no flag column needed , 0 or 1 to create a const flag column ,
* 2 to create a variable flag column
* flag : - 1 if no flag column needed , 0 or 1 to create a const flag column
* hack_constants : true to copy up constants ( see comments in code )
* input_tlist : targetlist of this node ' s input node
* refnames_tlist : targetlist to take column names from
@ -450,8 +445,6 @@ generate_setop_tlist(List *colTypes, int flag,
- 1 ,
pstrdup ( " flag " ) ,
true ) ;
if ( flag < = 1 )
{
/* flag value is the given constant */
expr = ( Node * ) makeConst ( INT4OID ,
sizeof ( int4 ) ,
@ -460,16 +453,6 @@ generate_setop_tlist(List *colTypes, int flag,
true ,
false ,
false ) ;
}
else
{
/* flag value is being copied up from subplan */
expr = ( Node * ) makeVar ( 0 ,
resdom - > resno ,
INT4OID ,
- 1 ,
0 ) ;
}
tlist = lappend ( tlist , makeTargetEntry ( resdom , expr ) ) ;
}
@ -477,44 +460,117 @@ generate_setop_tlist(List *colTypes, int flag,
}
/*
* Merge typmods of a list of set - operation subplans .
* Generate targetlist for a set - operation Append node
*
* If the inputs all agree on type and typmod of a particular column ,
* use that typmod ; else use - 1. We assume the result tlist has been
* initialized with the types and typmods of the first input subplan .
* colTypes : column datatypes for non - junk columns
* flag : true to create a flag column copied up from subplans
* input_plans : list of sub - plans of the Append
* refnames_tlist : targetlist to take column names from
*
* The entries in the Append ' s targetlist should always be simple Vars ;
* we just have to make sure they have the right datatypes and typmods .
*/
static void
merge_tlist_typmods ( List * tlist , List * planlist )
static List *
generate_append_tlist ( List * colTypes , bool flag ,
List * input_plans ,
List * refnames_tlist )
{
List * tlist = NIL ;
int resno = 1 ;
List * curColType ;
int colindex ;
Resdom * resdom ;
Node * expr ;
List * planl ;
int32 * colTypmods ;
foreach ( planl , planlist )
/*
* First extract typmods to use .
*
* If the inputs all agree on type and typmod of a particular column ,
* use that typmod ; else use - 1.
*/
colTypmods = ( int32 * ) palloc ( length ( colTypes ) * sizeof ( int32 ) ) ;
foreach ( planl , input_plans )
{
Plan * subplan = ( Plan * ) lfirst ( planl ) ;
List * subtlist = subplan - > targetlist ;
List * restlist ;
List * subtlist ;
foreach ( restlist , tlist )
curColType = colTypes ;
colindex = 0 ;
foreach ( subtlist , subplan - > targetlist )
{
TargetEntry * restle = ( TargetEntry * ) lfirst ( restlist ) ;
TargetEntry * subtle ;
TargetEntry * subtle = ( TargetEntry * ) lfirst ( subtlist ) ;
if ( re stle- > resdom - > resjunk )
if ( sub tle - > resdom - > resjunk )
continue ;
Assert ( subtlist ! = NIL ) ;
subtle = ( TargetEntry * ) lfirst ( subtlist ) ;
while ( subtle - > resdom - > resjunk )
Assert ( curColType ! = NIL ) ;
if ( subtle - > resdom - > restype = = ( Oid ) lfirsti ( curColType ) )
{
/* If first subplan, copy the typmod; else compare */
if ( planl = = input_plans )
colTypmods [ colindex ] = subtle - > resdom - > restypmod ;
else if ( subtle - > resdom - > restypmod ! = colTypmods [ colindex ] )
colTypmods [ colindex ] = - 1 ;
}
else
{
subtlist = lnext ( subtlist ) ;
Assert ( subtlist ! = NIL ) ;
subtle = ( TargetEntry * ) lfirst ( subtlist ) ;
/* types disagree, so force typmod to -1 */
colTypmods [ colindex ] = - 1 ;
}
if ( restle - > resdom - > restype ! = subtle - > resdom - > restype | |
restle - > resdom - > restypmod ! = subtle - > resdom - > restypmod )
restle - > resdom - > restypmod = - 1 ;
subtlist = lnext ( subtlist ) ;
curColType = lnext ( curColType ) ;
colindex + + ;
}
Assert ( curColType = = NIL ) ;
}
/*
* Now we can build the tlist for the Append .
*/
colindex = 0 ;
foreach ( curColType , colTypes )
{
Oid colType = ( Oid ) lfirsti ( curColType ) ;
int32 colTypmod = colTypmods [ colindex + + ] ;
TargetEntry * reftle = ( TargetEntry * ) lfirst ( refnames_tlist ) ;
Assert ( reftle - > resdom - > resno = = resno ) ;
Assert ( ! reftle - > resdom - > resjunk ) ;
expr = ( Node * ) makeVar ( 0 ,
resno ,
colType ,
colTypmod ,
0 ) ;
resdom = makeResdom ( ( AttrNumber ) resno + + ,
colType ,
colTypmod ,
pstrdup ( reftle - > resdom - > resname ) ,
false ) ;
tlist = lappend ( tlist , makeTargetEntry ( resdom , expr ) ) ;
refnames_tlist = lnext ( refnames_tlist ) ;
}
if ( flag )
{
/* Add a resjunk flag column */
resdom = makeResdom ( ( AttrNumber ) resno + + ,
INT4OID ,
- 1 ,
pstrdup ( " flag " ) ,
true ) ;
/* flag value is shown as copied up from subplan */
expr = ( Node * ) makeVar ( 0 ,
resdom - > resno ,
INT4OID ,
- 1 ,
0 ) ;
tlist = lappend ( tlist , makeTargetEntry ( resdom , expr ) ) ;
}
pfree ( colTypmods ) ;
return tlist ;
}
/*