mirror of
https://github.com/postgres/postgres.git
synced 2025-06-14 18:42:34 +03:00
Add a reverse-translation column number array to struct AppendRelInfo.
This provides for cheaper mapping of child columns back to parent columns. The one existing use-case in examine_simple_variable() would hardly justify this by itself; but an upcoming bug fix will make use of this array in a mainstream code path, and it seems likely that we'll find other uses for it as we continue to build out the partitioning infrastructure. Discussion: https://postgr.es/m/12424.1575168015@sss.pgh.pa.us
This commit is contained in:
@ -2327,6 +2327,8 @@ _copyAppendRelInfo(const AppendRelInfo *from)
|
|||||||
COPY_SCALAR_FIELD(parent_reltype);
|
COPY_SCALAR_FIELD(parent_reltype);
|
||||||
COPY_SCALAR_FIELD(child_reltype);
|
COPY_SCALAR_FIELD(child_reltype);
|
||||||
COPY_NODE_FIELD(translated_vars);
|
COPY_NODE_FIELD(translated_vars);
|
||||||
|
COPY_SCALAR_FIELD(num_child_cols);
|
||||||
|
COPY_POINTER_FIELD(parent_colnos, from->num_child_cols * sizeof(AttrNumber));
|
||||||
COPY_SCALAR_FIELD(parent_reloid);
|
COPY_SCALAR_FIELD(parent_reloid);
|
||||||
|
|
||||||
return newnode;
|
return newnode;
|
||||||
|
@ -900,6 +900,8 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
|
|||||||
COMPARE_SCALAR_FIELD(parent_reltype);
|
COMPARE_SCALAR_FIELD(parent_reltype);
|
||||||
COMPARE_SCALAR_FIELD(child_reltype);
|
COMPARE_SCALAR_FIELD(child_reltype);
|
||||||
COMPARE_NODE_FIELD(translated_vars);
|
COMPARE_NODE_FIELD(translated_vars);
|
||||||
|
COMPARE_SCALAR_FIELD(num_child_cols);
|
||||||
|
COMPARE_POINTER_FIELD(parent_colnos, a->num_child_cols * sizeof(AttrNumber));
|
||||||
COMPARE_SCALAR_FIELD(parent_reloid);
|
COMPARE_SCALAR_FIELD(parent_reloid);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -3103,6 +3103,7 @@ expression_tree_mutator(Node *node,
|
|||||||
|
|
||||||
FLATCOPY(newnode, appinfo, AppendRelInfo);
|
FLATCOPY(newnode, appinfo, AppendRelInfo);
|
||||||
MUTATE(newnode->translated_vars, appinfo->translated_vars, List *);
|
MUTATE(newnode->translated_vars, appinfo->translated_vars, List *);
|
||||||
|
/* Assume nothing need be done with parent_colnos[] */
|
||||||
return (Node *) newnode;
|
return (Node *) newnode;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -2509,6 +2509,8 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
|
|||||||
WRITE_OID_FIELD(parent_reltype);
|
WRITE_OID_FIELD(parent_reltype);
|
||||||
WRITE_OID_FIELD(child_reltype);
|
WRITE_OID_FIELD(child_reltype);
|
||||||
WRITE_NODE_FIELD(translated_vars);
|
WRITE_NODE_FIELD(translated_vars);
|
||||||
|
WRITE_INT_FIELD(num_child_cols);
|
||||||
|
WRITE_ATTRNUMBER_ARRAY(parent_colnos, node->num_child_cols);
|
||||||
WRITE_OID_FIELD(parent_reloid);
|
WRITE_OID_FIELD(parent_reloid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,7 +81,7 @@ static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
|
|||||||
int parentRTindex, Query *setOpQuery,
|
int parentRTindex, Query *setOpQuery,
|
||||||
int childRToffset);
|
int childRToffset);
|
||||||
static void make_setop_translation_list(Query *query, Index newvarno,
|
static void make_setop_translation_list(Query *query, Index newvarno,
|
||||||
List **translated_vars);
|
AppendRelInfo *appinfo);
|
||||||
static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
|
static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
|
||||||
JoinExpr *lowest_outer_join);
|
JoinExpr *lowest_outer_join);
|
||||||
static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode,
|
static Node *pull_up_simple_values(PlannerInfo *root, Node *jtnode,
|
||||||
@ -1313,8 +1313,7 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
|
|||||||
appinfo->child_relid = childRTindex;
|
appinfo->child_relid = childRTindex;
|
||||||
appinfo->parent_reltype = InvalidOid;
|
appinfo->parent_reltype = InvalidOid;
|
||||||
appinfo->child_reltype = InvalidOid;
|
appinfo->child_reltype = InvalidOid;
|
||||||
make_setop_translation_list(setOpQuery, childRTindex,
|
make_setop_translation_list(setOpQuery, childRTindex, appinfo);
|
||||||
&appinfo->translated_vars);
|
|
||||||
appinfo->parent_reloid = InvalidOid;
|
appinfo->parent_reloid = InvalidOid;
|
||||||
root->append_rel_list = lappend(root->append_rel_list, appinfo);
|
root->append_rel_list = lappend(root->append_rel_list, appinfo);
|
||||||
|
|
||||||
@ -1356,14 +1355,22 @@ pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root, int parentRTindex,
|
|||||||
* a UNION ALL member. (At this point it's just a simple list of
|
* a UNION ALL member. (At this point it's just a simple list of
|
||||||
* referencing Vars, but if we succeed in pulling up the member
|
* referencing Vars, but if we succeed in pulling up the member
|
||||||
* subquery, the Vars will get replaced by pulled-up expressions.)
|
* subquery, the Vars will get replaced by pulled-up expressions.)
|
||||||
|
* Also create the rather trivial reverse-translation array.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
make_setop_translation_list(Query *query, Index newvarno,
|
make_setop_translation_list(Query *query, Index newvarno,
|
||||||
List **translated_vars)
|
AppendRelInfo *appinfo)
|
||||||
{
|
{
|
||||||
List *vars = NIL;
|
List *vars = NIL;
|
||||||
|
AttrNumber *pcolnos;
|
||||||
ListCell *l;
|
ListCell *l;
|
||||||
|
|
||||||
|
/* Initialize reverse-translation array with all entries zero */
|
||||||
|
/* (entries for resjunk columns will stay that way) */
|
||||||
|
appinfo->num_child_cols = list_length(query->targetList);
|
||||||
|
appinfo->parent_colnos = pcolnos =
|
||||||
|
(AttrNumber *) palloc0(appinfo->num_child_cols * sizeof(AttrNumber));
|
||||||
|
|
||||||
foreach(l, query->targetList)
|
foreach(l, query->targetList)
|
||||||
{
|
{
|
||||||
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
TargetEntry *tle = (TargetEntry *) lfirst(l);
|
||||||
@ -1372,9 +1379,10 @@ make_setop_translation_list(Query *query, Index newvarno,
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
|
vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
|
||||||
|
pcolnos[tle->resno - 1] = tle->resno;
|
||||||
}
|
}
|
||||||
|
|
||||||
*translated_vars = vars;
|
appinfo->translated_vars = vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -34,7 +34,7 @@ typedef struct
|
|||||||
static void make_inh_translation_list(Relation oldrelation,
|
static void make_inh_translation_list(Relation oldrelation,
|
||||||
Relation newrelation,
|
Relation newrelation,
|
||||||
Index newvarno,
|
Index newvarno,
|
||||||
List **translated_vars);
|
AppendRelInfo *appinfo);
|
||||||
static Node *adjust_appendrel_attrs_mutator(Node *node,
|
static Node *adjust_appendrel_attrs_mutator(Node *node,
|
||||||
adjust_appendrel_attrs_context *context);
|
adjust_appendrel_attrs_context *context);
|
||||||
static List *adjust_inherited_tlist(List *tlist,
|
static List *adjust_inherited_tlist(List *tlist,
|
||||||
@ -55,8 +55,7 @@ make_append_rel_info(Relation parentrel, Relation childrel,
|
|||||||
appinfo->child_relid = childRTindex;
|
appinfo->child_relid = childRTindex;
|
||||||
appinfo->parent_reltype = parentrel->rd_rel->reltype;
|
appinfo->parent_reltype = parentrel->rd_rel->reltype;
|
||||||
appinfo->child_reltype = childrel->rd_rel->reltype;
|
appinfo->child_reltype = childrel->rd_rel->reltype;
|
||||||
make_inh_translation_list(parentrel, childrel, childRTindex,
|
make_inh_translation_list(parentrel, childrel, childRTindex, appinfo);
|
||||||
&appinfo->translated_vars);
|
|
||||||
appinfo->parent_reloid = RelationGetRelid(parentrel);
|
appinfo->parent_reloid = RelationGetRelid(parentrel);
|
||||||
|
|
||||||
return appinfo;
|
return appinfo;
|
||||||
@ -65,16 +64,23 @@ make_append_rel_info(Relation parentrel, Relation childrel,
|
|||||||
/*
|
/*
|
||||||
* make_inh_translation_list
|
* make_inh_translation_list
|
||||||
* Build the list of translations from parent Vars to child Vars for
|
* Build the list of translations from parent Vars to child Vars for
|
||||||
* an inheritance child.
|
* an inheritance child, as well as a reverse-translation array.
|
||||||
|
*
|
||||||
|
* The reverse-translation array has an entry for each child relation
|
||||||
|
* column, which is either the 1-based index of the corresponding parent
|
||||||
|
* column, or 0 if there's no match (that happens for dropped child columns,
|
||||||
|
* as well as child columns beyond those of the parent, which are allowed in
|
||||||
|
* traditional inheritance though not partitioning).
|
||||||
*
|
*
|
||||||
* For paranoia's sake, we match type/collation as well as attribute name.
|
* For paranoia's sake, we match type/collation as well as attribute name.
|
||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
||||||
Index newvarno,
|
Index newvarno,
|
||||||
List **translated_vars)
|
AppendRelInfo *appinfo)
|
||||||
{
|
{
|
||||||
List *vars = NIL;
|
List *vars = NIL;
|
||||||
|
AttrNumber *pcolnos;
|
||||||
TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
|
TupleDesc old_tupdesc = RelationGetDescr(oldrelation);
|
||||||
TupleDesc new_tupdesc = RelationGetDescr(newrelation);
|
TupleDesc new_tupdesc = RelationGetDescr(newrelation);
|
||||||
Oid new_relid = RelationGetRelid(newrelation);
|
Oid new_relid = RelationGetRelid(newrelation);
|
||||||
@ -83,6 +89,11 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||||||
int old_attno;
|
int old_attno;
|
||||||
int new_attno = 0;
|
int new_attno = 0;
|
||||||
|
|
||||||
|
/* Initialize reverse-translation array with all entries zero */
|
||||||
|
appinfo->num_child_cols = newnatts;
|
||||||
|
appinfo->parent_colnos = pcolnos =
|
||||||
|
(AttrNumber *) palloc0(newnatts * sizeof(AttrNumber));
|
||||||
|
|
||||||
for (old_attno = 0; old_attno < oldnatts; old_attno++)
|
for (old_attno = 0; old_attno < oldnatts; old_attno++)
|
||||||
{
|
{
|
||||||
Form_pg_attribute att;
|
Form_pg_attribute att;
|
||||||
@ -115,6 +126,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||||||
atttypmod,
|
atttypmod,
|
||||||
attcollation,
|
attcollation,
|
||||||
0));
|
0));
|
||||||
|
pcolnos[old_attno] = old_attno + 1;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -138,6 +150,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||||||
elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
|
elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
|
||||||
attname, RelationGetRelationName(newrelation));
|
attname, RelationGetRelationName(newrelation));
|
||||||
new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
|
new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
|
||||||
|
Assert(new_attno >= 0 && new_attno < newnatts);
|
||||||
ReleaseSysCache(newtup);
|
ReleaseSysCache(newtup);
|
||||||
|
|
||||||
att = TupleDescAttr(new_tupdesc, new_attno);
|
att = TupleDescAttr(new_tupdesc, new_attno);
|
||||||
@ -157,10 +170,11 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||||||
atttypmod,
|
atttypmod,
|
||||||
attcollation,
|
attcollation,
|
||||||
0));
|
0));
|
||||||
|
pcolnos[new_attno] = old_attno + 1;
|
||||||
new_attno++;
|
new_attno++;
|
||||||
}
|
}
|
||||||
|
|
||||||
*translated_vars = vars;
|
appinfo->translated_vars = vars;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -4769,29 +4769,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
|
|||||||
root)->rtekind == RTE_RELATION)
|
root)->rtekind == RTE_RELATION)
|
||||||
{
|
{
|
||||||
int parent_varattno;
|
int parent_varattno;
|
||||||
ListCell *l;
|
|
||||||
|
|
||||||
parent_varattno = 1;
|
|
||||||
found = false;
|
found = false;
|
||||||
foreach(l, appinfo->translated_vars)
|
if (varattno <= 0 || varattno > appinfo->num_child_cols)
|
||||||
{
|
break; /* safety check */
|
||||||
Var *childvar = lfirst_node(Var, l);
|
parent_varattno = appinfo->parent_colnos[varattno - 1];
|
||||||
|
if (parent_varattno == 0)
|
||||||
/* Ignore dropped attributes of the parent. */
|
break; /* Var is local to child */
|
||||||
if (childvar != NULL &&
|
|
||||||
varattno == childvar->varattno)
|
|
||||||
{
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
parent_varattno++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found)
|
|
||||||
break;
|
|
||||||
|
|
||||||
varno = appinfo->parent_relid;
|
varno = appinfo->parent_relid;
|
||||||
varattno = parent_varattno;
|
varattno = parent_varattno;
|
||||||
|
found = true;
|
||||||
|
|
||||||
/* If the parent is itself a child, continue up. */
|
/* If the parent is itself a child, continue up. */
|
||||||
appinfo = root->append_rel_array[varno];
|
appinfo = root->append_rel_array[varno];
|
||||||
|
@ -2151,17 +2151,13 @@ struct SpecialJoinInfo
|
|||||||
* "append relation" (essentially, a list of child RTEs), we build an
|
* "append relation" (essentially, a list of child RTEs), we build an
|
||||||
* AppendRelInfo for each child RTE. The list of AppendRelInfos indicates
|
* AppendRelInfo for each child RTE. The list of AppendRelInfos indicates
|
||||||
* which child RTEs must be included when expanding the parent, and each node
|
* which child RTEs must be included when expanding the parent, and each node
|
||||||
* carries information needed to translate Vars referencing the parent into
|
* carries information needed to translate between columns of the parent and
|
||||||
* Vars referencing that child.
|
* columns of the child.
|
||||||
*
|
*
|
||||||
* These structs are kept in the PlannerInfo node's append_rel_list.
|
* These structs are kept in the PlannerInfo node's append_rel_list, with
|
||||||
* Note that we just throw all the structs into one list, and scan the
|
* append_rel_array[] providing a convenient lookup method for the struct
|
||||||
* whole list when desiring to expand any one parent. We could have used
|
* associated with a particular child relid (there can be only one, though
|
||||||
* a more complex data structure (eg, one list per parent), but this would
|
* parent rels may have many entries in append_rel_list).
|
||||||
* be harder to update during operations such as pulling up subqueries,
|
|
||||||
* and not really any easier to scan. Considering that typical queries
|
|
||||||
* will not have many different append parents, it doesn't seem worthwhile
|
|
||||||
* to complicate things.
|
|
||||||
*
|
*
|
||||||
* Note: after completion of the planner prep phase, any given RTE is an
|
* Note: after completion of the planner prep phase, any given RTE is an
|
||||||
* append parent having entries in append_rel_list if and only if its
|
* append parent having entries in append_rel_list if and only if its
|
||||||
@ -2218,6 +2214,15 @@ typedef struct AppendRelInfo
|
|||||||
*/
|
*/
|
||||||
List *translated_vars; /* Expressions in the child's Vars */
|
List *translated_vars; /* Expressions in the child's Vars */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* This array simplifies translations in the reverse direction, from
|
||||||
|
* child's column numbers to parent's. The entry at [ccolno - 1] is the
|
||||||
|
* 1-based parent column number for child column ccolno, or zero if that
|
||||||
|
* child column is dropped or doesn't exist in the parent.
|
||||||
|
*/
|
||||||
|
int num_child_cols; /* length of array */
|
||||||
|
AttrNumber *parent_colnos; /* array of parent attnos, or zeroes */
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* We store the parent table's OID here for inheritance, or InvalidOid for
|
* We store the parent table's OID here for inheritance, or InvalidOid for
|
||||||
* UNION ALL. This is only needed to help in generating error messages if
|
* UNION ALL. This is only needed to help in generating error messages if
|
||||||
|
Reference in New Issue
Block a user