@ -5,8 +5,12 @@
* from a time when only UNIONs were implemented .
*
* There is also some code here to support planning of queries that use
* inheritance ( SELECT FROM foo * ) . This no longer has much connection
* to the processing of UNION queries , but it ' s still here .
* inheritance ( SELECT FROM foo * ) . Although inheritance is radically
* different from set operations as far as the parser representation of
* a query is concerned , we try to handle it identically to the UNION ALL
* case during planning : both are converted to " append rels " . ( Note that
* UNION ALL is special - cased : other kinds of set operations go through
* a completely different code path . )
*
*
* Portions Copyright ( c ) 1996 - 2005 , PostgreSQL Global Development Group
@ -14,7 +18,7 @@
*
*
* IDENTIFICATION
* $ PostgreSQL : pgsql / src / backend / optimizer / prep / prepunion . c , v 1.128 2005 / 11 / 22 18 : 17 : 14 momjian Exp $
* $ PostgreSQL : pgsql / src / backend / optimizer / prep / prepunion . c , v 1.129 2006 / 01 / 31 21 : 39 : 24 tgl Exp $
*
* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
*/
@ -38,18 +42,6 @@
# include "utils/lsyscache.h"
typedef struct
{
Index old_rt_index ;
Index new_rt_index ;
Oid old_rel_type ;
Oid new_rel_type ;
TupleDesc old_tupdesc ;
TupleDesc new_tupdesc ;
char * old_rel_name ;
char * new_rel_name ;
} adjust_inherited_attrs_context ;
static Plan * recurse_set_operations ( Node * setOp , PlannerInfo * root ,
double tuple_fraction ,
List * colTypes , bool junkOK ,
@ -73,11 +65,16 @@ 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 ) ;
static void expand_inherited_rtentry ( PlannerInfo * root , RangeTblEntry * rte ,
Index rti ) ;
static void make_translation_lists ( Relation oldrelation , Relation newrelation ,
Index newvarno ,
List * * col_mappings , List * * translated_vars ) ;
static Node * adjust_appendrel_attrs_mutator ( Node * node ,
AppendRelInfo * context ) ;
static Relids adjust_relid_set ( Relids relids , Index oldrelid , Index newrelid ) ;
static List * adjust_inherited_tlist ( List * tlist ,
adjust_inherited_attrs_context * context ) ;
AppendRelInfo * context ) ;
/*
@ -739,51 +736,81 @@ find_all_inheritors(Oid parentrel)
return rels_list ;
}
/*
* expand_inherited_tables
* Expand each rangetable entry that represents an inheritance set
* into an " append relation " . At the conclusion of this process ,
* the " inh " flag is set in all and only those RTEs that are append
* relation parents .
*/
void
expand_inherited_tables ( PlannerInfo * root )
{
Index nrtes ;
Index rti ;
ListCell * rl ;
/*
* expand_inherited_rtentry may add RTEs to parse - > rtable ; there is
* no need to scan them since they can ' t have inh = true . So just
* scan as far as the original end of the rtable list .
*/
nrtes = list_length ( root - > parse - > rtable ) ;
rl = list_head ( root - > parse - > rtable ) ;
for ( rti = 1 ; rti < = nrtes ; rti + + )
{
RangeTblEntry * rte = ( RangeTblEntry * ) lfirst ( rl ) ;
expand_inherited_rtentry ( root , rte , rti ) ;
rl = lnext ( rl ) ;
}
}
/*
* expand_inherited_rtentry
* Check whether a rangetable entry represents an inheritance set .
* If so , add entries for all the child tables to the query ' s
* rangetable , and return an integer list of RT indexes for the
* whole inheritance set ( parent and children ) .
* If not , return NIL .
* rangetable , and build AppendRelInfo nodes for all the child tables
* and add them to root - > append_rel_list . If not , clear the entry ' s
* " inh " flag to prevent later code from looking for AppendRelInfos .
*
* Note that the original RTE is considered to represent the whole
* inheritance set . The first member of the returned list is an RTE
* for the same table , but with inh = false , to represent the parent table
* in its role as a simple member of the set . The original RT index is
* never a member of the returned list .
* inheritance set . The first of the generated RTEs is an RTE for the same
* table , but with inh = false , to represent the parent table in its role
* as a simple member of the inheritance set .
*
* A childless table is never considered to be an inheritance set ; therefore
* the result will never be a one - element list . It ' ll be either empty
* or have two or more elements .
*
* Note : there are cases in which this routine will be invoked multiple
* times on the same RTE . We will generate a separate set of child RTEs
* for each invocation . This is somewhat wasteful but seems not worth
* trying to avoid .
* a parent RTE must always have at least two associated AppendRelInfos .
*/
List *
expand_inherited_rtentry ( PlannerInfo * root , Index rti )
static void
expand_inherited_rtentry ( PlannerInfo * root , RangeTblEntry * rte , Index rti )
{
Query * parse = root - > parse ;
RangeTblEntry * rte = rt_fetch ( rti , parse - > rtable ) ;
Oid parentOID ;
Relation oldrelation ;
LOCKMODE lockmode ;
List * inhOIDs ;
List * inhRTIs ;
List * appinfo s;
ListCell * l ;
/* Does RT entry allow inheritance? */
if ( ! rte - > inh )
return NIL ;
Assert ( rte - > rtekind = = RTE_RELATION ) ;
return ;
/* Ignore any already-expanded UNION ALL nodes */
if ( rte - > rtekind ! = RTE_RELATION )
{
Assert ( rte - > rtekind = = RTE_SUBQUERY ) ;
return ;
}
/* Fast path for common case of childless table */
parentOID = rte - > relid ;
if ( ! has_subclass ( parentOID ) )
{
/* Clear flag to save repeated tests if called again */
/* Clear flag before returning */
rte - > inh = false ;
return NIL ;
return ;
}
/* Scan for all members of inheritance set */
inhOIDs = find_all_inheritors ( parentOID ) ;
@ -794,18 +821,45 @@ expand_inherited_rtentry(PlannerInfo *root, Index rti)
*/
if ( list_length ( inhOIDs ) < 2 )
{
/* Clear flag to save repeated tests if called again */
/* Clear flag before returning */
rte - > inh = false ;
return NIL ;
return ;
}
/* OK, it's an inheritance set; expand it */
inhRTIs = NIL ;
/*
* Must open the parent relation to examine its tupdesc . We need not
* lock it since the rewriter already obtained at least AccessShareLock
* on each relation used in the query .
*/
oldrelation = heap_open ( parentOID , NoLock ) ;
/*
* However , for each child relation we add to the query , we must obtain
* an appropriate lock , because this will be the first use of those
* relations in the parse / rewrite / plan pipeline .
*
* If the parent relation is the query ' s result relation , then we need
* RowExclusiveLock . Otherwise , check to see if the relation is accessed
* FOR UPDATE / SHARE or not . We can ' t just grab AccessShareLock because
* then the executor would be trying to upgrade the lock , leading to
* possible deadlocks . ( This code should match the parser and rewriter . )
*/
if ( rti = = parse - > resultRelation )
lockmode = RowExclusiveLock ;
else if ( list_member_int ( parse - > rowMarks , rti ) )
lockmode = RowShareLock ;
else
lockmode = AccessShareLock ;
/* Scan the inheritance set and expand it */
appinfos = NIL ;
foreach ( l , inhOIDs )
{
Oid childOID = lfirst_oid ( l ) ;
Relation newrelation ;
RangeTblEntry * childrte ;
Index childRTindex ;
AppendRelInfo * appinfo ;
/*
* It is possible that the parent table has children that are temp
@ -817,6 +871,12 @@ expand_inherited_rtentry(PlannerInfo *root, Index rti)
isOtherTempNamespace ( get_rel_namespace ( childOID ) ) )
continue ;
/* Open rel, acquire the appropriate lock type */
if ( childOID ! = parentOID )
newrelation = heap_open ( childOID , lockmode ) ;
else
newrelation = oldrelation ;
/*
* Build an RTE for the child , and attach to query ' s rangetable list .
* We copy most fields of the parent ' s RTE , but replace relation OID ,
@ -827,75 +887,160 @@ expand_inherited_rtentry(PlannerInfo *root, Index rti)
childrte - > inh = false ;
parse - > rtable = lappend ( parse - > rtable , childrte ) ;
childRTindex = list_length ( parse - > rtable ) ;
inhRTIs = lappend_int ( inhRTIs , childRTindex ) ;
/*
* Build an AppendRelInfo for this parent and child .
*/
appinfo = makeNode ( AppendRelInfo ) ;
appinfo - > parent_relid = rti ;
appinfo - > child_relid = childRTindex ;
appinfo - > parent_reltype = oldrelation - > rd_rel - > reltype ;
appinfo - > child_reltype = newrelation - > rd_rel - > reltype ;
make_translation_lists ( oldrelation , newrelation , childRTindex ,
& appinfo - > col_mappings ,
& appinfo - > translated_vars ) ;
appinfo - > parent_reloid = parentOID ;
appinfos = lappend ( appinfos , appinfo ) ;
/* Close child relations, but keep locks */
if ( childOID ! = parentOID )
heap_close ( newrelation , NoLock ) ;
}
heap_close ( oldrelation , NoLock ) ;
/*
* If all the children were temp tables , pretend it ' s a non - inheritance
* situation . The duplicate RTE we added for the parent table is
* harmless .
* harmless , so we don ' t bother to get rid of it .
*/
if ( list_length ( inhRTIs ) < 2 )
if ( list_length ( appinfo s) < 2 )
{
/* Clear flag to save repeated tests if called again */
/* Clear flag before returning */
rte - > inh = false ;
return NIL ;
return ;
}
/* Otherwise, OK to add to root->append_rel_list */
root - > append_rel_list = list_concat ( root - > append_rel_list , appinfos ) ;
/*
* The executor will check the parent table ' s access permissions when it
* examines the parent ' s inheritlist entry . There ' s no need to check
* twice , so turn off access check bits in the original RTE . ( If we are
* invoked more than once , extra copies of the child RTEs will also not
* cause duplicate permission checks . )
* examines the parent ' s added RTE entry . There ' s no need to check
* twice , so turn off access check bits in the original RTE .
*/
rte - > requiredPerms = 0 ;
}
/*
* make_translation_lists
* Build the lists of translations from parent Vars to child Vars for
* an inheritance child . We need both a column number mapping list
* and a list of Vars representing the child columns .
*
* For paranoia ' s sake , we match type as well as attribute name .
*/
static void
make_translation_lists ( Relation oldrelation , Relation newrelation ,
Index newvarno ,
List * * col_mappings , List * * translated_vars )
{
List * numbers = NIL ;
List * vars = NIL ;
TupleDesc old_tupdesc = RelationGetDescr ( oldrelation ) ;
TupleDesc new_tupdesc = RelationGetDescr ( newrelation ) ;
int oldnatts = old_tupdesc - > natts ;
int newnatts = new_tupdesc - > natts ;
int old_attno ;
for ( old_attno = 0 ; old_attno < oldnatts ; old_attno + + )
{
Form_pg_attribute att ;
char * attname ;
Oid atttypid ;
int32 atttypmod ;
int new_attno ;
att = old_tupdesc - > attrs [ old_attno ] ;
if ( att - > attisdropped )
{
/* Just put 0/NULL into this list entry */
numbers = lappend_int ( numbers , 0 ) ;
vars = lappend ( vars , NULL ) ;
continue ;
}
attname = NameStr ( att - > attname ) ;
atttypid = att - > atttypid ;
atttypmod = att - > atttypmod ;
return inhRTIs ;
/*
* When we are generating the " translation list " for the parent
* table of an inheritance set , no need to search for matches .
*/
if ( oldrelation = = newrelation )
{
numbers = lappend_int ( numbers , old_attno + 1 ) ;
vars = lappend ( vars , makeVar ( newvarno ,
( AttrNumber ) ( old_attno + 1 ) ,
atttypid ,
atttypmod ,
0 ) ) ;
continue ;
}
/*
* Otherwise we have to search for the matching column by name .
* There ' s no guarantee it ' ll have the same column position ,
* because of cases like ALTER TABLE ADD COLUMN and multiple
* inheritance .
*/
for ( new_attno = 0 ; new_attno < newnatts ; new_attno + + )
{
att = new_tupdesc - > attrs [ new_attno ] ;
if ( att - > attisdropped | | att - > attinhcount = = 0 )
continue ;
if ( strcmp ( attname , NameStr ( att - > attname ) ) ! = 0 )
continue ;
/* Found it, check type */
if ( atttypid ! = att - > atttypid | | atttypmod ! = att - > atttypmod )
elog ( ERROR , " attribute \" %s \" of relation \" %s \" does not match parent's type " ,
attname , RelationGetRelationName ( newrelation ) ) ;
numbers = lappend_int ( numbers , new_attno + 1 ) ;
vars = lappend ( vars , makeVar ( newvarno ,
( AttrNumber ) ( new_attno + 1 ) ,
atttypid ,
atttypmod ,
0 ) ) ;
break ;
}
if ( new_attno > = newnatts )
elog ( ERROR , " could not find inherited attribute \" %s \" of relation \" %s \" " ,
attname , RelationGetRelationName ( newrelation ) ) ;
}
* col_mappings = numbers ;
* translated_vars = vars ;
}
/*
* adjust_inherited_attrs
* adjust_appendrel _attrs
* Copy the specified query or expression and translate Vars referring
* to old_rt_index to refer to new_rt_index .
* to the parent rel of the specified AppendRelInfo to refer to the
* child rel instead . We also update rtindexes appearing outside Vars ,
* such as resultRelation and jointree relids .
*
* We also adjust varattno to match the new table by column name , rather
* than column number . This hack makes it possible for child tables to have
* different column positions for the " same " attribute as a parent , which
* is necessary for ALTER TABLE ADD COLUMN .
* Note : this is only applied after conversion of sublinks to subplans ,
* so we don ' t need to cope with recursion into sub - queries .
*
* Note : this is not hugely different from what ResolveNew ( ) does ; maybe
* we should try to fold the two routines together .
*/
Node *
adjust_inherited_attrs ( Node * node ,
Index old_rt_index , Oid old_relid ,
Index new_rt_index , Oid new_relid )
adjust_appendrel_attrs ( Node * node , AppendRelInfo * appinfo )
{
Node * result ;
adjust_inherited_attrs_context context ;
Relation oldrelation ;
Relation newrelation ;
/* Handle simple case simply... */
if ( old_rt_index = = new_rt_index )
{
Assert ( old_relid = = new_relid ) ;
return copyObject ( node ) ;
}
/*
* We assume that by now the planner has acquired at least AccessShareLock
* on both rels , and so we need no additional lock now .
*/
oldrelation = heap_open ( old_relid , NoLock ) ;
newrelation = heap_open ( new_relid , NoLock ) ;
context . old_rt_index = old_rt_index ;
context . new_rt_index = new_rt_index ;
context . old_rel_type = oldrelation - > rd_rel - > reltype ;
context . new_rel_type = newrelation - > rd_rel - > reltype ;
context . old_tupdesc = RelationGetDescr ( oldrelation ) ;
context . new_tupdesc = RelationGetDescr ( newrelation ) ;
context . old_rel_name = RelationGetRelationName ( oldrelation ) ;
context . new_rel_name = RelationGetRelationName ( newrelation ) ;
/*
* Must be prepared to start with a Query or a bare expression tree .
@ -905,80 +1050,28 @@ adjust_inherited_attrs(Node *node,
Query * newnode ;
newnode = query_tree_mutator ( ( Query * ) node ,
adjust_inherited _attrs_mutator ,
( void * ) & context ,
adjust_appendrel _attrs_mutator ,
( void * ) appinfo ,
QTW_IGNORE_RT_SUBQUERIES ) ;
if ( newnode - > resultRelation = = old_rt_index )
if ( newnode - > resultRelation = = appinfo - > parent_relid )
{
newnode - > resultRelation = new_rt_index ;
newnode - > resultRelation = appinfo - > child_relid ;
/* Fix tlist resnos too, if it's inherited UPDATE */
if ( newnode - > commandType = = CMD_UPDATE )
newnode - > targetList =
adjust_inherited_tlist ( newnode - > targetList ,
& context ) ;
appinfo ) ;
}
result = ( Node * ) newnode ;
}
else
result = adjust_inherited_attrs_mutator ( node , & context ) ;
heap_close ( oldrelation , NoLock ) ;
heap_close ( newrelation , NoLock ) ;
result = adjust_appendrel_attrs_mutator ( node , appinfo ) ;
return result ;
}
/*
* Translate parent ' s attribute number into child ' s .
*
* For paranoia ' s sake , we match type as well as attribute name .
*/
static AttrNumber
translate_inherited_attnum ( AttrNumber old_attno ,
adjust_inherited_attrs_context * context )
{
Form_pg_attribute att ;
char * attname ;
Oid atttypid ;
int32 atttypmod ;
int newnatts ;
int i ;
if ( old_attno < = 0 | | old_attno > context - > old_tupdesc - > natts )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
( int ) old_attno , context - > old_rel_name ) ;
att = context - > old_tupdesc - > attrs [ old_attno - 1 ] ;
if ( att - > attisdropped )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
( int ) old_attno , context - > old_rel_name ) ;
attname = NameStr ( att - > attname ) ;
atttypid = att - > atttypid ;
atttypmod = att - > atttypmod ;
newnatts = context - > new_tupdesc - > natts ;
for ( i = 0 ; i < newnatts ; i + + )
{
att = context - > new_tupdesc - > attrs [ i ] ;
if ( att - > attisdropped )
continue ;
if ( strcmp ( attname , NameStr ( att - > attname ) ) = = 0 )
{
/* Found it, check type */
if ( atttypid ! = att - > atttypid | | atttypmod ! = att - > atttypmod )
elog ( ERROR , " attribute \" %s \" of relation \" %s \" does not match parent's type " ,
attname , context - > new_rel_name ) ;
return ( AttrNumber ) ( i + 1 ) ;
}
}
elog ( ERROR , " attribute \" %s \" of relation \" %s \" does not exist " ,
attname , context - > new_rel_name ) ;
return 0 ; /* keep compiler quiet */
}
static Node *
adjust_inherited_attrs_mutator ( Node * node ,
adjust_inherited_attrs_context * context )
adjust_appendrel_attrs_mutator ( Node * node , AppendRelInfo * context )
{
if ( node = = NULL )
return NULL ;
@ -987,36 +1080,54 @@ adjust_inherited_attrs_mutator(Node *node,
Var * var = ( Var * ) copyObject ( node ) ;
if ( var - > varlevelsup = = 0 & &
var - > varno = = context - > old_rt_index )
var - > varno = = context - > parent_relid )
{
var - > varno = context - > new_rt_index ;
var - > varnoold = context - > new_rt_index ;
var - > varno = context - > child_relid ;
var - > varnoold = context - > child_relid ;
if ( var - > varattno > 0 )
{
var - > varattno = translate_inherited_attnum ( var - > varattno ,
context ) ;
var - > varoattno = var - > varattno ;
Node * newnode ;
if ( var - > varattno > list_length ( context - > translated_vars ) )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
var - > varattno , get_rel_name ( context - > parent_reloid ) ) ;
newnode = copyObject ( list_nth ( context - > translated_vars ,
var - > varattno - 1 ) ) ;
if ( newnode = = NULL )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
var - > varattno , get_rel_name ( context - > parent_reloid ) ) ;
return newnode ;
}
else if ( var - > varattno = = 0 )
{
/*
* Whole - row Var : we need to insert a coercion step to convert
* the tuple layout to the parent ' s rowtype .
* Whole - row Var : if we are dealing with named rowtypes ,
* we can use a whole - row Var for the child table plus a
* coercion step to convert the tuple layout to the parent ' s
* rowtype . Otherwise we have to generate a RowExpr .
*/
if ( context - > old_rel_type ! = context - > new_rel_type )
if ( OidIsValid ( context - > child_reltype ) )
{
ConvertRowtypeExpr * r = makeNode ( ConvertRowtypeExpr ) ;
r - > arg = ( Expr * ) var ;
r - > resulttype = context - > old_rel_type ;
r - > convertformat = COERCE_IMPLICIT_CAST ;
/* Make sure the Var node has the right type ID, too */
Assert ( var - > vartype = = context - > old_rel_type ) ;
var - > vartype = context - > new_rel_type ;
return ( Node * ) r ;
Assert ( var - > vartype = = context - > parent_reltype ) ;
if ( context - > parent_reltype ! = context - > child_reltype )
{
ConvertRowtypeExpr * r = makeNode ( ConvertRowtypeExpr ) ;
r - > arg = ( Expr * ) var ;
r - > resulttype = context - > parent_reltype ;
r - > convertformat = COERCE_IMPLICIT_CAST ;
/* Make sure the Var node has the right type ID, too */
var - > vartype = context - > child_reltype ;
return ( Node * ) r ;
}
}
else
{
/* XXX copy some code from ResolveNew */
Assert ( false ) ; /* not done yet */
}
}
/* system attributes don't need any translation */
/* system attributes don't need any other translation */
}
return ( Node * ) var ;
}
@ -1024,8 +1135,8 @@ adjust_inherited_attrs_mutator(Node *node,
{
RangeTblRef * rtr = ( RangeTblRef * ) copyObject ( node ) ;
if ( rtr - > rtindex = = context - > old_rt_index )
rtr - > rtindex = context - > new_rt_index ;
if ( rtr - > rtindex = = context - > parent_relid )
rtr - > rtindex = context - > child_relid ;
return ( Node * ) rtr ;
}
if ( IsA ( node , JoinExpr ) )
@ -1034,11 +1145,11 @@ adjust_inherited_attrs_mutator(Node *node,
JoinExpr * j ;
j = ( JoinExpr * ) expression_tree_mutator ( node ,
adjust_inherited _attrs_mutator ,
adjust_appendrel _attrs_mutator ,
( void * ) context ) ;
/* now fix JoinExpr's rtindex */
if ( j - > rtindex = = context - > old_rt_index )
j - > rtindex = context - > new_rt_index ;
/* now fix JoinExpr's rtindex (probably never happens) */
if ( j - > rtindex = = context - > parent_relid )
j - > rtindex = context - > child_relid ;
return ( Node * ) j ;
}
if ( IsA ( node , InClauseInfo ) )
@ -1047,17 +1158,20 @@ adjust_inherited_attrs_mutator(Node *node,
InClauseInfo * ininfo ;
ininfo = ( InClauseInfo * ) expression_tree_mutator ( node ,
adjust_inherited _attrs_mutator ,
adjust_appendrel _attrs_mutator ,
( void * ) context ) ;
/* now fix InClauseInfo's relid sets */
ininfo - > lefthand = adjust_relid_set ( ininfo - > lefthand ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
ininfo - > righthand = adjust_relid_set ( ininfo - > righthand ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
return ( Node * ) ininfo ;
}
/* Shouldn't need to handle OuterJoinInfo or AppendRelInfo here */
Assert ( ! IsA ( node , OuterJoinInfo ) ) ;
Assert ( ! IsA ( node , AppendRelInfo ) ) ;
/*
* We have to process RestrictInfo nodes specially .
@ -1072,25 +1186,25 @@ adjust_inherited_attrs_mutator(Node *node,
/* Recursively fix the clause itself */
newinfo - > clause = ( Expr * )
adjust_inherited _attrs_mutator ( ( Node * ) oldinfo - > clause , context ) ;
adjust_appendrel _attrs_mutator ( ( Node * ) oldinfo - > clause , context ) ;
/* and the modified version, if an OR clause */
newinfo - > orclause = ( Expr * )
adjust_inherited _attrs_mutator ( ( Node * ) oldinfo - > orclause , context ) ;
adjust_appendrel _attrs_mutator ( ( Node * ) oldinfo - > orclause , context ) ;
/* adjust relid sets too */
newinfo - > clause_relids = adjust_relid_set ( oldinfo - > clause_relids ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
newinfo - > required_relids = adjust_relid_set ( oldinfo - > required_relids ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
newinfo - > left_relids = adjust_relid_set ( oldinfo - > left_relids ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
newinfo - > right_relids = adjust_relid_set ( oldinfo - > right_relids ,
context - > old_rt_index ,
context - > new_rt_index ) ;
context - > parent_relid ,
context - > child_relid ) ;
/*
* Reset cached derivative fields , since these might need to have
@ -1119,7 +1233,7 @@ adjust_inherited_attrs_mutator(Node *node,
* BUT : although we don ' t need to recurse into subplans , we do need to
* make sure that they are copied , not just referenced as
* expression_tree_mutator will do by default . Otherwise we ' ll have the
* same subplan node referenced from each arm of the inheritance APPEND
* same subplan node referenced from each arm of the finished APPEND
* plan , which will cause trouble in the executor . This is a kluge that
* should go away when we redesign querytrees .
*/
@ -1128,7 +1242,7 @@ adjust_inherited_attrs_mutator(Node *node,
SubPlan * subplan ;
/* Copy the node and process subplan args */
node = expression_tree_mutator ( node , adjust_inherited _attrs_mutator ,
node = expression_tree_mutator ( node , adjust_appendrel _attrs_mutator ,
( void * ) context ) ;
/* Make sure we have separate copies of subplan and its rtable */
subplan = ( SubPlan * ) node ;
@ -1137,7 +1251,7 @@ adjust_inherited_attrs_mutator(Node *node,
return node ;
}
return expression_tree_mutator ( node , adjust_inherited _attrs_mutator ,
return expression_tree_mutator ( node , adjust_appendrel _attrs_mutator ,
( void * ) context ) ;
}
@ -1158,6 +1272,110 @@ adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
return relids ;
}
/*
* adjust_appendrel_attr_needed
* Adjust an attr_needed [ ] array to reference a member rel instead of
* the original appendrel
*
* oldrel : source of data ( we use the attr_needed , min_attr , max_attr fields )
* appinfo : supplies parent_relid , child_relid , col_mappings
* new_min_attr , new_max_attr : desired bounds of new attr_needed array
*
* The relid sets are adjusted by substituting child_relid for parent_relid .
* ( NOTE : oldrel is not necessarily the parent_relid relation ! ) We are also
* careful to map attribute numbers within the array properly . User
* attributes have to be mapped through col_mappings , but system attributes
* and whole - row references always have the same attno .
*
* Returns a palloc ' d array with the specified bounds
*/
Relids *
adjust_appendrel_attr_needed ( RelOptInfo * oldrel , AppendRelInfo * appinfo ,
AttrNumber new_min_attr , AttrNumber new_max_attr )
{
Relids * new_attr_needed ;
Index parent_relid = appinfo - > parent_relid ;
Index child_relid = appinfo - > child_relid ;
int parent_attr ;
ListCell * lm ;
/* Create empty result array */
Assert ( new_min_attr < = oldrel - > min_attr ) ;
Assert ( new_max_attr > = oldrel - > max_attr ) ;
new_attr_needed = ( Relids * )
palloc0 ( ( new_max_attr - new_min_attr + 1 ) * sizeof ( Relids ) ) ;
/* Process user attributes, with appropriate attno mapping */
parent_attr = 1 ;
foreach ( lm , appinfo - > col_mappings )
{
int child_attr = lfirst_int ( lm ) ;
if ( child_attr > 0 )
{
Relids attrneeded ;
Assert ( parent_attr < = oldrel - > max_attr ) ;
Assert ( child_attr < = new_max_attr ) ;
attrneeded = oldrel - > attr_needed [ parent_attr - oldrel - > min_attr ] ;
attrneeded = adjust_relid_set ( attrneeded ,
parent_relid , child_relid ) ;
new_attr_needed [ child_attr - new_min_attr ] = attrneeded ;
}
parent_attr + + ;
}
/* Process system attributes, including whole-row references */
for ( parent_attr = oldrel - > min_attr ; parent_attr < = 0 ; parent_attr + + )
{
Relids attrneeded ;
attrneeded = oldrel - > attr_needed [ parent_attr - oldrel - > min_attr ] ;
attrneeded = adjust_relid_set ( attrneeded ,
parent_relid , child_relid ) ;
new_attr_needed [ parent_attr - new_min_attr ] = attrneeded ;
}
return new_attr_needed ;
}
/*
* adjust_other_rel_attr_needed
* Adjust an attr_needed [ ] array to reference a member rel instead of
* the original appendrel
*
* This is exactly like adjust_appendrel_attr_needed except that we disregard
* appinfo - > col_mappings and instead assume that the mapping of user
* attributes is one - to - one . This is appropriate for generating an attr_needed
* array that describes another relation to be joined with a member rel .
*/
Relids *
adjust_other_rel_attr_needed ( RelOptInfo * oldrel , AppendRelInfo * appinfo ,
AttrNumber new_min_attr , AttrNumber new_max_attr )
{
Relids * new_attr_needed ;
Index parent_relid = appinfo - > parent_relid ;
Index child_relid = appinfo - > child_relid ;
int parent_attr ;
/* Create empty result array */
Assert ( new_min_attr < = oldrel - > min_attr ) ;
Assert ( new_max_attr > = oldrel - > max_attr ) ;
new_attr_needed = ( Relids * )
palloc0 ( ( new_max_attr - new_min_attr + 1 ) * sizeof ( Relids ) ) ;
/* Process user attributes and system attributes */
for ( parent_attr = oldrel - > min_attr ; parent_attr < = oldrel - > max_attr ;
parent_attr + + )
{
Relids attrneeded ;
attrneeded = oldrel - > attr_needed [ parent_attr - oldrel - > min_attr ] ;
attrneeded = adjust_relid_set ( attrneeded ,
parent_relid , child_relid ) ;
new_attr_needed [ parent_attr - new_min_attr ] = attrneeded ;
}
return new_attr_needed ;
}
/*
* Adjust the targetlist entries of an inherited UPDATE operation
*
@ -1175,8 +1393,7 @@ adjust_relid_set(Relids relids, Index oldrelid, Index newrelid)
* Note that this is not needed for INSERT because INSERT isn ' t inheritable .
*/
static List *
adjust_inherited_tlist ( List * tlist ,
adjust_inherited_attrs_context * context )
adjust_inherited_tlist ( List * tlist , AppendRelInfo * context )
{
bool changed_it = false ;
ListCell * tl ;
@ -1184,19 +1401,31 @@ adjust_inherited_tlist(List *tlist,
bool more ;
int attrno ;
/* Scan tlist and update resnos to match attnums of new_relid */
/* This should only happen for an inheritance case, not UNION ALL */
Assert ( OidIsValid ( context - > parent_reloid ) ) ;
/* Scan tlist and update resnos to match attnums of child rel */
foreach ( tl , tlist )
{
TargetEntry * tle = ( TargetEntry * ) lfirst ( tl ) ;
int newattno ;
if ( tle - > resjunk )
continue ; /* ignore junk items */
attrno = translate_inherited_attnum ( tle - > resno , context ) ;
if ( tle - > resno ! = attrno )
/* Look up the translation of this column */
if ( tle - > resno < = 0 | |
tle - > resno > list_length ( context - > col_mappings ) )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
tle - > resno , get_rel_name ( context - > parent_reloid ) ) ;
newattno = list_nth_int ( context - > col_mappings , tle - > resno - 1 ) ;
if ( newattno < = 0 )
elog ( ERROR , " attribute %d of relation \" %s \" does not exist " ,
tle - > resno , get_rel_name ( context - > parent_reloid ) ) ;
if ( tle - > resno ! = newattno )
{
tle - > resno = attrno ;
tle - > resno = new attno;
changed_it = true ;
}
}