]> granicus.if.org Git - postgresql/blobdiff - src/backend/optimizer/util/clauses.c
Change the planner-to-executor API so that the planner tells the executor
[postgresql] / src / backend / optimizer / util / clauses.c
index 04f346d46256ee15573cbbc283b6d774ed295a36..4858f985cffe2eb0f1f061a866aba3d7a996c37a 100644 (file)
@@ -3,12 +3,12 @@
  * clauses.c
  *       routines to manipulate qualification clauses
  *
- * Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
+ * Portions Copyright (c) 1996-2007, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
  * IDENTIFICATION
- *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.218 2006/08/12 02:52:05 tgl Exp $
+ *       $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.229 2007/01/10 18:06:04 tgl Exp $
  *
  * HISTORY
  *       AUTHOR                        DATE                    MAJOR EVENT
@@ -403,7 +403,7 @@ count_agg_clauses_walker(Node *node, AggClauseCounts *counts)
                Form_pg_aggregate aggform;
                Oid                     aggtranstype;
                int                     i;
-               ListCell        *l;
+               ListCell   *l;
 
                Assert(aggref->agglevelsup == 0);
                counts->numAggs++;
@@ -557,6 +557,8 @@ expression_returns_set_walker(Node *node, void *context)
                return false;
        if (IsA(node, MinMaxExpr))
                return false;
+       if (IsA(node, XmlExpr))
+               return false;
        if (IsA(node, NullIfExpr))
                return false;
 
@@ -870,6 +872,8 @@ contain_nonstrict_functions_walker(Node *node, void *context)
                return true;
        if (IsA(node, MinMaxExpr))
                return true;
+       if (IsA(node, XmlExpr))
+               return true;
        if (IsA(node, NullIfExpr))
                return true;
        if (IsA(node, NullTest))
@@ -887,7 +891,7 @@ contain_nonstrict_functions_walker(Node *node, void *context)
  *
  * Returns the set of all Relids that are referenced in the clause in such
  * a way that the clause cannot possibly return TRUE if any of these Relids
- * is an all-NULL row.  (It is OK to err on the side of conservatism; hence
+ * is an all-NULL row. (It is OK to err on the side of conservatism; hence
  * the analysis here is simplistic.)
  *
  * The semantics here are subtly different from contain_nonstrict_functions:
@@ -1020,7 +1024,7 @@ find_nonnullable_rels_walker(Node *node, bool top_level)
 static bool
 is_strict_saop(ScalarArrayOpExpr *expr, bool falseOK)
 {
-       Node   *rightop;
+       Node       *rightop;
 
        /* The contained operator must be strict. */
        if (!op_strict(expr->opno))
@@ -1143,7 +1147,7 @@ has_distinct_on_clause(Query *query)
                                continue;               /* we can ignore unsorted junk cols */
                        return true;            /* definitely not in DISTINCT list */
                }
-               if (targetIsInSortList(tle, query->distinctClause))
+               if (targetIsInSortList(tle, InvalidOid, query->distinctClause))
                {
                        if (tle->resjunk)
                                return true;    /* junk TLE in DISTINCT means DISTINCT ON */
@@ -1154,7 +1158,7 @@ has_distinct_on_clause(Query *query)
                        /* This TLE is not in DISTINCT list */
                        if (!tle->resjunk)
                                return true;    /* non-junk, non-DISTINCT, so DISTINCT ON */
-                       if (targetIsInSortList(tle, query->sortClause))
+                       if (targetIsInSortList(tle, InvalidOid, query->sortClause))
                                return true;    /* sorted, non-distinct junk */
                        /* unsorted junk is okay, keep looking */
                }
@@ -1288,14 +1292,11 @@ CommuteRowCompareExpr(RowCompareExpr *clause)
        }
 
        clause->opnos = newops;
+
        /*
-        * Note: we don't bother to update the opclasses list, but just set
-        * it to empty.  This is OK since this routine is currently only used
-        * for index quals, and the index machinery won't use the opclass
-        * information.  The original opclass list is NOT valid if we have
-        * commuted any cross-type comparisons, so don't leave it in place.
+        * Note: we need not change the opfamilies list; we assume any btree
+        * opfamily containing an operator will also contain its commutator.
         */
-       clause->opclasses = NIL;        /* XXX */
 
        temp = clause->largs;
        clause->largs = clause->rargs;
@@ -1462,7 +1463,9 @@ eval_const_expressions(Node *node)
  *
  * Currently the extra steps that are taken in this mode are:
  * 1. Substitute values for Params, where a bound Param value has been made
- *       available by the caller of planner().
+ *       available by the caller of planner(), even if the Param isn't marked
+ *       constant.  This effectively means that we plan using the first supplied
+ *       value of the Param.
  * 2. Fold stable, as well as immutable, functions to constants.
  *--------------------
  */
@@ -1487,33 +1490,38 @@ eval_const_expressions_mutator(Node *node,
        {
                Param      *param = (Param *) node;
 
-               /* OK to try to substitute value? */
-               if (context->estimate && param->paramkind == PARAM_EXTERN &&
-                       PlannerBoundParamList != NULL)
+               /* Look to see if we've been given a value for this Param */
+               if (param->paramkind == PARAM_EXTERN &&
+                       PlannerBoundParamList != NULL &&
+                       param->paramid > 0 &&
+                       param->paramid <= PlannerBoundParamList->numParams)
                {
-                       /* Look to see if we've been given a value for this Param */
-                       if (param->paramid > 0 &&
-                               param->paramid <= PlannerBoundParamList->numParams)
-                       {
-                               ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
+                       ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
 
-                               if (OidIsValid(prm->ptype))
+                       if (OidIsValid(prm->ptype))
+                       {
+                               /* OK to substitute parameter value? */
+                               if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
                                {
                                        /*
-                                        * Found it, so return a Const representing the param
-                                        * value.  Note that we don't copy pass-by-ref datatypes,
-                                        * so the Const will only be valid as long as the bound
-                                        * parameter list exists.  This is okay for intended uses
-                                        * of estimate_expression_value().
+                                        * Return a Const representing the param value.  Must copy
+                                        * pass-by-ref datatypes, since the Param might be in a
+                                        * memory context shorter-lived than our output plan
+                                        * should be.
                                         */
                                        int16           typLen;
                                        bool            typByVal;
+                                       Datum           pval;
 
                                        Assert(prm->ptype == param->paramtype);
                                        get_typlenbyval(param->paramtype, &typLen, &typByVal);
+                                       if (prm->isnull || typByVal)
+                                               pval = prm->value;
+                                       else
+                                               pval = datumCopy(prm->value, typByVal, typLen);
                                        return (Node *) makeConst(param->paramtype,
                                                                                          (int) typLen,
-                                                                                         prm->value,
+                                                                                         pval,
                                                                                          prm->isnull,
                                                                                          typByVal);
                                }
@@ -2092,6 +2100,85 @@ eval_const_expressions_mutator(Node *node,
                newfselect->resulttypmod = fselect->resulttypmod;
                return (Node *) newfselect;
        }
+       if (IsA(node, NullTest))
+       {
+               NullTest   *ntest = (NullTest *) node;
+               NullTest   *newntest;
+               Node       *arg;
+
+               arg = eval_const_expressions_mutator((Node *) ntest->arg,
+                                                                                        context);
+               if (arg && IsA(arg, RowExpr))
+               {
+                       RowExpr    *rarg = (RowExpr *) arg;
+                       List       *newargs = NIL;
+                       ListCell   *l;
+
+                       /*
+                        * We break ROW(...) IS [NOT] NULL into separate tests on its
+                        * component fields.  This form is usually more efficient to
+                        * evaluate, as well as being more amenable to optimization.
+                        */
+                       foreach(l, rarg->args)
+                       {
+                               Node       *relem = (Node *) lfirst(l);
+
+                               /*
+                                * A constant field refutes the whole NullTest if it's of the
+                                * wrong nullness; else we can discard it.
+                                */
+                               if (relem && IsA(relem, Const))
+                               {
+                                       Const      *carg = (Const *) relem;
+
+                                       if (carg->constisnull ?
+                                               (ntest->nulltesttype == IS_NOT_NULL) :
+                                               (ntest->nulltesttype == IS_NULL))
+                                               return makeBoolConst(false, false);
+                                       continue;
+                               }
+                               newntest = makeNode(NullTest);
+                               newntest->arg = (Expr *) relem;
+                               newntest->nulltesttype = ntest->nulltesttype;
+                               newargs = lappend(newargs, newntest);
+                       }
+                       /* If all the inputs were constants, result is TRUE */
+                       if (newargs == NIL)
+                               return makeBoolConst(true, false);
+                       /* If only one nonconst input, it's the result */
+                       if (list_length(newargs) == 1)
+                               return (Node *) linitial(newargs);
+                       /* Else we need an AND node */
+                       return (Node *) make_andclause(newargs);
+               }
+               if (arg && IsA(arg, Const))
+               {
+                       Const      *carg = (Const *) arg;
+                       bool            result;
+
+                       switch (ntest->nulltesttype)
+                       {
+                               case IS_NULL:
+                                       result = carg->constisnull;
+                                       break;
+                               case IS_NOT_NULL:
+                                       result = !carg->constisnull;
+                                       break;
+                               default:
+                                       elog(ERROR, "unrecognized nulltesttype: %d",
+                                                (int) ntest->nulltesttype);
+                                       result = false;         /* keep compiler quiet */
+                                       break;
+                       }
+
+                       return makeBoolConst(result, false);
+               }
+
+               newntest = makeNode(NullTest);
+               newntest->arg = (Expr *) arg;
+               newntest->nulltesttype = ntest->nulltesttype;
+               return (Node *) newntest;
+       }
        if (IsA(node, BooleanTest))
        {
                BooleanTest *btest = (BooleanTest *) node;
@@ -2102,8 +2189,8 @@ eval_const_expressions_mutator(Node *node,
                                                                                         context);
                if (arg && IsA(arg, Const))
                {
-                       Const  *carg = (Const *) arg;
-                       bool    result;
+                       Const      *carg = (Const *) arg;
+                       bool            result;
 
                        switch (btest->booltesttype)
                        {
@@ -2132,7 +2219,7 @@ eval_const_expressions_mutator(Node *node,
                                default:
                                        elog(ERROR, "unrecognized booltesttype: %d",
                                                 (int) btest->booltesttype);
-                                       result = false; /* keep compiler quiet */
+                                       result = false;         /* keep compiler quiet */
                                        break;
                        }
 
@@ -2689,7 +2776,6 @@ inline_function(Oid funcid, Oid result_type, List *args,
         */
        if (!IsA(querytree, Query) ||
                querytree->commandType != CMD_SELECT ||
-               querytree->resultRelation != 0 ||
                querytree->into ||
                querytree->hasAggs ||
                querytree->hasSubLinks ||
@@ -3017,10 +3103,9 @@ evaluate_expr(Expr *expr, Oid result_type)
  * stage.  In particular, it handles List nodes since a cnf-ified qual clause
  * will have List structure at the top level, and it handles TargetEntry nodes
  * so that a scan of a target list can be handled without additional code.
- * (But only the "expr" part of a TargetEntry is examined, unless the walker
- * chooses to process TargetEntry nodes specially.)  Also, RangeTblRef,
- * FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query
- * jointrees and setOperation trees can be processed without additional code.
+ * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are
+ * handled, so that query jointrees and setOperation trees can be processed
+ * without additional code.
  *
  * expression_tree_walker will handle SubLink nodes by recursing normally
  * into the "testexpr" subtree (which is an expression belonging to the outer
@@ -3090,8 +3175,9 @@ expression_tree_walker(Node *node,
                        break;
                case T_Aggref:
                        {
-                               Aggref   *expr = (Aggref *) node;
+                               Aggref     *expr = (Aggref *) node;
 
+                               /* recurse directly on List */
                                if (expression_tree_walker((Node *) expr->args,
                                                                                   walker, context))
                                        return true;
@@ -3164,8 +3250,7 @@ expression_tree_walker(Node *node,
                        {
                                SubLink    *sublink = (SubLink *) node;
 
-                               if (expression_tree_walker(sublink->testexpr,
-                                                                                  walker, context))
+                               if (walker(sublink->testexpr, context))
                                        return true;
 
                                /*
@@ -3180,8 +3265,7 @@ expression_tree_walker(Node *node,
                                SubPlan    *subplan = (SubPlan *) node;
 
                                /* recurse into the testexpr, but not into the Plan */
-                               if (expression_tree_walker(subplan->testexpr,
-                                                                                  walker, context))
+                               if (walker(subplan->testexpr, context))
                                        return true;
                                /* also examine args list */
                                if (expression_tree_walker((Node *) subplan->args,
@@ -3244,6 +3328,17 @@ expression_tree_walker(Node *node,
                        return walker(((CoalesceExpr *) node)->args, context);
                case T_MinMaxExpr:
                        return walker(((MinMaxExpr *) node)->args, context);
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               
+                               if (walker(xexpr->named_args, context))
+                                       return true;
+                               /* we assume walker doesn't care about arg_names */
+                               if (walker(xexpr->args, context))
+                                       return true;
+                       }
+                       break;
                case T_NullIfExpr:
                        return walker(((NullIfExpr *) node)->args, context);
                case T_NullTest:
@@ -3365,6 +3460,38 @@ query_tree_walker(Query *query,
                return true;
        if (range_table_walker(query->rtable, walker, context, flags))
                return true;
+       if (query->utilityStmt)
+       {
+               /*
+                * Certain utility commands contain general-purpose Querys embedded in
+                * them --- if this is one, invoke the walker on the sub-Query.
+                */
+               if (IsA(query->utilityStmt, CopyStmt))
+               {
+                       if (walker(((CopyStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, DeclareCursorStmt))
+               {
+                       if (walker(((DeclareCursorStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, ExplainStmt))
+               {
+                       if (walker(((ExplainStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, PrepareStmt))
+               {
+                       if (walker(((PrepareStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+               if (IsA(query->utilityStmt, ViewStmt))
+               {
+                       if (walker(((ViewStmt *) query->utilityStmt)->query, context))
+                               return true;
+               }
+       }
        return false;
 }
 
@@ -3712,8 +3839,8 @@ expression_tree_mutator(Node *node,
                        break;
                case T_RowCompareExpr:
                        {
-                               RowCompareExpr    *rcexpr = (RowCompareExpr *) node;
-                               RowCompareExpr    *newnode;
+                               RowCompareExpr *rcexpr = (RowCompareExpr *) node;
+                               RowCompareExpr *newnode;
 
                                FLATCOPY(newnode, rcexpr, RowCompareExpr);
                                MUTATE(newnode->largs, rcexpr->largs, List *);
@@ -3741,6 +3868,18 @@ expression_tree_mutator(Node *node,
                                return (Node *) newnode;
                        }
                        break;
+               case T_XmlExpr:
+                       {
+                               XmlExpr *xexpr = (XmlExpr *) node;
+                               XmlExpr *newnode;
+
+                               FLATCOPY(newnode, xexpr, XmlExpr);
+                               MUTATE(newnode->named_args, xexpr->named_args, List *);
+                               /* assume mutator does not care about arg_names */
+                               MUTATE(newnode->args, xexpr->args, List *);
+                               return (Node *) newnode;
+                       }
+                       break;
                case T_NullIfExpr:
                        {
                                NullIfExpr *expr = (NullIfExpr *) node;
@@ -3856,6 +3995,7 @@ expression_tree_mutator(Node *node,
 
                                FLATCOPY(newnode, ininfo, InClauseInfo);
                                MUTATE(newnode->sub_targetlist, ininfo->sub_targetlist, List *);
+                               /* Assume we need not make a copy of in_operators list */
                                return (Node *) newnode;
                        }
                        break;