]> granicus.if.org Git - postgresql/commitdiff
Revise the planner's handling of "pseudoconstant" WHERE clauses, that is
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Jul 2006 18:38:33 +0000 (18:38 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 1 Jul 2006 18:38:33 +0000 (18:38 +0000)
clauses containing no variables and no volatile functions.  Such a clause
can be used as a one-time qual in a gating Result plan node, to suppress
plan execution entirely when it is false.  Even when the clause is true,
putting it in a gating node wins by avoiding repeated evaluation of the
clause.  In previous PG releases, query_planner() would do this for
pseudoconstant clauses appearing at the top level of the jointree, but
there was no ability to generate a gating Result deeper in the plan tree.
To fix it, get rid of the special case in query_planner(), and instead
process pseudoconstant clauses through the normal RestrictInfo qual
distribution mechanism.  When a pseudoconstant clause is found attached to
a path node in create_plan(), pull it out and generate a gating Result at
that point.  This requires special-casing pseudoconstants in selectivity
estimation and cost_qual_eval, but on the whole it's pretty clean.
It probably even makes the planner a bit faster than before for the normal
case of no pseudoconstants, since removing pull_constant_clauses saves one
useless traversal of the qual tree.  Per gripe from Phil Frost.

20 files changed:
src/backend/nodes/copyfuncs.c
src/backend/nodes/outfuncs.c
src/backend/optimizer/README
src/backend/optimizer/path/allpaths.c
src/backend/optimizer/path/clausesel.c
src/backend/optimizer/path/costsize.c
src/backend/optimizer/path/indxpath.c
src/backend/optimizer/plan/createplan.c
src/backend/optimizer/plan/initsplan.c
src/backend/optimizer/plan/planagg.c
src/backend/optimizer/plan/planmain.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/pathnode.c
src/backend/optimizer/util/restrictinfo.c
src/include/nodes/relation.h
src/include/optimizer/clauses.h
src/include/optimizer/pathnode.h
src/include/optimizer/planmain.h
src/include/optimizer/restrictinfo.h

index 2f2111458e025ef4b68b5766d135f3bb4d91dd8b..6cf580c136c8887c04d48e6d2f9dcbaa5c5ec62f 100644 (file)
@@ -15,7 +15,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.337 2006/06/27 03:43:19 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/copyfuncs.c,v 1.338 2006/07/01 18:38:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1264,6 +1264,7 @@ _copyRestrictInfo(RestrictInfo *from)
        COPY_SCALAR_FIELD(is_pushed_down);
        COPY_SCALAR_FIELD(outerjoin_delayed);
        COPY_SCALAR_FIELD(can_join);
+       COPY_SCALAR_FIELD(pseudoconstant);
        COPY_BITMAPSET_FIELD(clause_relids);
        COPY_BITMAPSET_FIELD(required_relids);
        COPY_BITMAPSET_FIELD(left_relids);
index 25d3a112799e9b1802d7f32bf81f59ef5ff3ea06..7444001acb8927bc9671bbae0a722216ebff4ff1 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.274 2006/04/30 18:30:39 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/nodes/outfuncs.c,v 1.275 2006/07/01 18:38:32 tgl Exp $
  *
  * NOTES
  *       Every node type that can appear in stored rules' parsetrees *must*
@@ -1107,8 +1107,7 @@ _outResultPath(StringInfo str, ResultPath *node)
 
        _outPathInfo(str, (Path *) node);
 
-       WRITE_NODE_FIELD(subpath);
-       WRITE_NODE_FIELD(constantqual);
+       WRITE_NODE_FIELD(quals);
 }
 
 static void
@@ -1185,6 +1184,7 @@ _outPlannerInfo(StringInfo str, PlannerInfo *node)
        WRITE_BOOL_FIELD(hasJoinRTEs);
        WRITE_BOOL_FIELD(hasOuterJoins);
        WRITE_BOOL_FIELD(hasHavingQual);
+       WRITE_BOOL_FIELD(hasPseudoConstantQuals);
 }
 
 static void
@@ -1252,6 +1252,7 @@ _outRestrictInfo(StringInfo str, RestrictInfo *node)
        WRITE_BOOL_FIELD(is_pushed_down);
        WRITE_BOOL_FIELD(outerjoin_delayed);
        WRITE_BOOL_FIELD(can_join);
+       WRITE_BOOL_FIELD(pseudoconstant);
        WRITE_BITMAPSET_FIELD(clause_relids);
        WRITE_BITMAPSET_FIELD(required_relids);
        WRITE_BITMAPSET_FIELD(left_relids);
index df9828b21505500e7ed240367607fafcae985e2e..f0bb64d1a9abc1354e126f21e5c079efc625b3b2 100644 (file)
@@ -329,7 +329,7 @@ RelOptInfo      - a relation or joined relations
   BitmapHeapPath - top of a bitmapped index scan
   TidPath       - scan by CTID
   AppendPath    - append multiple subpaths together
-  ResultPath    - a Result plan node (used for variable-free tlist or qual)
+  ResultPath    - a Result plan node (used for FROM-less SELECT)
   MaterialPath  - a Material plan node
   UniquePath    - remove duplicate rows
   NestPath      - nested-loop joins
index de82c3df8d08308e67e889b253bdcd9af7e6ca23..ad55360a85337ec397009ee3576c7a1f43344d83 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.146 2006/05/02 04:34:18 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/allpaths.c,v 1.147 2006/07/01 18:38:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -446,7 +446,9 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
         * There are several cases where we cannot push down clauses. Restrictions
         * involving the subquery are checked by subquery_is_pushdown_safe().
         * Restrictions on individual clauses are checked by
-        * qual_is_pushdown_safe().
+        * qual_is_pushdown_safe().  Also, we don't want to push down
+        * pseudoconstant clauses; better to have the gating node above the
+        * subquery.
         *
         * Non-pushed-down clauses will get evaluated as qpquals of the
         * SubqueryScan node.
@@ -466,7 +468,8 @@ set_subquery_pathlist(PlannerInfo *root, RelOptInfo *rel,
                        RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
                        Node       *clause = (Node *) rinfo->clause;
 
-                       if (qual_is_pushdown_safe(subquery, rti, clause, differentTypes))
+                       if (!rinfo->pseudoconstant &&
+                               qual_is_pushdown_safe(subquery, rti, clause, differentTypes))
                        {
                                /* Push it down */
                                subquery_push_qual(subquery, rte, rti, clause);
@@ -1066,7 +1069,6 @@ print_path(PlannerInfo *root, Path *path, int indent)
                        break;
                case T_ResultPath:
                        ptype = "Result";
-                       subpath = ((ResultPath *) path)->subpath;
                        break;
                case T_MaterialPath:
                        ptype = "Material";
index 3ff02902f7c7e52c82bce4981b0f44105c62dc01..f595a3f07f34ad96c95ff253c52327426a91ce6d 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.79 2006/03/07 01:00:15 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.80 2006/07/01 18:38:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -117,10 +117,18 @@ clauselist_selectivity(PlannerInfo *root,
 
                /*
                 * Check for being passed a RestrictInfo.
+                *
+                * If it's a pseudoconstant RestrictInfo, then s2 is either 1.0 or
+                * 0.0; just use that rather than looking for range pairs.
                 */
                if (IsA(clause, RestrictInfo))
                {
                        rinfo = (RestrictInfo *) clause;
+                       if (rinfo->pseudoconstant)
+                       {
+                               s1 = s1 * s2;
+                               continue;
+                       }
                        clause = (Node *) rinfo->clause;
                }
                else
@@ -422,6 +430,20 @@ clause_selectivity(PlannerInfo *root,
        {
                rinfo = (RestrictInfo *) clause;
 
+               /*
+                * If the clause is marked pseudoconstant, then it will be used as
+                * a gating qual and should not affect selectivity estimates; hence
+                * return 1.0.  The only exception is that a constant FALSE may
+                * be taken as having selectivity 0.0, since it will surely mean
+                * no rows out of the plan.  This case is simple enough that we
+                * need not bother caching the result.
+                */
+               if (rinfo->pseudoconstant)
+               {
+                       if (! IsA(rinfo->clause, Const))
+                               return s1;
+               }
+
                /*
                 * If possible, cache the result of the selectivity calculation for
                 * the clause.  We can cache if varRelid is zero or the clause
@@ -509,7 +531,10 @@ clause_selectivity(PlannerInfo *root,
        else if (IsA(clause, Const))
        {
                /* bool constant is pretty easy... */
-               s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
+               Const  *con = (Const *) clause;
+
+               s1 = con->constisnull ? 0.0 :
+                       DatumGetBool(con->constvalue) ? 1.0 : 0.0;
        }
        else if (IsA(clause, Param))
        {
@@ -519,7 +544,10 @@ clause_selectivity(PlannerInfo *root,
                if (IsA(subst, Const))
                {
                        /* bool constant is pretty easy... */
-                       s1 = ((bool) ((Const *) subst)->constvalue) ? 1.0 : 0.0;
+                       Const  *con = (Const *) subst;
+
+                       s1 = con->constisnull ? 0.0 :
+                               DatumGetBool(con->constvalue) ? 1.0 : 0.0;
                }
                else
                {
index fa8d06707b891713218ab2efd36ca7f776204679..eec165ab5db96023e616d4d07e16fbaf416c8e5f 100644 (file)
@@ -54,7 +54,7 @@
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.158 2006/06/06 17:59:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/costsize.c,v 1.159 2006/07/01 18:38:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -1604,20 +1604,29 @@ cost_qual_eval(QualCost *cost, List *quals)
                 * routine's use, so that it's not necessary to evaluate the qual
                 * clause's cost more than once.  If the clause's cost hasn't been
                 * computed yet, the field's startup value will contain -1.
+                *
+                * If the RestrictInfo is marked pseudoconstant, it will be tested
+                * only once, so treat its cost as all startup cost.
                 */
                if (qual && IsA(qual, RestrictInfo))
                {
-                       RestrictInfo *restrictinfo = (RestrictInfo *) qual;
+                       RestrictInfo *rinfo = (RestrictInfo *) qual;
 
-                       if (restrictinfo->eval_cost.startup < 0)
+                       if (rinfo->eval_cost.startup < 0)
                        {
-                               restrictinfo->eval_cost.startup = 0;
-                               restrictinfo->eval_cost.per_tuple = 0;
-                               cost_qual_eval_walker((Node *) restrictinfo->clause,
-                                                                         &restrictinfo->eval_cost);
+                               rinfo->eval_cost.startup = 0;
+                               rinfo->eval_cost.per_tuple = 0;
+                               cost_qual_eval_walker((Node *) rinfo->clause,
+                                                                         &rinfo->eval_cost);
+                               if (rinfo->pseudoconstant)
+                               {
+                                       /* count one execution during startup */
+                                       rinfo->eval_cost.startup += rinfo->eval_cost.per_tuple;
+                                       rinfo->eval_cost.per_tuple = 0;
+                               }
                        }
-                       cost->startup += restrictinfo->eval_cost.startup;
-                       cost->per_tuple += restrictinfo->eval_cost.per_tuple;
+                       cost->startup += rinfo->eval_cost.startup;
+                       cost->per_tuple += rinfo->eval_cost.per_tuple;
                }
                else
                {
@@ -1876,7 +1885,9 @@ set_joinrel_size_estimates(PlannerInfo *root, RelOptInfo *rel,
         *
         * If we are doing an outer join, take that into account: the output must
         * be at least as large as the non-nullable input.      (Is there any chance
-        * of being even smarter?)
+        * of being even smarter?)  (XXX this is not really right, because it
+        * assumes all the restriction clauses are join clauses; we should figure
+        * pushed-down clauses separately.)
         *
         * For JOIN_IN and variants, the Cartesian product is figured with respect
         * to a unique-ified input, and then we can clamp to the size of the other
index 75f2487757e852f6db6f1c88ff3d451412e1c6b6..6e6f4ac3a713fe2f9f1a7a1304846eb9b9cda9e5 100644 (file)
@@ -9,7 +9,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.208 2006/06/07 17:08:07 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/path/indxpath.c,v 1.209 2006/07/01 18:38:32 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -998,6 +998,15 @@ match_clause_to_indexcol(IndexOptInfo *index,
        Oid                     expr_op;
        bool            plain_op;
 
+       /*
+        * Never match pseudoconstants to indexes.  (Normally this could not
+        * happen anyway, since a pseudoconstant clause couldn't contain a
+        * Var, but what if someone builds an expression index on a constant?
+        * It's not totally unreasonable to do so with a partial index, either.)
+        */
+       if (rinfo->pseudoconstant)
+               return false;
+
        /* First check for boolean-index cases. */
        if (IsBooleanOpclass(opclass))
        {
@@ -2212,6 +2221,7 @@ expand_indexqual_conditions(IndexOptInfo *index, List *clausegroups)
                                                                                  make_restrictinfo(boolqual,
                                                                                                                        true,
                                                                                                                        false,
+                                                                                                                       false,
                                                                                                                        NULL));
                                        continue;
                                }
@@ -2577,7 +2587,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                                                                  matching_cols);
                rc->rargs = list_truncate((List *) copyObject(clause->rargs),
                                                                  matching_cols);
-               return make_restrictinfo((Expr *) rc, true, false, NULL);
+               return make_restrictinfo((Expr *) rc, true, false, false, NULL);
        }
        else
        {
@@ -2586,7 +2596,7 @@ expand_indexqual_rowcompare(RestrictInfo *rinfo,
                opexpr = make_opclause(linitial_oid(new_ops), BOOLOID, false,
                                                           copyObject(linitial(clause->largs)),
                                                           copyObject(linitial(clause->rargs)));
-               return make_restrictinfo(opexpr, true, false, NULL);
+               return make_restrictinfo(opexpr, true, false, false, NULL);
        }
 }
 
@@ -2678,7 +2688,7 @@ prefix_quals(Node *leftop, Oid opclass,
                        elog(ERROR, "no = operator for opclass %u", opclass);
                expr = make_opclause(oproid, BOOLOID, false,
                                                         (Expr *) leftop, (Expr *) prefix_const);
-               result = list_make1(make_restrictinfo(expr, true, false, NULL));
+               result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
                return result;
        }
 
@@ -2693,7 +2703,7 @@ prefix_quals(Node *leftop, Oid opclass,
                elog(ERROR, "no >= operator for opclass %u", opclass);
        expr = make_opclause(oproid, BOOLOID, false,
                                                 (Expr *) leftop, (Expr *) prefix_const);
-       result = list_make1(make_restrictinfo(expr, true, false, NULL));
+       result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
 
        /*-------
         * If we can create a string larger than the prefix, we can say
@@ -2709,7 +2719,8 @@ prefix_quals(Node *leftop, Oid opclass,
                        elog(ERROR, "no < operator for opclass %u", opclass);
                expr = make_opclause(oproid, BOOLOID, false,
                                                         (Expr *) leftop, (Expr *) greaterstr);
-               result = lappend(result, make_restrictinfo(expr, true, false, NULL));
+               result = lappend(result,
+                                                make_restrictinfo(expr, true, false, false, NULL));
        }
 
        return result;
@@ -2772,7 +2783,7 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
                                                 (Expr *) leftop,
                                                 (Expr *) makeConst(datatype, -1, opr1right,
                                                                                        false, false));
-       result = list_make1(make_restrictinfo(expr, true, false, NULL));
+       result = list_make1(make_restrictinfo(expr, true, false, false, NULL));
 
        /* create clause "key <= network_scan_last( rightop )" */
 
@@ -2787,7 +2798,8 @@ network_prefix_quals(Node *leftop, Oid expr_op, Oid opclass, Datum rightop)
                                                 (Expr *) leftop,
                                                 (Expr *) makeConst(datatype, -1, opr2right,
                                                                                        false, false));
-       result = lappend(result, make_restrictinfo(expr, true, false, NULL));
+       result = lappend(result,
+                                        make_restrictinfo(expr, true, false, false, NULL));
 
        return result;
 }
index 1cad6574f3783b8e29df3130a5937ef83a9670cb..7a9bb08b89c9a9ada4a023314b539dbbaa0133d9 100644 (file)
@@ -10,7 +10,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.211 2006/05/18 18:57:31 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/createplan.c,v 1.212 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include "utils/syscache.h"
 
 
-static Scan *create_scan_plan(PlannerInfo *root, Path *best_path);
+static Plan *create_scan_plan(PlannerInfo *root, Path *best_path);
 static List *build_relation_tlist(RelOptInfo *rel);
 static bool use_physical_tlist(RelOptInfo *rel);
 static void disuse_physical_tlist(Plan *plan, Path *path);
-static Join *create_join_plan(PlannerInfo *root, JoinPath *best_path);
+static Plan *create_gating_plan(PlannerInfo *root, Plan *plan, List *quals);
+static Plan *create_join_plan(PlannerInfo *root, JoinPath *best_path);
 static Plan *create_append_plan(PlannerInfo *root, AppendPath *best_path);
 static Result *create_result_plan(PlannerInfo *root, ResultPath *best_path);
 static Material *create_material_plan(PlannerInfo *root, MaterialPath *best_path);
@@ -74,6 +75,7 @@ static void fix_indexqual_references(List *indexquals, IndexPath *index_path,
 static Node *fix_indexqual_operand(Node *node, IndexOptInfo *index,
                                          Oid *opclass);
 static List *get_switched_clauses(List *clauses, Relids outerrelids);
+static List *order_qual_clauses(PlannerInfo *root, List *clauses);
 static void copy_path_costsize(Plan *dest, Path *src);
 static void copy_plan_costsize(Plan *dest, Plan *src);
 static SeqScan *make_seqscan(List *qptlist, List *qpqual, Index scanrelid);
@@ -146,17 +148,17 @@ create_plan(PlannerInfo *root, Path *best_path)
                case T_TidScan:
                case T_SubqueryScan:
                case T_FunctionScan:
-                       plan = (Plan *) create_scan_plan(root, best_path);
+                       plan = create_scan_plan(root, best_path);
                        break;
                case T_HashJoin:
                case T_MergeJoin:
                case T_NestLoop:
-                       plan = (Plan *) create_join_plan(root,
-                                                                                        (JoinPath *) best_path);
+                       plan = create_join_plan(root,
+                                                                       (JoinPath *) best_path);
                        break;
                case T_Append:
-                       plan = (Plan *) create_append_plan(root,
-                                                                                          (AppendPath *) best_path);
+                       plan = create_append_plan(root,
+                                                                         (AppendPath *) best_path);
                        break;
                case T_Result:
                        plan = (Plan *) create_result_plan(root,
@@ -167,8 +169,8 @@ create_plan(PlannerInfo *root, Path *best_path)
                                                                                                 (MaterialPath *) best_path);
                        break;
                case T_Unique:
-                       plan = (Plan *) create_unique_plan(root,
-                                                                                          (UniquePath *) best_path);
+                       plan = create_unique_plan(root,
+                                                                         (UniquePath *) best_path);
                        break;
                default:
                        elog(ERROR, "unrecognized node type: %d",
@@ -183,16 +185,14 @@ create_plan(PlannerInfo *root, Path *best_path)
 /*
  * create_scan_plan
  *      Create a scan plan for the parent relation of 'best_path'.
- *
- *      Returns a Plan node.
  */
-static Scan *
+static Plan *
 create_scan_plan(PlannerInfo *root, Path *best_path)
 {
        RelOptInfo *rel = best_path->parent;
        List       *tlist;
        List       *scan_clauses;
-       Scan       *plan;
+       Plan       *plan;
 
        /*
         * For table scans, rather than using the relation targetlist (which is
@@ -213,22 +213,23 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
                tlist = build_relation_tlist(rel);
 
        /*
-        * Extract the relevant restriction clauses from the parent relation; the
-        * executor must apply all these restrictions during the scan.
+        * Extract the relevant restriction clauses from the parent relation.
+        * The executor must apply all these restrictions during the scan,
+        * except for pseudoconstants which we'll take care of below.
         */
        scan_clauses = rel->baserestrictinfo;
 
        switch (best_path->pathtype)
        {
                case T_SeqScan:
-                       plan = (Scan *) create_seqscan_plan(root,
+                       plan = (Plan *) create_seqscan_plan(root,
                                                                                                best_path,
                                                                                                tlist,
                                                                                                scan_clauses);
                        break;
 
                case T_IndexScan:
-                       plan = (Scan *) create_indexscan_plan(root,
+                       plan = (Plan *) create_indexscan_plan(root,
                                                                                                  (IndexPath *) best_path,
                                                                                                  tlist,
                                                                                                  scan_clauses,
@@ -236,28 +237,28 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
                        break;
 
                case T_BitmapHeapScan:
-                       plan = (Scan *) create_bitmap_scan_plan(root,
+                       plan = (Plan *) create_bitmap_scan_plan(root,
                                                                                                (BitmapHeapPath *) best_path,
                                                                                                        tlist,
                                                                                                        scan_clauses);
                        break;
 
                case T_TidScan:
-                       plan = (Scan *) create_tidscan_plan(root,
+                       plan = (Plan *) create_tidscan_plan(root,
                                                                                                (TidPath *) best_path,
                                                                                                tlist,
                                                                                                scan_clauses);
                        break;
 
                case T_SubqueryScan:
-                       plan = (Scan *) create_subqueryscan_plan(root,
+                       plan = (Plan *) create_subqueryscan_plan(root,
                                                                                                         best_path,
                                                                                                         tlist,
                                                                                                         scan_clauses);
                        break;
 
                case T_FunctionScan:
-                       plan = (Scan *) create_functionscan_plan(root,
+                       plan = (Plan *) create_functionscan_plan(root,
                                                                                                         best_path,
                                                                                                         tlist,
                                                                                                         scan_clauses);
@@ -270,6 +271,14 @@ create_scan_plan(PlannerInfo *root, Path *best_path)
                        break;
        }
 
+       /*
+        * If there are any pseudoconstant clauses attached to this node,
+        * insert a gating Result node that evaluates the pseudoconstants
+        * as one-time quals.
+        */
+       if (root->hasPseudoConstantQuals)
+               plan = create_gating_plan(root, plan, scan_clauses);
+
        return plan;
 }
 
@@ -365,19 +374,54 @@ disuse_physical_tlist(Plan *plan, Path *path)
        }
 }
 
+/*
+ * create_gating_plan
+ *       Deal with pseudoconstant qual clauses
+ *
+ * If the node's quals list includes any pseudoconstant quals, put them
+ * into a gating Result node atop the already-built plan.  Otherwise,
+ * return the plan as-is.
+ *
+ * Note that we don't change cost or size estimates when doing gating.
+ * The costs of qual eval were already folded into the plan's startup cost.
+ * Leaving the size alone amounts to assuming that the gating qual will
+ * succeed, which is the conservative estimate for planning upper queries.
+ * We certainly don't want to assume the output size is zero (unless the
+ * gating qual is actually constant FALSE, and that case is dealt with in
+ * clausesel.c).  Interpolating between the two cases is silly, because
+ * it doesn't reflect what will really happen at runtime, and besides which
+ * in most cases we have only a very bad idea of the probability of the gating
+ * qual being true.
+ */
+static Plan *
+create_gating_plan(PlannerInfo *root, Plan *plan, List *quals)
+{
+       List       *pseudoconstants;
+
+       /* Pull out any pseudoconstant quals from the RestrictInfo list */
+       pseudoconstants = extract_actual_clauses(quals, true);
+
+       if (!pseudoconstants)
+               return plan;
+
+       pseudoconstants = order_qual_clauses(root, pseudoconstants);
+
+       return (Plan *) make_result((List *) copyObject(plan->targetlist),
+                                                               (Node *) pseudoconstants,
+                                                               plan);
+}
+
 /*
  * create_join_plan
  *       Create a join plan for 'best_path' and (recursively) plans for its
  *       inner and outer paths.
- *
- *       Returns a Plan node.
  */
-static Join *
+static Plan *
 create_join_plan(PlannerInfo *root, JoinPath *best_path)
 {
        Plan       *outer_plan;
        Plan       *inner_plan;
-       Join       *plan;
+       Plan       *plan;
 
        outer_plan = create_plan(root, best_path->outerjoinpath);
        inner_plan = create_plan(root, best_path->innerjoinpath);
@@ -385,19 +429,19 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
        switch (best_path->path.pathtype)
        {
                case T_MergeJoin:
-                       plan = (Join *) create_mergejoin_plan(root,
+                       plan = (Plan *) create_mergejoin_plan(root,
                                                                                                  (MergePath *) best_path,
                                                                                                  outer_plan,
                                                                                                  inner_plan);
                        break;
                case T_HashJoin:
-                       plan = (Join *) create_hashjoin_plan(root,
+                       plan = (Plan *) create_hashjoin_plan(root,
                                                                                                 (HashPath *) best_path,
                                                                                                 outer_plan,
                                                                                                 inner_plan);
                        break;
                case T_NestLoop:
-                       plan = (Join *) create_nestloop_plan(root,
+                       plan = (Plan *) create_nestloop_plan(root,
                                                                                                 (NestPath *) best_path,
                                                                                                 outer_plan,
                                                                                                 inner_plan);
@@ -409,6 +453,14 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
                        break;
        }
 
+       /*
+        * If there are any pseudoconstant clauses attached to this node,
+        * insert a gating Result node that evaluates the pseudoconstants
+        * as one-time quals.
+        */
+       if (root->hasPseudoConstantQuals)
+               plan = create_gating_plan(root, plan, best_path->joinrestrictinfo);
+
 #ifdef NOT_USED
 
        /*
@@ -473,34 +525,24 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
 
 /*
  * create_result_plan
- *       Create a Result plan for 'best_path' and (recursively) plans
- *       for its subpaths.
+ *       Create a Result plan for 'best_path'.
+ *       This is only used for the case of a query with an empty jointree.
  *
  *       Returns a Plan node.
  */
 static Result *
 create_result_plan(PlannerInfo *root, ResultPath *best_path)
 {
-       Result     *plan;
        List       *tlist;
-       List       *constclauses;
-       Plan       *subplan;
+       List       *quals;
 
-       if (best_path->path.parent)
-               tlist = build_relation_tlist(best_path->path.parent);
-       else
-               tlist = NIL;                    /* will be filled in later */
-
-       if (best_path->subpath)
-               subplan = create_plan(root, best_path->subpath);
-       else
-               subplan = NULL;
+       /* The tlist will be installed later, since we have no RelOptInfo */
+       Assert(best_path->path.parent == NULL);
+       tlist = NIL;
 
-       constclauses = order_qual_clauses(root, best_path->constantqual);
+       quals = order_qual_clauses(root, best_path->quals);
 
-       plan = make_result(tlist, (Node *) constclauses, subplan);
-
-       return plan;
+       return make_result(tlist, (Node *) quals, NULL);
 }
 
 /*
@@ -716,8 +758,8 @@ create_seqscan_plan(PlannerInfo *root, Path *best_path,
        Assert(scan_relid > 0);
        Assert(best_path->parent->rtekind == RTE_RELATION);
 
-       /* Reduce RestrictInfo list to bare expressions */
-       scan_clauses = get_actual_clauses(scan_clauses);
+       /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
 
        /* Sort clauses into best execution order */
        scan_clauses = order_qual_clauses(root, scan_clauses);
@@ -824,7 +866,8 @@ create_indexscan_plan(PlannerInfo *root,
         * plan so that they'll be properly rechecked by EvalPlanQual testing.
         *
         * While at it, we strip off the RestrictInfos to produce a list of plain
-        * expressions.
+        * expressions (this loop replaces extract_actual_clauses used in the
+        * other routines in this file).  We have to ignore pseudoconstants.
         */
        qpqual = NIL;
        foreach(l, scan_clauses)
@@ -832,6 +875,8 @@ create_indexscan_plan(PlannerInfo *root,
                RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
 
                Assert(IsA(rinfo, RestrictInfo));
+               if (rinfo->pseudoconstant)
+                       continue;
                if (list_member_ptr(nonlossy_indexquals, rinfo))
                        continue;
                if (!contain_mutable_functions((Node *) rinfo->clause))
@@ -900,8 +945,8 @@ create_bitmap_scan_plan(PlannerInfo *root,
        bitmapqualplan = create_bitmap_subplan(root, best_path->bitmapqual,
                                                                                   &bitmapqualorig, &indexquals);
 
-       /* Reduce RestrictInfo list to bare expressions */
-       scan_clauses = get_actual_clauses(scan_clauses);
+       /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
 
        /*
         * If this is a innerjoin scan, the indexclauses will contain join clauses
@@ -1183,8 +1228,8 @@ create_tidscan_plan(PlannerInfo *root, TidPath *best_path,
        Assert(scan_relid > 0);
        Assert(best_path->path.parent->rtekind == RTE_RELATION);
 
-       /* Reduce RestrictInfo list to bare expressions */
-       scan_clauses = get_actual_clauses(scan_clauses);
+       /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
 
        /*
         * Remove any clauses that are TID quals.  This is a bit tricky since
@@ -1224,8 +1269,8 @@ create_subqueryscan_plan(PlannerInfo *root, Path *best_path,
        Assert(scan_relid > 0);
        Assert(best_path->parent->rtekind == RTE_SUBQUERY);
 
-       /* Reduce RestrictInfo list to bare expressions */
-       scan_clauses = get_actual_clauses(scan_clauses);
+       /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
 
        /* Sort clauses into best execution order */
        scan_clauses = order_qual_clauses(root, scan_clauses);
@@ -1256,8 +1301,8 @@ create_functionscan_plan(PlannerInfo *root, Path *best_path,
        Assert(scan_relid > 0);
        Assert(best_path->parent->rtekind == RTE_FUNCTION);
 
-       /* Reduce RestrictInfo list to bare expressions */
-       scan_clauses = get_actual_clauses(scan_clauses);
+       /* Reduce RestrictInfo list to bare expressions; ignore pseudoconstants */
+       scan_clauses = extract_actual_clauses(scan_clauses, false);
 
        /* Sort clauses into best execution order */
        scan_clauses = order_qual_clauses(root, scan_clauses);
@@ -1348,15 +1393,16 @@ create_nestloop_plan(PlannerInfo *root,
        }
 
        /* Get the join qual clauses (in plain expression form) */
+       /* Any pseudoconstant clauses are ignored here */
        if (IS_OUTER_JOIN(best_path->jointype))
        {
-               get_actual_join_clauses(joinrestrictclauses,
-                                                               &joinclauses, &otherclauses);
+               extract_actual_join_clauses(joinrestrictclauses,
+                                                                       &joinclauses, &otherclauses);
        }
        else
        {
                /* We can treat all clauses alike for an inner join */
-               joinclauses = get_actual_clauses(joinrestrictclauses);
+               joinclauses = extract_actual_clauses(joinrestrictclauses, false);
                otherclauses = NIL;
        }
 
@@ -1389,15 +1435,17 @@ create_mergejoin_plan(PlannerInfo *root,
        MergeJoin  *join_plan;
 
        /* Get the join qual clauses (in plain expression form) */
+       /* Any pseudoconstant clauses are ignored here */
        if (IS_OUTER_JOIN(best_path->jpath.jointype))
        {
-               get_actual_join_clauses(best_path->jpath.joinrestrictinfo,
-                                                               &joinclauses, &otherclauses);
+               extract_actual_join_clauses(best_path->jpath.joinrestrictinfo,
+                                                                       &joinclauses, &otherclauses);
        }
        else
        {
                /* We can treat all clauses alike for an inner join */
-               joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);
+               joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo,
+                                                                                        false);
                otherclauses = NIL;
        }
 
@@ -1473,15 +1521,17 @@ create_hashjoin_plan(PlannerInfo *root,
        Hash       *hash_plan;
 
        /* Get the join qual clauses (in plain expression form) */
+       /* Any pseudoconstant clauses are ignored here */
        if (IS_OUTER_JOIN(best_path->jpath.jointype))
        {
-               get_actual_join_clauses(best_path->jpath.joinrestrictinfo,
-                                                               &joinclauses, &otherclauses);
+               extract_actual_join_clauses(best_path->jpath.joinrestrictinfo,
+                                                                       &joinclauses, &otherclauses);
        }
        else
        {
                /* We can treat all clauses alike for an inner join */
-               joinclauses = get_actual_clauses(best_path->jpath.joinrestrictinfo);
+               joinclauses = extract_actual_clauses(best_path->jpath.joinrestrictinfo,
+                                                                                        false);
                otherclauses = NIL;
        }
 
@@ -1831,7 +1881,7 @@ get_switched_clauses(List *clauses, Relids outerrelids)
  * For now, we just move any quals that contain SubPlan references (but not
  * InitPlan references) to the end of the list.
  */
-List *
+static List *
 order_qual_clauses(PlannerInfo *root, List *clauses)
 {
        List       *nosubplans;
@@ -2880,6 +2930,15 @@ make_limit(Plan *lefttree, Node *limitOffset, Node *limitCount,
        return node;
 }
 
+/*
+ * make_result
+ *       Build a Result plan node
+ *
+ * If we have a subplan, assume that any evaluation costs for the gating qual
+ * were already factored into the subplan's startup cost, and just copy the
+ * subplan cost.  If there's no subplan, we should include the qual eval
+ * cost.  In either case, tlist eval cost is not to be included here.
+ */
 Result *
 make_result(List *tlist,
                        Node *resconstantqual,
@@ -2895,17 +2954,16 @@ make_result(List *tlist,
                plan->startup_cost = 0;
                plan->total_cost = cpu_tuple_cost;
                plan->plan_rows = 1;    /* wrong if we have a set-valued function? */
-               plan->plan_width = 0;   /* XXX try to be smarter? */
-       }
-
-       if (resconstantqual)
-       {
-               QualCost        qual_cost;
+               plan->plan_width = 0;   /* XXX is it worth being smarter? */
+               if (resconstantqual)
+               {
+                       QualCost        qual_cost;
 
-               cost_qual_eval(&qual_cost, (List *) resconstantqual);
-               /* resconstantqual is evaluated once at startup */
-               plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
-               plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
+                       cost_qual_eval(&qual_cost, (List *) resconstantqual);
+                       /* resconstantqual is evaluated once at startup */
+                       plan->startup_cost += qual_cost.startup + qual_cost.per_tuple;
+                       plan->total_cost += qual_cost.startup + qual_cost.per_tuple;
+               }
        }
 
        plan->targetlist = tlist;
index 1c04a8784d296eed421059f0592e9c6ec922bdf4..bf8e67d0dcd07ea6135de6144f2531a0adf58896 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.117 2006/03/14 22:48:19 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/initsplan.c,v 1.118 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -23,6 +23,7 @@
 #include "optimizer/pathnode.h"
 #include "optimizer/paths.h"
 #include "optimizer/planmain.h"
+#include "optimizer/prep.h"
 #include "optimizer/restrictinfo.h"
 #include "optimizer/tlist.h"
 #include "optimizer/var.h"
@@ -72,6 +73,9 @@ static void check_hashjoinable(RestrictInfo *restrictinfo);
  *       the base relations (ie, table, subquery, and function RTEs)
  *       appearing in the jointree.
  *
+ * The initial invocation must pass root->parse->jointree as the value of
+ * jtnode.  Internally, the function recurses through the jointree.
+ *
  * At the end of this process, there should be one baserel RelOptInfo for
  * every non-join RTE that is used in the query.  Therefore, this routine
  * is the only place that should call build_simple_rel with reloptkind
@@ -578,6 +582,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
 {
        Relids          relids;
        bool            outerjoin_delayed;
+       bool            pseudoconstant = false;
        bool            maybe_equijoin;
        bool            maybe_outer_join;
        RestrictInfo *restrictinfo;
@@ -599,16 +604,57 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
                elog(ERROR, "JOIN qualification may not refer to other relations");
 
        /*
-        * If the clause is variable-free, we force it to be evaluated at its
-        * original syntactic level.  Note that this should not happen for
-        * top-level clauses, because query_planner() special-cases them.  But it
-        * will happen for variable-free JOIN/ON clauses.  We don't have to be
-        * real smart about such a case, we just have to be correct.  Also note
-        * that for an outer-join clause, we must force it to the OJ's semantic
-        * level, not the syntactic scope.
+        * If the clause is variable-free, our normal heuristic for pushing it
+        * down to just the mentioned rels doesn't work, because there are none.
+        *
+        * If the clause is an outer-join clause, we must force it to the OJ's
+        * semantic level to preserve semantics.
+        *
+        * Otherwise, when the clause contains volatile functions, we force it
+        * to be evaluated at its original syntactic level.  This preserves the
+        * expected semantics.
+        *
+        * When the clause contains no volatile functions either, it is actually
+        * a pseudoconstant clause that will not change value during any one
+        * execution of the plan, and hence can be used as a one-time qual in
+        * a gating Result plan node.  We put such a clause into the regular
+        * RestrictInfo lists for the moment, but eventually createplan.c will
+        * pull it out and make a gating Result node immediately above whatever
+        * plan node the pseudoconstant clause is assigned to.  It's usually
+        * best to put a gating node as high in the plan tree as possible.
+        * If we are not below an outer join, we can actually push the
+        * pseudoconstant qual all the way to the top of the tree.  If we are
+        * below an outer join, we leave the qual at its original syntactic level
+        * (we could push it up to just below the outer join, but that seems more
+        * complex than it's worth).
         */
        if (bms_is_empty(relids))
-               relids = ojscope ? ojscope : qualscope;
+       {
+               if (ojscope)
+               {
+                       /* clause is attached to outer join, eval it there */
+                       relids = ojscope;
+                       /* mustn't use as gating qual, so don't mark pseudoconstant */
+               }
+               else
+               {
+                       /* eval at original syntactic level */
+                       relids = qualscope;
+                       if (!contain_volatile_functions(clause))
+                       {
+                               /* mark as gating qual */
+                               pseudoconstant = true;
+                               /* tell createplan.c to check for gating quals */
+                               root->hasPseudoConstantQuals = true;
+                               /* if not below outer join, push it to top of tree */
+                               if (!below_outer_join)
+                               {
+                                       relids = get_relids_in_jointree((Node *) root->parse->jointree);
+                                       is_pushed_down = true;
+                               }
+                       }
+               }
+       }
 
        /*
         * Check to see if clause application must be delayed by outer-join
@@ -624,6 +670,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
                 */
                Assert(bms_equal(relids, qualscope));
                Assert(!ojscope);
+               Assert(!pseudoconstant);
                /* Needn't feed it back for more deductions */
                outerjoin_delayed = false;
                maybe_equijoin = false;
@@ -647,6 +694,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
                Assert(ojscope);
                relids = ojscope;
                outerjoin_delayed = true;
+               Assert(!pseudoconstant);
 
                /*
                 * We can't use such a clause to deduce equijoin (the left and right
@@ -738,6 +786,7 @@ distribute_qual_to_rels(PlannerInfo *root, Node *clause,
        restrictinfo = make_restrictinfo((Expr *) clause,
                                                                         is_pushed_down,
                                                                         outerjoin_delayed,
+                                                                        pseudoconstant,
                                                                         relids);
 
        /*
@@ -1179,6 +1228,8 @@ check_mergejoinable(RestrictInfo *restrictinfo)
                                leftOp,
                                rightOp;
 
+       if (restrictinfo->pseudoconstant)
+               return;
        if (!is_opclause(clause))
                return;
        if (list_length(((OpExpr *) clause)->args) != 2)
@@ -1212,6 +1263,8 @@ check_hashjoinable(RestrictInfo *restrictinfo)
        Expr       *clause = restrictinfo->clause;
        Oid                     opno;
 
+       if (restrictinfo->pseudoconstant)
+               return;
        if (!is_opclause(clause))
                return;
        if (list_length(((OpExpr *) clause)->args) != 2)
index c567f8b6b7447498774199e0ea98f7cb77c0afad..7a61b3fb17f0d27ea71a402d30adb65e59b4f0a8 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.15 2006/06/06 17:59:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planagg.c,v 1.16 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -46,8 +46,7 @@ static bool build_minmax_path(PlannerInfo *root, RelOptInfo *rel,
                                  MinMaxAggInfo *info);
 static ScanDirection match_agg_to_index_col(MinMaxAggInfo *info,
                                           IndexOptInfo *index, int indexcol);
-static void make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info,
-                                List *constant_quals);
+static void make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info);
 static Node *replace_aggs_with_params_mutator(Node *node, List **context);
 static Oid     fetch_agg_sort_op(Oid aggfnoid);
 
@@ -81,7 +80,6 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
        Plan       *plan;
        Node       *hqual;
        QualCost        tlist_cost;
-       List       *constant_quals;
 
        /* Nothing to do if query has no aggregates */
        if (!parse->hasAggs)
@@ -164,27 +162,13 @@ optimize_minmax_aggregates(PlannerInfo *root, List *tlist, Path *best_path)
                return NULL;                    /* too expensive */
 
        /*
-        * OK, we are going to generate an optimized plan.      The first thing we
-        * need to do is look for any non-variable WHERE clauses that
-        * query_planner might have removed from the basic plan.  (Normal WHERE
-        * clauses will be properly incorporated into the sub-plans by
-        * create_plan.)  If there are any, they will be in a gating Result node
-        * atop the best_path. They have to be incorporated into a gating Result
-        * in each sub-plan in order to produce the semantically correct result.
+        * OK, we are going to generate an optimized plan.
         */
-       if (IsA(best_path, ResultPath))
-       {
-               constant_quals = ((ResultPath *) best_path)->constantqual;
-               /* no need to do this more than once: */
-               constant_quals = order_qual_clauses(root, constant_quals);
-       }
-       else
-               constant_quals = NIL;
 
        /* Pass 3: generate subplans and output Param nodes */
        foreach(l, aggs_list)
        {
-               make_agg_subplan(root, (MinMaxAggInfo *) lfirst(l), constant_quals);
+               make_agg_subplan(root, (MinMaxAggInfo *) lfirst(l));
        }
 
        /*
@@ -434,11 +418,12 @@ match_agg_to_index_col(MinMaxAggInfo *info, IndexOptInfo *index, int indexcol)
  * Construct a suitable plan for a converted aggregate query
  */
 static void
-make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals)
+make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info)
 {
        PlannerInfo subroot;
        Query      *subparse;
        Plan       *plan;
+       Plan       *iplan;
        TargetEntry *tle;
        SortClause *sortcl;
        NullTest   *ntest;
@@ -482,8 +467,7 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals)
        /*
         * Generate the plan for the subquery.  We already have a Path for the
         * basic indexscan, but we have to convert it to a Plan and attach a LIMIT
-        * node above it.  We might need a gating Result, too, to handle any
-        * non-variable qual clauses.
+        * node above it.
         *
         * Also we must add a "WHERE foo IS NOT NULL" restriction to the
         * indexscan, to be sure we don't return a NULL, which'd be contrary to
@@ -491,21 +475,26 @@ make_agg_subplan(PlannerInfo *root, MinMaxAggInfo *info, List *constant_quals)
         * earlier, so that the selectivity of the restriction could be included
         * in our cost estimates.  But that looks painful, and in most cases the
         * fraction of NULLs isn't high enough to change the decision.
+        *
+        * The NOT NULL qual has to go on the actual indexscan; create_plan
+        * might have stuck a gating Result atop that, if there were any
+        * pseudoconstant quals.
         */
        plan = create_plan(&subroot, (Path *) info->path);
 
        plan->targetlist = copyObject(subparse->targetList);
 
+       if (IsA(plan, Result))
+               iplan = plan->lefttree;
+       else
+               iplan = plan;
+       Assert(IsA(iplan, IndexScan));
+
        ntest = makeNode(NullTest);
        ntest->nulltesttype = IS_NOT_NULL;
        ntest->arg = copyObject(info->target);
 
-       plan->qual = lcons(ntest, plan->qual);
-
-       if (constant_quals)
-               plan = (Plan *) make_result(copyObject(plan->targetlist),
-                                                                       copyObject(constant_quals),
-                                                                       plan);
+       iplan->qual = lcons(ntest, iplan->qual);
 
        plan = (Plan *) make_limit(plan,
                                                           subparse->limitOffset,
index bc1438a4672a003ba710949e8cca0a6c2fc5c8a5..2ad786ce646184ee52dd079f80d0907498d15d64 100644 (file)
@@ -14,7 +14,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.93 2006/03/05 15:58:29 momjian Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planmain.c,v 1.94 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -82,7 +82,6 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
                          double *num_groups)
 {
        Query      *parse = root->parse;
-       List       *constant_quals;
        List       *joinlist;
        RelOptInfo *final_rel;
        Path       *cheapestpath;
@@ -99,26 +98,12 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
         */
        if (parse->jointree->fromlist == NIL)
        {
-               *cheapest_path = (Path *) create_result_path(NULL, NULL,
-                                                                                       (List *) parse->jointree->quals);
+               *cheapest_path = (Path *)
+                       create_result_path((List *) parse->jointree->quals);
                *sorted_path = NULL;
                return;
        }
 
-       /*
-        * Pull out any non-variable WHERE clauses so these can be put in a
-        * toplevel "Result" node, where they will gate execution of the whole
-        * plan (the Result will not invoke its descendant plan unless the quals
-        * are true).  Note that any *really* non-variable quals will have been
-        * optimized away by eval_const_expressions().  What we're mostly
-        * interested in here is quals that depend only on outer-level vars,
-        * although if the qual reduces to "WHERE FALSE" this path will also be
-        * taken.
-        */
-       parse->jointree->quals = (Node *)
-               pull_constant_clauses((List *) parse->jointree->quals,
-                                                         &constant_quals);
-
        /*
         * Init planner lists to empty, and set up the array to hold RelOptInfos
         * for "simple" rels.
@@ -324,20 +309,6 @@ query_planner(PlannerInfo *root, List *tlist, double tuple_fraction,
                }
        }
 
-       /*
-        * If we have constant quals, add a toplevel Result step to process them.
-        */
-       if (constant_quals)
-       {
-               cheapestpath = (Path *) create_result_path(final_rel,
-                                                                                                  cheapestpath,
-                                                                                                  constant_quals);
-               if (sortedpath)
-                       sortedpath = (Path *) create_result_path(final_rel,
-                                                                                                        sortedpath,
-                                                                                                        constant_quals);
-       }
-
        *cheapest_path = cheapestpath;
        *sorted_path = sortedpath;
 }
index da1cadcd0db83998ad9acf7bf9d4be285598deec..160310c56d6770a8fd6b02ed70908d160444803c 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.200 2006/06/28 20:04:38 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.201 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -270,6 +270,9 @@ subquery_planner(Query *parse, double tuple_fraction,
         */
        root->hasHavingQual = (parse->havingQual != NULL);
 
+       /* Clear this flag; might get set in distribute_qual_to_rels */
+       root->hasPseudoConstantQuals = false;
+
        /*
         * Do expression preprocessing on targetlist and quals.
         */
index 4da9f47dec5ba6e2872fe317771d010b525128bc..bde0966f4aebbff10327983db9d376f94cd5d863 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.212 2006/06/16 18:42:22 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.213 2006/07/01 18:38:33 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -1052,14 +1052,13 @@ is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK)
 
 /*
  * is_pseudo_constant_clause
- *       Detect whether a clause is "constant", ie, it contains no variables
- *       of the current query level and no uses of volatile functions.
- *       Such a clause is not necessarily a true constant: it can still contain
+ *       Detect whether an expression is "pseudo constant", ie, it contains no
+ *       variables of the current query level and no uses of volatile functions.
+ *       Such an expr is not necessarily a true constant: it can still contain
  *       Params and outer-level Vars, not to mention functions whose results
- *       may vary from one statement to the next.      However, the clause's value
+ *       may vary from one statement to the next.      However, the expr's value
  *       will be constant over any one scan of the current query, so it can be
- *       used as an indexscan key or (if a top-level qual) can be pushed up to
- *       become a gating qual.
+ *       used as, eg, an indexscan key.
  */
 bool
 is_pseudo_constant_clause(Node *clause)
@@ -1079,7 +1078,7 @@ is_pseudo_constant_clause(Node *clause)
 /*
  * is_pseudo_constant_clause_relids
  *       Same as above, except caller already has available the var membership
- *       of the clause; this lets us avoid the contain_var_clause() scan.
+ *       of the expression; this lets us avoid the contain_var_clause() scan.
  */
 bool
 is_pseudo_constant_clause_relids(Node *clause, Relids relids)
@@ -1090,34 +1089,6 @@ is_pseudo_constant_clause_relids(Node *clause, Relids relids)
        return false;
 }
 
-/*
- * pull_constant_clauses
- *             Scan through a list of qualifications and separate "constant" quals
- *             from those that are not.
- *
- * Returns a list of the pseudo-constant clauses in constantQual and the
- * remaining quals as the return value.
- */
-List *
-pull_constant_clauses(List *quals, List **constantQual)
-{
-       List       *constqual = NIL,
-                          *restqual = NIL;
-       ListCell   *q;
-
-       foreach(q, quals)
-       {
-               Node       *qual = (Node *) lfirst(q);
-
-               if (is_pseudo_constant_clause(qual))
-                       constqual = lappend(constqual, qual);
-               else
-                       restqual = lappend(restqual, qual);
-       }
-       *constantQual = constqual;
-       return restqual;
-}
-
 
 /*****************************************************************************
  *             Tests on clauses of queries
index f8270074142ce7a032541ec6da7e361d2afce95a..c0363d2405dd4d1ce7b8d7b4dbf1fe9dd3223892 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.128 2006/06/06 17:59:57 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/pathnode.c,v 1.129 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -667,36 +667,29 @@ create_append_path(RelOptInfo *rel, List *subpaths)
 
 /*
  * create_result_path
- *       Creates a path corresponding to a Result plan, returning the
- *       pathnode.
+ *       Creates a path representing a Result-and-nothing-else plan.
+ *       This is only used for the case of a query with an empty jointree.
  */
 ResultPath *
-create_result_path(RelOptInfo *rel, Path *subpath, List *constantqual)
+create_result_path(List *quals)
 {
        ResultPath *pathnode = makeNode(ResultPath);
 
        pathnode->path.pathtype = T_Result;
-       pathnode->path.parent = rel;    /* may be NULL */
-
-       if (subpath)
-               pathnode->path.pathkeys = subpath->pathkeys;
-       else
-               pathnode->path.pathkeys = NIL;
-
-       pathnode->subpath = subpath;
-       pathnode->constantqual = constantqual;
+       pathnode->path.parent = NULL;
+       pathnode->path.pathkeys = NIL;
+       pathnode->quals = quals;
 
        /* Ideally should define cost_result(), but I'm too lazy */
-       if (subpath)
-       {
-               pathnode->path.startup_cost = subpath->startup_cost;
-               pathnode->path.total_cost = subpath->total_cost;
-       }
-       else
-       {
-               pathnode->path.startup_cost = 0;
-               pathnode->path.total_cost = cpu_tuple_cost;
-       }
+       pathnode->path.startup_cost = 0;
+       pathnode->path.total_cost = cpu_tuple_cost;
+       /*
+        * In theory we should include the qual eval cost as well, but
+        * at present that doesn't accomplish much except duplicate work that
+        * will be done again in make_result; since this is only used for
+        * degenerate cases, nothing interesting will be done with the path
+        * cost values...
+        */
 
        return pathnode;
 }
index 606f77bf90018822d9b3135e3a8ad085b3d1915b..ec43ee39f0e493d7cd14030450d0f4c21ecc8d63 100644 (file)
@@ -8,7 +8,7 @@
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.47 2006/04/07 17:05:39 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/restrictinfo.c,v 1.48 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -26,10 +26,12 @@ static RestrictInfo *make_restrictinfo_internal(Expr *clause,
                                                   Expr *orclause,
                                                   bool is_pushed_down,
                                                   bool outerjoin_delayed,
+                                                  bool pseudoconstant,
                                                   Relids required_relids);
 static Expr *make_sub_restrictinfos(Expr *clause,
                                           bool is_pushed_down,
                                           bool outerjoin_delayed,
+                                          bool pseudoconstant,
                                           Relids required_relids);
 static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
                                                 RestrictInfo *rinfo,
@@ -42,9 +44,10 @@ static RestrictInfo *join_clause_is_redundant(PlannerInfo *root,
  *
  * Build a RestrictInfo node containing the given subexpression.
  *
- * The is_pushed_down and outerjoin_delayed flags must be supplied by the
- * caller.     required_relids can be NULL, in which case it defaults to the
- * actual clause contents (i.e., clause_relids).
+ * The is_pushed_down, outerjoin_delayed, and pseudoconstant flags for the
+ * RestrictInfo must be supplied by the caller.  required_relids can be NULL,
+ * in which case it defaults to the actual clause contents (i.e.,
+ * clause_relids).
  *
  * We initialize fields that depend only on the given subexpression, leaving
  * others that depend on context (or may never be needed at all) to be filled
@@ -54,6 +57,7 @@ RestrictInfo *
 make_restrictinfo(Expr *clause,
                                  bool is_pushed_down,
                                  bool outerjoin_delayed,
+                                 bool pseudoconstant,
                                  Relids required_relids)
 {
        /*
@@ -64,13 +68,17 @@ make_restrictinfo(Expr *clause,
                return (RestrictInfo *) make_sub_restrictinfos(clause,
                                                                                                           is_pushed_down,
                                                                                                           outerjoin_delayed,
+                                                                                                          pseudoconstant,
                                                                                                           required_relids);
 
        /* Shouldn't be an AND clause, else AND/OR flattening messed up */
        Assert(!and_clause((Node *) clause));
 
-       return make_restrictinfo_internal(clause, NULL,
-                                                                         is_pushed_down, outerjoin_delayed,
+       return make_restrictinfo_internal(clause,
+                                                                         NULL,
+                                                                         is_pushed_down,
+                                                                         outerjoin_delayed,
+                                                                         pseudoconstant,
                                                                          required_relids);
 }
 
@@ -85,7 +93,8 @@ make_restrictinfo(Expr *clause,
  * RestrictInfos.
  *
  * The caller must pass is_pushed_down, but we assume outerjoin_delayed
- * is false (no such qual should ever get into a bitmapqual).
+ * and pseudoconstant are false (no such qual should ever get into a
+ * bitmapqual).
  *
  * If include_predicates is true, we add any partial index predicates to
  * the explicit index quals.  When this is not true, we return a condition
@@ -214,6 +223,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
                                                                                                          make_orclause(withris),
                                                                                                          is_pushed_down,
                                                                                                          false,
+                                                                                                         false,
                                                                                                          NULL));
                }
        }
@@ -239,6 +249,7 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
                                                                         make_restrictinfo(pred,
                                                                                                           is_pushed_down,
                                                                                                           false,
+                                                                                                          false,
                                                                                                           NULL));
                        }
                }
@@ -258,8 +269,11 @@ make_restrictinfo_from_bitmapqual(Path *bitmapqual,
  * Common code for the main entry points and the recursive cases.
  */
 static RestrictInfo *
-make_restrictinfo_internal(Expr *clause, Expr *orclause,
-                                                  bool is_pushed_down, bool outerjoin_delayed,
+make_restrictinfo_internal(Expr *clause,
+                                                  Expr *orclause,
+                                                  bool is_pushed_down,
+                                                  bool outerjoin_delayed,
+                                                  bool pseudoconstant,
                                                   Relids required_relids)
 {
        RestrictInfo *restrictinfo = makeNode(RestrictInfo);
@@ -268,6 +282,7 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
        restrictinfo->orclause = orclause;
        restrictinfo->is_pushed_down = is_pushed_down;
        restrictinfo->outerjoin_delayed = outerjoin_delayed;
+       restrictinfo->pseudoconstant = pseudoconstant;
        restrictinfo->can_join = false;         /* may get set below */
 
        /*
@@ -292,7 +307,11 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
                        !bms_is_empty(restrictinfo->right_relids) &&
                        !bms_overlap(restrictinfo->left_relids,
                                                 restrictinfo->right_relids))
+               {
                        restrictinfo->can_join = true;
+                       /* pseudoconstant should certainly not be true */
+                       Assert(!restrictinfo->pseudoconstant);
+               }
        }
        else
        {
@@ -346,13 +365,18 @@ make_restrictinfo_internal(Expr *clause, Expr *orclause,
  * implicit-AND lists at top level of RestrictInfo lists.  Only ORs and
  * simple clauses are valid RestrictInfos.
  *
+ * The same is_pushed_down, outerjoin_delayed, and pseudoconstant flag
+ * values can be applied to all RestrictInfo nodes in the result.
+ *
  * The given required_relids are attached to our top-level output,
  * but any OR-clause constituents are allowed to default to just the
  * contained rels.
  */
 static Expr *
 make_sub_restrictinfos(Expr *clause,
-                                          bool is_pushed_down, bool outerjoin_delayed,
+                                          bool is_pushed_down,
+                                          bool outerjoin_delayed,
+                                          bool pseudoconstant,
                                           Relids required_relids)
 {
        if (or_clause((Node *) clause))
@@ -365,11 +389,13 @@ make_sub_restrictinfos(Expr *clause,
                                                         make_sub_restrictinfos(lfirst(temp),
                                                                                                        is_pushed_down,
                                                                                                        outerjoin_delayed,
+                                                                                                       pseudoconstant,
                                                                                                        NULL));
                return (Expr *) make_restrictinfo_internal(clause,
                                                                                                   make_orclause(orlist),
                                                                                                   is_pushed_down,
                                                                                                   outerjoin_delayed,
+                                                                                                  pseudoconstant,
                                                                                                   required_relids);
        }
        else if (and_clause((Node *) clause))
@@ -382,6 +408,7 @@ make_sub_restrictinfos(Expr *clause,
                                                          make_sub_restrictinfos(lfirst(temp),
                                                                                                         is_pushed_down,
                                                                                                         outerjoin_delayed,
+                                                                                                        pseudoconstant,
                                                                                                         required_relids));
                return make_andclause(andlist);
        }
@@ -390,6 +417,7 @@ make_sub_restrictinfos(Expr *clause,
                                                                                                   NULL,
                                                                                                   is_pushed_down,
                                                                                                   outerjoin_delayed,
+                                                                                                  pseudoconstant,
                                                                                                   required_relids);
 }
 
@@ -411,47 +439,91 @@ restriction_is_or_clause(RestrictInfo *restrictinfo)
  * get_actual_clauses
  *
  * Returns a list containing the bare clauses from 'restrictinfo_list'.
+ *
+ * This is only to be used in cases where none of the RestrictInfos can
+ * be pseudoconstant clauses (for instance, it's OK on indexqual lists).
  */
 List *
 get_actual_clauses(List *restrictinfo_list)
 {
        List       *result = NIL;
-       ListCell   *temp;
+       ListCell   *l;
 
-       foreach(temp, restrictinfo_list)
+       foreach(l, restrictinfo_list)
        {
-               RestrictInfo *rinfo = (RestrictInfo *) lfirst(temp);
+               RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
 
                Assert(IsA(rinfo, RestrictInfo));
 
+               Assert(!rinfo->pseudoconstant);
+
                result = lappend(result, rinfo->clause);
        }
        return result;
 }
 
 /*
- * get_actual_join_clauses
+ * extract_actual_clauses
  *
- * Extract clauses from 'restrictinfo_list', separating those that
+ * Extract bare clauses from 'restrictinfo_list', returning either the
+ * regular ones or the pseudoconstant ones per 'pseudoconstant'.
+ */
+List *
+extract_actual_clauses(List *restrictinfo_list,
+                                          bool pseudoconstant)
+{
+       List       *result = NIL;
+       ListCell   *l;
+
+       foreach(l, restrictinfo_list)
+       {
+               RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+               Assert(IsA(rinfo, RestrictInfo));
+
+               if (rinfo->pseudoconstant == pseudoconstant)
+                       result = lappend(result, rinfo->clause);
+       }
+       return result;
+}
+
+/*
+ * extract_actual_join_clauses
+ *
+ * Extract bare clauses from 'restrictinfo_list', separating those that
  * syntactically match the join level from those that were pushed down.
+ * Pseudoconstant clauses are excluded from the results.
+ *
+ * This is only used at outer joins, since for plain joins we don't care
+ * about pushed-down-ness.
  */
 void
-get_actual_join_clauses(List *restrictinfo_list,
-                                               List **joinquals, List **otherquals)
+extract_actual_join_clauses(List *restrictinfo_list,
+                                                       List **joinquals,
+                                                       List **otherquals)
 {
-       ListCell   *temp;
+       ListCell   *l;
 
        *joinquals = NIL;
        *otherquals = NIL;
 
-       foreach(temp, restrictinfo_list)
+       foreach(l, restrictinfo_list)
        {
-               RestrictInfo *clause = (RestrictInfo *) lfirst(temp);
+               RestrictInfo *rinfo = (RestrictInfo *) lfirst(l);
+
+               Assert(IsA(rinfo, RestrictInfo));
 
-               if (clause->is_pushed_down)
-                       *otherquals = lappend(*otherquals, clause->clause);
+               if (rinfo->is_pushed_down)
+               {
+                       if (!rinfo->pseudoconstant)
+                               *otherquals = lappend(*otherquals, rinfo->clause);
+               }
                else
-                       *joinquals = lappend(*joinquals, clause->clause);
+               {
+                       /* joinquals shouldn't have been marked pseudoconstant */
+                       Assert(!rinfo->pseudoconstant);
+                       *joinquals = lappend(*joinquals, rinfo->clause);
+               }
        }
 }
 
index 1f971118f5b59cde2a9cedfa430408bc90106818..d7a93f0f6506e95ded42b1765f8153441fb4b119 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.125 2006/06/06 17:59:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/relation.h,v 1.126 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -114,6 +114,8 @@ typedef struct PlannerInfo
        bool            hasJoinRTEs;    /* true if any RTEs are RTE_JOIN kind */
        bool            hasOuterJoins;  /* true if any RTEs are outer joins */
        bool            hasHavingQual;  /* true if havingQual was non-null */
+       bool            hasPseudoConstantQuals; /* true if any RestrictInfo has
+                                                                                * pseudoconstant = true */
 } PlannerInfo;
 
 
@@ -524,25 +526,16 @@ typedef struct AppendPath
 } AppendPath;
 
 /*
- * ResultPath represents use of a Result plan node.  There are several
- * applications for this:
- *     * To compute a variable-free targetlist (a "SELECT expressions" query).
- *       In this case subpath and path.parent will both be NULL.  constantqual
- *       might or might not be empty ("SELECT expressions WHERE something").
- *     * To gate execution of a subplan with a one-time (variable-free) qual
- *       condition.  path.parent is copied from the subpath.
- *     * To substitute for a scan plan when we have proven that no rows in
- *       a table will satisfy the query.  subpath is NULL but path.parent
- *       references the not-to-be-scanned relation, and constantqual is
- *       a constant FALSE.
- *
- * Note that constantqual is a list of bare clauses, not RestrictInfos.
+ * ResultPath represents use of a Result plan node to compute a variable-free
+ * targetlist with no underlying tables (a "SELECT expressions" query).
+ * The query could have a WHERE clause, too, represented by "quals".
+ *
+ * Note that quals is a list of bare clauses, not RestrictInfos.
  */
 typedef struct ResultPath
 {
        Path            path;
-       Path       *subpath;
-       List       *constantqual;
+       List       *quals;
 } ResultPath;
 
 /*
@@ -732,6 +725,22 @@ typedef struct HashPath
  * OR/AND structure.  This is a convenience for OR indexscan processing:
  * indexquals taken from either the top level or an OR subclause will have
  * associated RestrictInfo nodes.
+ *
+ * The can_join flag is set true if the clause looks potentially useful as
+ * a merge or hash join clause, that is if it is a binary opclause with
+ * nonoverlapping sets of relids referenced in the left and right sides.
+ * (Whether the operator is actually merge or hash joinable isn't checked,
+ * however.)
+ *
+ * The pseudoconstant flag is set true if the clause contains no Vars of
+ * the current query level and no volatile functions.  Such a clause can be
+ * pulled out and used as a one-time qual in a gating Result node.  We keep
+ * pseudoconstant clauses in the same lists as other RestrictInfos so that
+ * the regular clause-pushing machinery can assign them to the correct join
+ * level, but they need to be treated specially for cost and selectivity
+ * estimates.  Note that a pseudoconstant clause can never be an indexqual
+ * or merge or hash join clause, so it's of no interest to large parts of
+ * the planner.
  */
 
 typedef struct RestrictInfo
@@ -744,14 +753,9 @@ typedef struct RestrictInfo
 
        bool            outerjoin_delayed;              /* TRUE if delayed by outer join */
 
-       /*
-        * This flag is set true if the clause looks potentially useful as a merge
-        * or hash join clause, that is if it is a binary opclause with
-        * nonoverlapping sets of relids referenced in the left and right sides.
-        * (Whether the operator is actually merge or hash joinable isn't checked,
-        * however.)
-        */
-       bool            can_join;
+       bool            can_join;               /* see comment above */
+
+       bool            pseudoconstant; /* see comment above */
 
        /* The set of relids (varnos) actually referenced in the clause: */
        Relids          clause_relids;
index d384d2fa16d9e99d23ade3e07bedc806454f0746..b7c960e77a3a22566b4c9da42c1aadec896616ad 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.83 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.84 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -61,7 +61,6 @@ extern Relids find_nonnullable_rels(Node *clause);
 
 extern bool is_pseudo_constant_clause(Node *clause);
 extern bool is_pseudo_constant_clause_relids(Node *clause, Relids relids);
-extern List *pull_constant_clauses(List *quals, List **constantQual);
 
 extern bool has_distinct_clause(Query *query);
 extern bool has_distinct_on_clause(Query *query);
index f728489be54fc7974ae6d7b7b0e81d9e58d9e793..3e7f510b28d44e01f22832c9bc8eb5415e422ead 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.68 2006/06/06 17:59:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/pathnode.h,v 1.69 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -47,8 +47,7 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
 extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
                                        List *tidquals);
 extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths);
-extern ResultPath *create_result_path(RelOptInfo *rel, Path *subpath,
-                                  List *constantqual);
+extern ResultPath *create_result_path(List *quals);
 extern MaterialPath *create_material_path(RelOptInfo *rel, Path *subpath);
 extern UniquePath *create_unique_path(PlannerInfo *root, RelOptInfo *rel,
                                   Path *subpath);
index 16948801c5d8213105275104c3c27bde34eded45..30b89d0974d4cbd2c63c1095f7383127c03d442b 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.92 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planmain.h,v 1.93 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
@@ -42,7 +42,6 @@ extern Sort *make_sort_from_sortclauses(PlannerInfo *root, List *sortcls,
                                                   Plan *lefttree);
 extern Sort *make_sort_from_groupcols(PlannerInfo *root, List *groupcls,
                                                 AttrNumber *grpColIdx, Plan *lefttree);
-extern List *order_qual_clauses(PlannerInfo *root, List *clauses);
 extern Agg *make_agg(PlannerInfo *root, List *tlist, List *qual,
                 AggStrategy aggstrategy,
                 int numGroupCols, AttrNumber *grpColIdx,
index 17978ba6668ef8baaf069457111e2ae721b65743..86add7916047a7a58356745b4fefddd861006c55 100644 (file)
@@ -7,7 +7,7 @@
  * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.36 2006/03/05 15:58:57 momjian Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/restrictinfo.h,v 1.37 2006/07/01 18:38:33 tgl Exp $
  *
  *-------------------------------------------------------------------------
  */
 extern RestrictInfo *make_restrictinfo(Expr *clause,
                                  bool is_pushed_down,
                                  bool outerjoin_delayed,
+                                 bool pseudoconstant,
                                  Relids required_relids);
 extern List *make_restrictinfo_from_bitmapqual(Path *bitmapqual,
                                                                  bool is_pushed_down,
                                                                  bool include_predicates);
 extern bool restriction_is_or_clause(RestrictInfo *restrictinfo);
 extern List *get_actual_clauses(List *restrictinfo_list);
-extern void get_actual_join_clauses(List *restrictinfo_list,
-                                               List **joinquals, List **otherquals);
+extern List *extract_actual_clauses(List *restrictinfo_list,
+                                                                       bool pseudoconstant);
+extern void extract_actual_join_clauses(List *restrictinfo_list,
+                                                       List **joinquals,
+                                                       List **otherquals);
 extern List *remove_redundant_join_clauses(PlannerInfo *root,
                                                          List *restrictinfo_list,
                                                          bool isouterjoin);