Move building of child base quals out into a new function
authorAlvaro Herrera <[email protected]>
Fri, 1 Feb 2019 09:47:49 +0000 (06:47 -0300)
committerAlvaro Herrera <[email protected]>
Fri, 1 Feb 2019 09:47:49 +0000 (06:47 -0300)
An upcoming patch which changes how inheritance planning works requires
adding a new function that does a similar job to set_append_rel_size() but
for child target relations.  To save it from having to duplicate the qual
building code, move that to a separate function first.

Here we also change things so that we never attempt to build security quals
after detecting some const false child quals.  We needlessly used to do this
just before we marked the child relation as a dummy rel.

In passing, this also moves the partition pruned check to before the qual
building code.  We don't need to build the child quals before we check if
the partition has been pruned.

Author: David Rowley
Discussion: https://postgr.es/m/CAKJS1f_i+jrrD+if8qC7KPuTAAWsd=dtepgY_7u=P86GDEwm7A@mail.gmail.com

src/backend/optimizer/path/allpaths.c

index 2144e14ec8d667868be64b5d179a7e6fd38d9833..55b871c02c904ec20b71bd502a441a1ffbc8fa19 100644 (file)
@@ -138,6 +138,9 @@ static void subquery_push_qual(Query *subquery,
 static void recurse_push_qual(Node *setOp, Query *topquery,
                  RangeTblEntry *rte, Index rti, Node *qual);
 static void remove_unused_subquery_outputs(Query *subquery, RelOptInfo *rel);
+static bool apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+                     RelOptInfo *childrel,
+                     RangeTblEntry *childRTE, AppendRelInfo *appinfo);
 
 
 /*
@@ -1010,12 +1013,8 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
        int         childRTindex;
        RangeTblEntry *childRTE;
        RelOptInfo *childrel;
-       List       *childquals;
-       Index       cq_min_security;
-       bool        have_const_false_cq;
        ListCell   *parentvars;
        ListCell   *childvars;
-       ListCell   *lc;
 
        /* append_rel_list contains all append rels; ignore others */
        if (appinfo->parent_relid != parentRTindex)
@@ -1031,119 +1030,21 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
        childrel = find_base_rel(root, childRTindex);
        Assert(childrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
 
-       /*
-        * We have to copy the parent's targetlist and quals to the child,
-        * with appropriate substitution of variables.  However, only the
-        * baserestrictinfo quals are needed before we can check for
-        * constraint exclusion; so do that first and then check to see if we
-        * can disregard this child.
-        *
-        * 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;
-       have_const_false_cq = false;
-       foreach(lc, rel->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 */
-                   have_const_false_cq = true;
-                   break;
-               }
-               /* 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_inherited_rtentry().)  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)
+       if (did_pruning && !bms_is_member(appinfo->child_relid, live_children))
        {
-           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);
+           /* This partition was pruned; skip it. */
+           set_dummy_rel_pathlist(childrel);
+           continue;
        }
 
        /*
-        * OK, we've got all the baserestrictinfo quals for this child.
+        * We have to copy the parent's targetlist and quals to the child,
+        * with appropriate substitution of variables.  If any constant false
+        * or NULL clauses turn up, we can disregard the child right away.
+        * If not, we can apply constraint exclusion with just the
+        * baserestrictinfo quals.
         */
-       childrel->baserestrictinfo = childquals;
-       childrel->baserestrict_min_security = cq_min_security;
-
-       if (have_const_false_cq)
+       if (!apply_child_basequals(root, rel, childrel, childRTE, appinfo))
        {
            /*
             * Some restriction clause reduced to constant FALSE or NULL after
@@ -1153,13 +1054,6 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
            continue;
        }
 
-       if (did_pruning && !bms_is_member(appinfo->child_relid, live_children))
-       {
-           /* This partition was pruned; skip it. */
-           set_dummy_rel_pathlist(childrel);
-           continue;
-       }
-
        if (relation_excluded_by_constraints(root, childrel, childRTE))
        {
            /*
@@ -3660,6 +3554,133 @@ generate_partitionwise_join_paths(PlannerInfo *root, RelOptInfo *rel)
    list_free(live_children);
 }
 
+/*
+ * apply_child_basequals
+ *     Populate childrel's quals based on rel's quals, translating them using
+ *     appinfo.
+ *
+ * If any of the resulting clauses evaluate to false or NULL, we return false
+ * and don't apply any quals.  Caller can mark the relation as a dummy rel in
+ * this case, since it needn't be scanned.
+ *
+ * If any resulting clauses evaluate to true, they're unnecessary and we don't
+ * apply then.
+ */
+static bool
+apply_child_basequals(PlannerInfo *root, RelOptInfo *rel,
+                     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, rel->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_inherited_rtentry().) 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;
+}
 
 /*****************************************************************************
  *         DEBUG SUPPORT