Commit ce76c0ba authored by Tom Lane's avatar Tom Lane

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
parent 4526951d
...@@ -2327,6 +2327,8 @@ _copyAppendRelInfo(const AppendRelInfo *from) ...@@ -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) ...@@ -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, ...@@ -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) ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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, ...@@ -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 ...@@ -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 ...@@ -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
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment