@ -18,110 +18,90 @@
# include "access/table.h"
# include "access/table.h"
# include "catalog/partition.h"
# include "catalog/partition.h"
# include "catalog/pg_inherits.h"
# include "catalog/pg_inherits.h"
# include "catalog/pg_type.h"
# include "miscadmin.h"
# include "miscadmin.h"
# include "nodes/makefuncs.h"
# include "optimizer/appendinfo.h"
# include "optimizer/appendinfo.h"
# include "optimizer/inherit.h"
# include "optimizer/inherit.h"
# include "optimizer/optimizer.h"
# include "optimizer/pathnode.h"
# include "optimizer/planmain.h"
# include "optimizer/planner.h"
# include "optimizer/planner.h"
# include "optimizer/prep.h"
# include "optimizer/prep.h"
# include "optimizer/restrictinfo.h"
# include "parser/parsetree.h"
# include "partitioning/partdesc.h"
# include "partitioning/partdesc.h"
# include "partitioning/partprune.h"
# include "utils/rel.h"
# include "utils/rel.h"
static void expand_inherited_rtentry ( PlannerInfo * root , RangeTblEntry * rte ,
static void expand_partitioned_rtentry ( PlannerInfo * root , RelOptInfo * relinfo ,
Index rti ) ;
static void expand_partitioned_rtentry ( PlannerInfo * root ,
RangeTblEntry * parentrte ,
RangeTblEntry * parentrte ,
Index parentRTindex , Relation parentrel ,
Index parentRTindex , Relation parentrel ,
PlanRowMark * top_parentrc , LOCKMODE lockmode ,
PlanRowMark * top_parentrc , LOCKMODE lockmode ) ;
List * * appinfos ) ;
static void expand_single_inheritance_child ( PlannerInfo * root ,
static void expand_single_inheritance_child ( PlannerInfo * root ,
RangeTblEntry * parentrte ,
RangeTblEntry * parentrte ,
Index parentRTindex , Relation parentrel ,
Index parentRTindex , Relation parentrel ,
PlanRowMark * top_parentrc , Relation childrel ,
PlanRowMark * top_parentrc , Relation childrel ,
List * * appinfos , RangeTblEntry * * childrte_p ,
RangeTblEntry * * childrte_p ,
Index * childRTindex_p ) ;
Index * childRTindex_p ) ;
static Bitmapset * translate_col_privs ( const Bitmapset * parent_privs ,
static Bitmapset * translate_col_privs ( const Bitmapset * parent_privs ,
List * translated_vars ) ;
List * translated_vars ) ;
static void expand_appendrel_subquery ( PlannerInfo * root , RelOptInfo * rel ,
RangeTblEntry * rte , Index rti ) ;
/*
* 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 . The function is
* expected to recursively handle any RTEs that it creates with 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
* expand_inherited_rtentry
* Check whether a rangetable entry represents an inheritance set .
* Expand a rangetable entry that has the " inh " bit set .
* If so , add entries for all the child tables to the query ' s
*
* rangetable , and build AppendRelInfo nodes for all the child tables
* " inh " is only allowed in two cases : RELATION and SUBQUERY RTEs .
* 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
* " inh " on a plain RELATION RTE means that it is a partitioned table or the
* inheritance set . The first of the generated RTEs is an RTE for the same
* parent of a traditional - inheritance set . In this case we must add entries
* table , but with inh = false , to represent the parent table in its role
* for all the interesting child tables to the query ' s rangetable , and build
* as a simple member of the inheritance set .
* additional planner data structures for them , including RelOptInfos ,
* AppendRelInfos , and possibly PlanRowMarks .
*
*
* A childless table is never considered to be an inheritance set . For
* Note that the original RTE is considered to represent the whole inheritance
* regular inheritance , a parent RTE must always have at least two associated
* set . In the case of traditional inheritance , the first of the generated
* AppendRelInfos : one corresponding to the parent table as a simple member of
* RTEs is an RTE for the same table , but with inh = false , to represent the
* the inheritance set and one or more corresponding to the actual children .
* parent table in its role as a simple member of the inheritance set . For
* ( But a partitioned table might have only one associated AppendRelInfo ,
* partitioning , we don ' t need a second RTE because the partitioned table
* since it ' s not itself scanned and hence doesn ' t need a second RTE to
* itself has no data and need not be scanned .
* represent itself as a member of the set . )
*
* " inh " on a SUBQUERY RTE means that it ' s the parent of a UNION ALL group ,
* which is treated as an appendrel similarly to inheritance cases ; however ,
* we already made RTEs and AppendRelInfos for the subqueries . We only need
* to build RelOptInfos for them , which is done by expand_appendrel_subquery .
*/
*/
static void
void
expand_inherited_rtentry ( PlannerInfo * root , RangeTblEntry * rte , Index rti )
expand_inherited_rtentry ( PlannerInfo * root , RelOptInfo * rel ,
RangeTblEntry * rte , Index rti )
{
{
Oid parentOID ;
Oid parentOID ;
PlanRowMark * oldrc ;
Relation oldrelation ;
Relation oldrelation ;
LOCKMODE lockmode ;
LOCKMODE lockmode ;
List * inhOIDs ;
PlanRowMark * oldrc ;
ListCell * l ;
bool old_isParent = false ;
int old_allMarkTypes = 0 ;
/* Does RT entry allow inheritance? */
Assert ( rte - > inh ) ; /* else caller error */
if ( ! rte - > inh )
return ;
if ( rte - > rtekind = = RTE_SUBQUERY )
/* Ignore any already-expanded UNION ALL nodes */
if ( rte - > rtekind ! = RTE_RELATION )
{
{
Assert ( rte - > rtekind = = RTE_SUBQUERY ) ;
expand_appendrel_subquery ( root , rel , rte , rti ) ;
return ;
return ;
}
}
/* Fast path for common case of childless table */
Assert ( rte - > rtekind = = RTE_RELATION ) ;
parentOID = rte - > relid ;
parentOID = rte - > relid ;
if ( ! has_subclass ( parentOID ) )
{
/*
/* Clear flag before returning */
* We used to check has_subclass ( ) here , but there ' s no longer any need
rte - > inh = false ;
* to , because subquery_planner already did .
return ;
*/
}
/*
/*
* The rewriter should already have obtained an appropriate lock on each
* The rewriter should already have obtained an appropriate lock on each
@ -141,7 +121,12 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
*/
*/
oldrc = get_plan_rowmark ( root - > rowMarks , rti ) ;
oldrc = get_plan_rowmark ( root - > rowMarks , rti ) ;
if ( oldrc )
if ( oldrc )
{
old_isParent = oldrc - > isParent ;
oldrc - > isParent = true ;
oldrc - > isParent = true ;
/* Save initial value of allMarkTypes before children add to it */
old_allMarkTypes = oldrc - > allMarkTypes ;
}
/* Scan the inheritance set and expand it */
/* Scan the inheritance set and expand it */
if ( oldrelation - > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE )
if ( oldrelation - > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE )
@ -151,17 +136,12 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
*/
*/
Assert ( rte - > relkind = = RELKIND_PARTITIONED_TABLE ) ;
Assert ( rte - > relkind = = RELKIND_PARTITIONED_TABLE ) ;
if ( root - > glob - > partition_directory = = NULL )
root - > glob - > partition_directory =
CreatePartitionDirectory ( CurrentMemoryContext ) ;
/*
/*
* If this table has partitions , recursively expand and lock them .
* Recursively expand and lock the partitions . While at it , also
* While at it , also extract the partition key columns of all the
* extract the partition key columns of all the partitioned tables .
* partitioned tables .
*/
*/
expand_partitioned_rtentry ( root , rte , rti , oldrelation , oldrc ,
expand_partitioned_rtentry ( root , rel , r te , rti ,
lockmode , & root - > append_rel_list ) ;
oldrelation , oldrc , lockmode ) ;
}
}
else
else
{
{
@ -170,25 +150,25 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* that partitioned tables are not allowed to have inheritance
* that partitioned tables are not allowed to have inheritance
* children , so it ' s not possible for both cases to apply . )
* children , so it ' s not possible for both cases to apply . )
*/
*/
List * appinfos = NIL ;
List * inhOIDs ;
RangeTblEntry * childrte ;
ListCell * l ;
Index childRTindex ;
/* Scan for all members of inheritance set, acquire needed locks */
/* Scan for all members of inheritance set, acquire needed locks */
inhOIDs = find_all_inheritors ( parentOID , lockmode , NULL ) ;
inhOIDs = find_all_inheritors ( parentOID , lockmode , NULL ) ;
/*
/*
* Check that there ' s at least one descendant , else treat as no - child
* We used to special - case the situation where the table no longer has
* case . This could happen despite above has_subclass ( ) check , if the
* any children , by clearing rte - > inh and exiting . That no longer
* table once had a child but no longer does .
* works , because this function doesn ' t get run until after decisions
* have been made that depend on rte - > inh . We have to treat such
* situations as normal inheritance . The table itself should always
* have been found , though .
*/
*/
if ( list_length ( inhOIDs ) < 2 )
Assert ( inhOIDs ! = NIL ) ;
{
Assert ( linitial_oid ( inhOIDs ) = = parentOID ) ;
/* Clear flag before returning */
rte - > inh = false ;
/* Expand simple_rel_array and friends to hold child objects. */
heap_close ( oldrelation , NoLock ) ;
expand_planner_arrays ( root , list_length ( inhOIDs ) ) ;
return ;
}
/*
/*
* Expand inheritance children in the order the OIDs were returned by
* Expand inheritance children in the order the OIDs were returned by
@ -198,6 +178,8 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
{
{
Oid childOID = lfirst_oid ( l ) ;
Oid childOID = lfirst_oid ( l ) ;
Relation newrelation ;
Relation newrelation ;
RangeTblEntry * childrte ;
Index childRTindex ;
/* Open rel if needed; we already have required locks */
/* Open rel if needed; we already have required locks */
if ( childOID ! = parentOID )
if ( childOID ! = parentOID )
@ -217,29 +199,78 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
continue ;
continue ;
}
}
expand_single_inheritance_child ( root , rte , rti , oldrelation , oldrc ,
/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
newrelation ,
expand_single_inheritance_child ( root , rte , rti , oldrelation ,
& appinfos , & childrte ,
oldrc , newrelation ,
& childRTindex ) ;
& childrte , & childRTindex ) ;
/* Create the otherrel RelOptInfo too. */
( void ) build_simple_rel ( root , childRTindex , rel ) ;
/* Close child relations, but keep locks */
/* Close child relations, but keep locks */
if ( childOID ! = parentOID )
if ( childOID ! = parentOID )
table_close ( newrelation , NoLock ) ;
table_close ( newrelation , NoLock ) ;
}
}
}
/*
* Some children might require different mark types , which would ' ve been
* reported into oldrc . If so , add relevant entries to the top - level
* targetlist and update parent rel ' s reltarget . This should match what
* preprocess_targetlist ( ) would have added if the mark types had been
* requested originally .
*/
if ( oldrc )
{
int new_allMarkTypes = oldrc - > allMarkTypes ;
Var * var ;
TargetEntry * tle ;
char resname [ 32 ] ;
List * newvars = NIL ;
/* The old PlanRowMark should already have necessitated adding TID */
Assert ( old_allMarkTypes & ~ ( 1 < < ROW_MARK_COPY ) ) ;
/* Add whole-row junk Var if needed, unless we had it already */
if ( ( new_allMarkTypes & ( 1 < < ROW_MARK_COPY ) ) & &
! ( old_allMarkTypes & ( 1 < < ROW_MARK_COPY ) ) )
{
var = makeWholeRowVar ( planner_rt_fetch ( oldrc - > rti , root ) ,
oldrc - > rti ,
0 ,
false ) ;
snprintf ( resname , sizeof ( resname ) , " wholerow%u " , oldrc - > rowmarkId ) ;
tle = makeTargetEntry ( ( Expr * ) var ,
list_length ( root - > processed_tlist ) + 1 ,
pstrdup ( resname ) ,
true ) ;
root - > processed_tlist = lappend ( root - > processed_tlist , tle ) ;
newvars = lappend ( newvars , var ) ;
}
/* Add tableoid junk Var, unless we had it already */
if ( ! old_isParent )
{
var = makeVar ( oldrc - > rti ,
TableOidAttributeNumber ,
OIDOID ,
- 1 ,
InvalidOid ,
0 ) ;
snprintf ( resname , sizeof ( resname ) , " tableoid%u " , oldrc - > rowmarkId ) ;
tle = makeTargetEntry ( ( Expr * ) var ,
list_length ( root - > processed_tlist ) + 1 ,
pstrdup ( resname ) ,
true ) ;
root - > processed_tlist = lappend ( root - > processed_tlist , tle ) ;
newvars = lappend ( newvars , var ) ;
}
/*
/*
* If all the children were temp tables , pretend it ' s a
* Add the newly added Vars to parent ' s reltarget . We needn ' t worry
* non - inheritance situation ; we don ' t need Append node in that case .
* about the children ' s reltargets , they ' ll be made later .
* The duplicate RTE we added for the parent table is harmless , so we
* don ' t bother to get rid of it ; ditto for the useless PlanRowMark
* node .
*/
*/
if ( list_length ( appinfos ) < 2 )
add_vars_to_targetlist ( root , newvars , bms_make_singleton ( 0 ) , false ) ;
rte - > inh = false ;
else
root - > append_rel_list = list_concat ( root - > append_rel_list ,
appinfos ) ;
}
}
table_close ( oldrelation , NoLock ) ;
table_close ( oldrelation , NoLock ) ;
@ -250,26 +281,26 @@ expand_inherited_rtentry(PlannerInfo *root, RangeTblEntry *rte, Index rti)
* Recursively expand an RTE for a partitioned table .
* Recursively expand an RTE for a partitioned table .
*/
*/
static void
static void
expand_partitioned_rtentry ( PlannerInfo * root , RangeTblEntry * parentrte ,
expand_partitioned_rtentry ( PlannerInfo * root , RelOptInfo * relinfo ,
RangeTblEntry * parentrte ,
Index parentRTindex , Relation parentrel ,
Index parentRTindex , Relation parentrel ,
PlanRowMark * top_parentrc , LOCKMODE lockmode ,
PlanRowMark * top_parentrc , LOCKMODE lockmode )
List * * appinfos )
{
{
int i ;
RangeTblEntry * childrte ;
Index childRTindex ;
PartitionDesc partdesc ;
PartitionDesc partdesc ;
Bitmapset * live_parts ;
int num_live_parts ;
int i ;
check_stack_depth ( ) ;
Assert ( parentrte - > inh ) ;
partdesc = PartitionDirectoryLookup ( root - > glob - > partition_directory ,
partdesc = PartitionDirectoryLookup ( root - > glob - > partition_directory ,
parentrel ) ;
parentrel ) ;
check_stack_depth ( ) ;
/* A partitioned table should always have a partition descriptor. */
/* A partitioned table should always have a partition descriptor. */
Assert ( partdesc ) ;
Assert ( partdesc ) ;
Assert ( parentrte - > inh ) ;
/*
/*
* Note down whether any partition key cols are being updated . Though it ' s
* Note down whether any partition key cols are being updated . Though it ' s
* the root partitioned table ' s updatedCols we are interested in , we
* the root partitioned table ' s updatedCols we are interested in , we
@ -285,25 +316,45 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
*/
*/
Assert ( ! has_partition_attrs ( parentrel , parentrte - > extraUpdatedCols , NULL ) ) ;
Assert ( ! has_partition_attrs ( parentrel , parentrte - > extraUpdatedCols , NULL ) ) ;
/*
/* Nothing further to do here if there are no partitions. */
* If the partitioned table has no partitions , treat this as the
* non - inheritance case .
*/
if ( partdesc - > nparts = = 0 )
if ( partdesc - > nparts = = 0 )
{
parentrte - > inh = false ;
return ;
return ;
}
/*
/*
* Create a child RTE for each partition . Note that unlike traditional
* Perform partition pruning using restriction clauses assigned to parent
* inheritance , we don ' t need a child RTE for the partitioned table
* relation . live_parts will contain PartitionDesc indexes of partitions
* itself , because it ' s not going to be scanned .
* that survive pruning . Below , we will initialize child objects for the
* surviving partitions .
*/
*/
for ( i = 0 ; i < partdesc - > nparts ; i + + )
live_parts = prune_append_rel_partitions ( relinfo ) ;
/* Expand simple_rel_array and friends to hold child objects. */
num_live_parts = bms_num_members ( live_parts ) ;
if ( num_live_parts > 0 )
expand_planner_arrays ( root , num_live_parts ) ;
/*
* We also store partition RelOptInfo pointers in the parent relation .
* Since we ' re palloc0 ' ing , slots corresponding to pruned partitions will
* contain NULL .
*/
Assert ( relinfo - > part_rels = = NULL ) ;
relinfo - > part_rels = ( RelOptInfo * * )
palloc0 ( relinfo - > nparts * sizeof ( RelOptInfo * ) ) ;
/*
* Create a child RTE for each live partition . Note that unlike
* traditional inheritance , we don ' t need a child RTE for the partitioned
* table itself , because it ' s not going to be scanned .
*/
i = - 1 ;
while ( ( i = bms_next_member ( live_parts , i ) ) > = 0 )
{
{
Oid childOID = partdesc - > oids [ i ] ;
Oid childOID = partdesc - > oids [ i ] ;
Relation childrel ;
Relation childrel ;
RangeTblEntry * childrte ;
Index childRTindex ;
RelOptInfo * childrelinfo ;
/* Open rel, acquiring required locks */
/* Open rel, acquiring required locks */
childrel = table_open ( childOID , lockmode ) ;
childrel = table_open ( childOID , lockmode ) ;
@ -316,15 +367,20 @@ expand_partitioned_rtentry(PlannerInfo *root, RangeTblEntry *parentrte,
if ( RELATION_IS_OTHER_TEMP ( childrel ) )
if ( RELATION_IS_OTHER_TEMP ( childrel ) )
elog ( ERROR , " temporary relation from another session found as partition " ) ;
elog ( ERROR , " temporary relation from another session found as partition " ) ;
/* Create RTE and AppendRelInfo, plus PlanRowMark if needed. */
expand_single_inheritance_child ( root , parentrte , parentRTindex ,
expand_single_inheritance_child ( root , parentrte , parentRTindex ,
parentrel , top_parentrc , childrel ,
parentrel , top_parentrc , childrel ,
appinfos , & childrte , & childRTindex ) ;
& childrte , & childRTindex ) ;
/* Create the otherrel RelOptInfo too. */
childrelinfo = build_simple_rel ( root , childRTindex , relinfo ) ;
relinfo - > part_rels [ i ] = childrelinfo ;
/* If this child is itself partitioned, recurse */
/* If this child is itself partitioned, recurse */
if ( childrel - > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE )
if ( childrel - > rd_rel - > relkind = = RELKIND_PARTITIONED_TABLE )
expand_partitioned_rtentry ( root , childrte , childRTindex ,
expand_partitioned_rtentry ( root , childrelinfo ,
childrel , top_parentrc , lockmode ,
childrte , childRTindex ,
appinfos ) ;
childrel , top_parentrc , lockmode ) ;
/* Close child relation, but keep locks */
/* Close child relation, but keep locks */
table_close ( childrel , NoLock ) ;
table_close ( childrel , NoLock ) ;
@ -355,7 +411,7 @@ static void
expand_single_inheritance_child ( PlannerInfo * root , RangeTblEntry * parentrte ,
expand_single_inheritance_child ( PlannerInfo * root , RangeTblEntry * parentrte ,
Index parentRTindex , Relation parentrel ,
Index parentRTindex , Relation parentrel ,
PlanRowMark * top_parentrc , Relation childrel ,
PlanRowMark * top_parentrc , Relation childrel ,
List * * appinfos , RangeTblEntry * * childrte_p ,
RangeTblEntry * * childrte_p ,
Index * childRTindex_p )
Index * childRTindex_p )
{
{
Query * parse = root - > parse ;
Query * parse = root - > parse ;
@ -367,8 +423,8 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
/*
/*
* Build an RTE for the child , and attach to query ' s rangetable list . We
* 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 and
* copy most fields of the parent ' s RTE , but replace relation OID ,
* relkind , and set inh = false . Also , set requiredPerms to zero since
* relkind , and inh for the child . Also , set requiredPerms to zero since
* all required permissions checks are done on the original RTE . Likewise ,
* all required permissions checks are done on the original RTE . Likewise ,
* set the child ' s securityQuals to empty , because we only want to apply
* set the child ' s securityQuals to empty , because we only want to apply
* the parent ' s RLS conditions regardless of what RLS properties
* the parent ' s RLS conditions regardless of what RLS properties
@ -400,7 +456,7 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
*/
*/
appinfo = make_append_rel_info ( parentrel , childrel ,
appinfo = make_append_rel_info ( parentrel , childrel ,
parentRTindex , childRTindex ) ;
parentRTindex , childRTindex ) ;
* appinfos = lappend ( * appinfos , appinfo ) ;
root - > append_rel_list = lappend ( root - > append_rel_list , appinfo ) ;
/*
/*
* Translate the column permissions bitmaps to the child ' s attnums ( we
* Translate the column permissions bitmaps to the child ' s attnums ( we
@ -423,6 +479,16 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
appinfo - > translated_vars ) ;
appinfo - > translated_vars ) ;
}
}
/*
* Store the RTE and appinfo in the respective PlannerInfo arrays , which
* the caller must already have allocated space for .
*/
Assert ( childRTindex < root - > simple_rel_array_size ) ;
Assert ( root - > simple_rte_array [ childRTindex ] = = NULL ) ;
root - > simple_rte_array [ childRTindex ] = childrte ;
Assert ( root - > append_rel_array [ childRTindex ] = = NULL ) ;
root - > append_rel_array [ childRTindex ] = appinfo ;
/*
/*
* Build a PlanRowMark if parent is marked FOR UPDATE / SHARE .
* Build a PlanRowMark if parent is marked FOR UPDATE / SHARE .
*/
*/
@ -443,7 +509,7 @@ expand_single_inheritance_child(PlannerInfo *root, RangeTblEntry *parentrte,
/*
/*
* We mark RowMarks for partitioned child tables as parent RowMarks so
* We mark RowMarks for partitioned child tables as parent RowMarks so
* that the executor ignores them ( except their existence means that
* that the executor ignores them ( except their existence means that
* the child tables be locked using appropriate mode ) .
* the child tables will be locked using the appropriate mode ) .
*/
*/
childrc - > isParent = ( childrte - > relkind = = RELKIND_PARTITIONED_TABLE ) ;
childrc - > isParent = ( childrte - > relkind = = RELKIND_PARTITIONED_TABLE ) ;
@ -505,3 +571,169 @@ translate_col_privs(const Bitmapset *parent_privs,
return child_privs ;
return child_privs ;
}
}
/*
* expand_appendrel_subquery
* Add " other rel " RelOptInfos for the children of an appendrel baserel
*
* " rel " is a subquery relation that has the rte - > inh flag set , meaning it
* is a UNION ALL subquery that ' s been flattened into an appendrel , with
* child subqueries listed in root - > append_rel_list . We need to build
* a RelOptInfo for each child relation so that we can plan scans on them .
*/
static void
expand_appendrel_subquery ( PlannerInfo * root , RelOptInfo * rel ,
RangeTblEntry * rte , Index rti )
{
ListCell * l ;
foreach ( l , root - > append_rel_list )
{
AppendRelInfo * appinfo = ( AppendRelInfo * ) lfirst ( l ) ;
Index childRTindex = appinfo - > child_relid ;
RangeTblEntry * childrte ;
RelOptInfo * childrel ;
/* append_rel_list contains all append rels; ignore others */
if ( appinfo - > parent_relid ! = rti )
continue ;
/* find the child RTE, which should already exist */
Assert ( childRTindex < root - > simple_rel_array_size ) ;
childrte = root - > simple_rte_array [ childRTindex ] ;
Assert ( childrte ! = NULL ) ;
/* Build the child RelOptInfo. */
childrel = build_simple_rel ( root , childRTindex , rel ) ;
/* Child may itself be an inherited rel, either table or subquery. */
if ( childrte - > inh )
expand_inherited_rtentry ( root , childrel , childrte , childRTindex ) ;
}
}
/*
* apply_child_basequals
* Populate childrel ' s base restriction quals from parent rel ' s quals ,
* translating them using appinfo .
*
* If any of the resulting clauses evaluate to constant false or NULL , we
* return false and don ' t apply any quals . Caller should mark the relation as
* a dummy rel in this case , since it doesn ' t need to be scanned .
*/
bool
apply_child_basequals ( PlannerInfo * root , RelOptInfo * parentrel ,
RelOptInfo * childrel , RangeTblEntry * childRTE ,
AppendRelInfo * appinfo )
{
List * childquals ;
Index cq_min_security ;
ListCell * lc ;
/*
* The child rel ' s targetlist might contain non - Var expressions , which
* means that substitution into the quals could produce opportunities for
* const - simplification , and perhaps even pseudoconstant quals . Therefore ,
* transform each RestrictInfo separately to see if it reduces to a
* constant or pseudoconstant . ( We must process them separately to keep
* track of the security level of each qual . )
*/
childquals = NIL ;
cq_min_security = UINT_MAX ;
foreach ( lc , parentrel - > baserestrictinfo )
{
RestrictInfo * rinfo = ( RestrictInfo * ) lfirst ( lc ) ;
Node * childqual ;
ListCell * lc2 ;
Assert ( IsA ( rinfo , RestrictInfo ) ) ;
childqual = adjust_appendrel_attrs ( root ,
( Node * ) rinfo - > clause ,
1 , & appinfo ) ;
childqual = eval_const_expressions ( root , childqual ) ;
/* check for flat-out constant */
if ( childqual & & IsA ( childqual , Const ) )
{
if ( ( ( Const * ) childqual ) - > constisnull | |
! DatumGetBool ( ( ( Const * ) childqual ) - > constvalue ) )
{
/* Restriction reduces to constant FALSE or NULL */
return false ;
}
/* Restriction reduces to constant TRUE, so drop it */
continue ;
}
/* might have gotten an AND clause, if so flatten it */
foreach ( lc2 , make_ands_implicit ( ( Expr * ) childqual ) )
{
Node * onecq = ( Node * ) lfirst ( lc2 ) ;
bool pseudoconstant ;
/* check for pseudoconstant (no Vars or volatile functions) */
pseudoconstant =
! contain_vars_of_level ( onecq , 0 ) & &
! contain_volatile_functions ( onecq ) ;
if ( pseudoconstant )
{
/* tell createplan.c to check for gating quals */
root - > hasPseudoConstantQuals = true ;
}
/* reconstitute RestrictInfo with appropriate properties */
childquals = lappend ( childquals ,
make_restrictinfo ( ( Expr * ) onecq ,
rinfo - > is_pushed_down ,
rinfo - > outerjoin_delayed ,
pseudoconstant ,
rinfo - > security_level ,
NULL , NULL , NULL ) ) ;
/* track minimum security level among child quals */
cq_min_security = Min ( cq_min_security , rinfo - > security_level ) ;
}
}
/*
* In addition to the quals inherited from the parent , we might have
* securityQuals associated with this particular child node . ( Currently
* this can only happen in appendrels originating from UNION ALL ;
* inheritance child tables don ' t have their own securityQuals , see
* expand_single_inheritance_child ( ) . ) Pull any such securityQuals up
* into the baserestrictinfo for the child . This is similar to
* process_security_barrier_quals ( ) for the parent rel , except that we
* can ' t make any general deductions from such quals , since they don ' t
* hold for the whole appendrel .
*/
if ( childRTE - > securityQuals )
{
Index security_level = 0 ;
foreach ( lc , childRTE - > securityQuals )
{
List * qualset = ( List * ) lfirst ( lc ) ;
ListCell * lc2 ;
foreach ( lc2 , qualset )
{
Expr * qual = ( Expr * ) lfirst ( lc2 ) ;
/* not likely that we'd see constants here, so no check */
childquals = lappend ( childquals ,
make_restrictinfo ( qual ,
true , false , false ,
security_level ,
NULL , NULL , NULL ) ) ;
cq_min_security = Min ( cq_min_security , security_level ) ;
}
security_level + + ;
}
Assert ( security_level < = root - > qual_security_level ) ;
}
/*
* OK , we ' ve got all the baserestrictinfo quals for this child .
*/
childrel - > baserestrictinfo = childquals ;
childrel - > baserestrict_min_security = cq_min_security ;
return true ;
}