Add a reverse-translation column number array to struct AppendRelInfo.
authorTom Lane <[email protected]>
Mon, 2 Dec 2019 23:05:29 +0000 (18:05 -0500)
committerTom Lane <[email protected]>
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