Add a reverse-translation column number array to struct AppendRelInfo.
authorTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Dec 2019 23:05:29 +0000 (18:05 -0500)
committerTom Lane <tgl@sss.pgh.pa.us>
Mon, 2 Dec 2019 23:05:29 +0000 (18:05 -0500)
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

src/backend/nodes/copyfuncs.c
src/backend/nodes/equalfuncs.c
src/backend/nodes/nodeFuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/prep/prepjointree.c
src/backend/optimizer/util/appendinfo.c
src/backend/utils/adt/selfuncs.c
src/include/nodes/pathnodes.h

index 2f267e4bb6538085113608f009cc03698b692078..a74b56bb599dc2eef89a56019decbb330077b074 100644 (file)
@@ -2327,6 +2327,8 @@ _copyAppendRelInfo(const AppendRelInfo *from)
        COPY_SCALAR_FIELD(parent_reltype);
        COPY_SCALAR_FIELD(child_reltype);
        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);
 
        return newnode;
index da0e1d139acbf2e566d5745250eebe654d335d4d..2fcd4a3467e4f4a125950846c449e688a2a2eaf3 100644 (file)
@@ -900,6 +900,8 @@ _equalAppendRelInfo(const AppendRelInfo *a, const AppendRelInfo *b)
        COMPARE_SCALAR_FIELD(parent_reltype);
        COMPARE_SCALAR_FIELD(child_reltype);
        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);
 
        return true;
index bcada740426851cf020bdb5a56aff00fb56c3928..880b0ec6846efb2767c455a7a9d1c05b6554f89f 100644 (file)
@@ -3103,6 +3103,7 @@ expression_tree_mutator(Node *node,
 
                                FLATCOPY(newnode, appinfo, AppendRelInfo);
                                MUTATE(newnode->translated_vars, appinfo->translated_vars, List *);
+                               /* Assume nothing need be done with parent_colnos[] */
                                return (Node *) newnode;
                        }
                        break;
index b0dcd02ff68493864fdf1723d420665d636a13e7..a80eccc2c107747591d640187c043c5006ffb584 100644 (file)
@@ -2509,6 +2509,8 @@ _outAppendRelInfo(StringInfo str, const AppendRelInfo *node)
        WRITE_OID_FIELD(parent_reltype);
        WRITE_OID_FIELD(child_reltype);
        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);
 }
 
index f489f140e3711a0acc1843df69e92585e63617c9..db25bcf441f60a09097f3e9c9d840535017de385 100644 (file)
@@ -81,7 +81,7 @@ static void pull_up_union_leaf_queries(Node *setOp, PlannerInfo *root,
                                                                           int parentRTindex, Query *setOpQuery,
                                                                           int childRToffset);
 static void make_setop_translation_list(Query *query, Index newvarno,
-                                                                               List **translated_vars);
+                                                                               AppendRelInfo *appinfo);
 static bool is_simple_subquery(Query *subquery, RangeTblEntry *rte,
                                                           JoinExpr *lowest_outer_join);
 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->parent_reltype = InvalidOid;
                appinfo->child_reltype = InvalidOid;
-               make_setop_translation_list(setOpQuery, childRTindex,
-                                                                       &appinfo->translated_vars);
+               make_setop_translation_list(setOpQuery, childRTindex, appinfo);
                appinfo->parent_reloid = InvalidOid;
                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
  *       referencing Vars, but if we succeed in pulling up the member
  *       subquery, the Vars will get replaced by pulled-up expressions.)
+ *       Also create the rather trivial reverse-translation array.
  */
 static void
 make_setop_translation_list(Query *query, Index newvarno,
-                                                       List **translated_vars)
+                                                       AppendRelInfo *appinfo)
 {
        List       *vars = NIL;
+       AttrNumber *pcolnos;
        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)
        {
                TargetEntry *tle = (TargetEntry *) lfirst(l);
@@ -1372,9 +1379,10 @@ make_setop_translation_list(Query *query, Index newvarno,
                        continue;
 
                vars = lappend(vars, makeVarFromTargetEntry(newvarno, tle));
+               pcolnos[tle->resno - 1] = tle->resno;
        }
 
-       *translated_vars = vars;
+       appinfo->translated_vars = vars;
 }
 
 /*
index 16d315176ebb7ef230191522b5c0ecea00f7e0ea..1890f256de86149aa01a49b8e3f5155b7a3cae1e 100644 (file)
@@ -34,7 +34,7 @@ typedef struct
 static void make_inh_translation_list(Relation oldrelation,
                                                                          Relation newrelation,
                                                                          Index newvarno,
-                                                                         List **translated_vars);
+                                                                         AppendRelInfo *appinfo);
 static Node *adjust_appendrel_attrs_mutator(Node *node,
                                                                                        adjust_appendrel_attrs_context *context);
 static List *adjust_inherited_tlist(List *tlist,
@@ -55,8 +55,7 @@ make_append_rel_info(Relation parentrel, Relation childrel,
        appinfo->child_relid = childRTindex;
        appinfo->parent_reltype = parentrel->rd_rel->reltype;
        appinfo->child_reltype = childrel->rd_rel->reltype;
-       make_inh_translation_list(parentrel, childrel, childRTindex,
-                                                         &appinfo->translated_vars);
+       make_inh_translation_list(parentrel, childrel, childRTindex, appinfo);
        appinfo->parent_reloid = RelationGetRelid(parentrel);
 
        return appinfo;
@@ -65,16 +64,23 @@ make_append_rel_info(Relation parentrel, Relation childrel,
 /*
  * make_inh_translation_list
  *       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.
  */
 static void
 make_inh_translation_list(Relation oldrelation, Relation newrelation,
                                                  Index newvarno,
-                                                 List **translated_vars)
+                                                 AppendRelInfo *appinfo)
 {
        List       *vars = NIL;
+       AttrNumber *pcolnos;
        TupleDesc       old_tupdesc = RelationGetDescr(oldrelation);
        TupleDesc       new_tupdesc = RelationGetDescr(newrelation);
        Oid                     new_relid = RelationGetRelid(newrelation);
@@ -83,6 +89,11 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
        int                     old_attno;
        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++)
        {
                Form_pg_attribute att;
@@ -115,6 +126,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
                                                                                 atttypmod,
                                                                                 attcollation,
                                                                                 0));
+                       pcolnos[old_attno] = old_attno + 1;
                        continue;
                }
 
@@ -138,6 +150,7 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
                                elog(ERROR, "could not find inherited attribute \"%s\" of relation \"%s\"",
                                         attname, RelationGetRelationName(newrelation));
                        new_attno = ((Form_pg_attribute) GETSTRUCT(newtup))->attnum - 1;
+                       Assert(new_attno >= 0 && new_attno < newnatts);
                        ReleaseSysCache(newtup);
 
                        att = TupleDescAttr(new_tupdesc, new_attno);
@@ -157,10 +170,11 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
                                                                         atttypmod,
                                                                         attcollation,
                                                                         0));
+               pcolnos[new_attno] = old_attno + 1;
                new_attno++;
        }
 
-       *translated_vars = vars;
+       appinfo->translated_vars = vars;
 }
 
 /*
index 35dbd728ecf3c54a7e634f82abd7580fc7c8d41a..ff02b5aafab9607d795672540cd53176c0c9f25d 100644 (file)
@@ -4769,29 +4769,17 @@ examine_simple_variable(PlannerInfo *root, Var *var,
                                                                                root)->rtekind == RTE_RELATION)
                                {
                                        int                     parent_varattno;
-                                       ListCell   *l;
 
-                                       parent_varattno = 1;
                                        found = false;
-                                       foreach(l, appinfo->translated_vars)
-                                       {
-                                               Var                *childvar = lfirst_node(Var, l);
-
-                                               /* Ignore dropped attributes of the parent. */
-                                               if (childvar != NULL &&
-                                                       varattno == childvar->varattno)
-                                               {
-                                                       found = true;
-                                                       break;
-                                               }
-                                               parent_varattno++;
-                                       }
-
-                                       if (!found)
-                                               break;
+                                       if (varattno <= 0 || varattno > appinfo->num_child_cols)
+                                               break;  /* safety check */
+                                       parent_varattno = appinfo->parent_colnos[varattno - 1];
+                                       if (parent_varattno == 0)
+                                               break;  /* Var is local to child */
 
                                        varno = appinfo->parent_relid;
                                        varattno = parent_varattno;
+                                       found = true;
 
                                        /* If the parent is itself a child, continue up. */
                                        appinfo = root->append_rel_array[varno];
index 23a06d718e3ab73bed9dbe3213eb2e0ad30bee28..6dab810d68f6c0b8ca2db09947e509d59e372dce 100644 (file)
@@ -2151,17 +2151,13 @@ struct SpecialJoinInfo
  * "append relation" (essentially, a list of child RTEs), we build an
  * AppendRelInfo for each child RTE.  The list of AppendRelInfos indicates
  * which child RTEs must be included when expanding the parent, and each node
- * carries information needed to translate Vars referencing the parent into
- * Vars referencing that child.
- *
- * These structs are kept in the PlannerInfo node's append_rel_list.
- * Note that we just throw all the structs into one list, and scan the
- * whole list when desiring to expand any one parent.  We could have used
- * a more complex data structure (eg, one list per parent), but this would
- * 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.
+ * carries information needed to translate between columns of the parent and
+ * columns of the child.
+ *
+ * These structs are kept in the PlannerInfo node's append_rel_list, with
+ * append_rel_array[] providing a convenient lookup method for the struct
+ * associated with a particular child relid (there can be only one, though
+ * parent rels may have many entries in append_rel_list).
  *
  * 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
@@ -2218,6 +2214,15 @@ typedef struct AppendRelInfo
         */
        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
         * UNION ALL.  This is only needed to help in generating error messages if