Arrange for function default arguments to be processed properly in expressions
authorTom Lane <tgl@sss.pgh.pa.us>
Fri, 9 Jan 2009 15:46:11 +0000 (15:46 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Fri, 9 Jan 2009 15:46:11 +0000 (15:46 +0000)
that are set up for execution with ExecPrepareExpr rather than going through
the full planner process.  By introducing an explicit notion of "expression
planning", this patch also lays a bit of groundwork for maybe someday
allowing sub-selects in standalone expressions.

src/backend/commands/typecmds.c
src/backend/executor/README
src/backend/executor/execQual.c
src/backend/optimizer/plan/planner.c
src/backend/optimizer/util/clauses.c
src/backend/optimizer/util/predtest.c
src/include/optimizer/planner.h

index 67783ed0439a851dbaa28970229dda371a77100b..d3e22f8a03d36c803b74b1d22ac0ff7b9ac18e15 100644 (file)
@@ -50,7 +50,7 @@
 #include "executor/executor.h"
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
-#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
 #include "optimizer/var.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_expr.h"
@@ -2390,8 +2390,8 @@ GetDomainConstraints(Oid typeOid)
 
                        check_expr = (Expr *) stringToNode(TextDatumGetCString(val));
 
-                       /* ExecInitExpr assumes we already fixed opfuncids */
-                       fix_opfuncids((Node *) check_expr);
+                       /* ExecInitExpr assumes we've planned the expression */
+                       check_expr = expression_planner(check_expr);
 
                        r = makeNode(DomainConstraintState);
                        r->constrainttype = DOM_CONSTRAINT_CHECK;
index 677bdcbd36a4cbb34052bb9dd390caf3f97ba066..f54366655ec62425c63444076f685820f0b6c93a 100644 (file)
@@ -124,7 +124,8 @@ be hidden inside function calls).  This case has a flow of control like
                creates per-tuple context
 
        ExecPrepareExpr
-               switch to per-query context to run ExecInitExpr
+               temporarily switch to per-query context
+               run the expression through expression_planner
                ExecInitExpr
 
        Repeatedly do:
index f05380d5dcc3b09c48e1fd1a851ec99fcf5eb256..736dc8d64d03d6dbaab45cb685369ecf530c7b84 100644 (file)
@@ -45,7 +45,7 @@
 #include "miscadmin.h"
 #include "nodes/makefuncs.h"
 #include "nodes/nodeFuncs.h"
-#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
 #include "pgstat.h"
 #include "utils/acl.h"
 #include "utils/builtins.h"
@@ -4794,10 +4794,11 @@ ExecInitExpr(Expr *node, PlanState *parent)
  * Plan tree context.
  *
  * This differs from ExecInitExpr in that we don't assume the caller is
- * already running in the EState's per-query context.  Also, we apply
- * fix_opfuncids() to the passed expression tree to be sure it is ready
- * to run.     (In ordinary Plan trees the planner will have fixed opfuncids,
- * but callers outside the executor will not have done this.)
+ * already running in the EState's per-query context.  Also, we run the
+ * passed expression tree through expression_planner() to prepare it for
+ * execution.  (In ordinary Plan trees the regular planning process will have
+ * made the appropriate transformations on expressions, but for standalone
+ * expressions this won't have happened.)
  */
 ExprState *
 ExecPrepareExpr(Expr *node, EState *estate)
@@ -4805,10 +4806,10 @@ ExecPrepareExpr(Expr *node, EState *estate)
        ExprState  *result;
        MemoryContext oldcontext;
 
-       fix_opfuncids((Node *) node);
-
        oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
 
+       node = expression_planner(node);
+
        result = ExecInitExpr(node, NULL);
 
        MemoryContextSwitchTo(oldcontext);
index eccd67f36a29d244712a581f1f7a563d8da2ed54..357d949c6a520604cb6ac3641014bc12b36446c0 100644 (file)
@@ -2576,3 +2576,39 @@ get_column_info_for_window(PlannerInfo *root, WindowClause *wc, List *tlist,
                        elog(ERROR, "failed to deconstruct sort operators into partitioning/ordering operators");
        }
 }
+
+
+/*
+ * expression_planner
+ *             Perform planner's transformations on a standalone expression.
+ *
+ * Various utility commands need to evaluate expressions that are not part
+ * of a plannable query.  They can do so using the executor's regular
+ * expression-execution machinery, but first the expression has to be fed
+ * through here to transform it from parser output to something executable.
+ *
+ * Currently, we disallow sublinks in standalone expressions, so there's no
+ * real "planning" involved here.  (That might not always be true though.)
+ * What we must do is run eval_const_expressions to ensure that any function
+ * default arguments get inserted.  The fact that constant subexpressions
+ * get simplified is a side-effect that is useful when the expression will
+ * get evaluated more than once.  Also, we must fix operator function IDs.
+ *
+ * Note: this must not make any damaging changes to the passed-in expression
+ * tree.  (It would actually be okay to apply fix_opfuncids to it, but since
+ * we first do an expression_tree_mutator-based walk, what is returned will
+ * be a new node tree.)
+ */
+Expr *
+expression_planner(Expr *expr)
+{
+       Node       *result;
+
+       /* Insert default arguments and simplify constant subexprs */
+       result = eval_const_expressions(NULL, (Node *) expr);
+
+       /* Fill in opfuncid values if missing */
+       fix_opfuncids(result);
+
+       return (Expr *) result;
+}
index 0777af03c3e0252b800955c410076cc3746de93d..d5eee9cd2d8fee3dc1e949fb74129c24f2468834 100644 (file)
@@ -2018,6 +2018,9 @@ rowtype_field_matches(Oid rowtypeid, int fieldnum,
  *
  * NOTE: the planner assumes that this will always flatten nested AND and
  * OR clauses into N-argument form.  See comments in prepqual.c.
+ *
+ * NOTE: another critical effect is that any function calls that require
+ * default arguments will be expanded.
  *--------------------
  */
 Node *
@@ -3854,10 +3857,14 @@ evaluate_expr(Expr *expr, Oid result_type, int32 result_typmod)
        /* We can use the estate's working context to avoid memory leaks. */
        oldcontext = MemoryContextSwitchTo(estate->es_query_cxt);
 
+       /* Make sure any opfuncids are filled in. */
+       fix_opfuncids((Node *) expr);
+
        /*
-        * Prepare expr for execution.
+        * Prepare expr for execution.  (Note: we can't use ExecPrepareExpr
+        * because it'd result in recursively invoking eval_const_expressions.)
         */
-       exprstate = ExecPrepareExpr(expr, estate);
+       exprstate = ExecInitExpr(expr, NULL);
 
        /*
         * And evaluate it.
index 72ccd6ab872d616fcd2a5c0d30a82f2669a5ff04..c16e4329686346d15d8fd4bc2a68c34d4143fc33 100644 (file)
@@ -22,6 +22,7 @@
 #include "miscadmin.h"
 #include "nodes/nodeFuncs.h"
 #include "optimizer/clauses.h"
+#include "optimizer/planmain.h"
 #include "optimizer/predtest.h"
 #include "utils/array.h"
 #include "utils/inval.h"
@@ -1405,8 +1406,11 @@ btree_predicate_proof(Expr *predicate, Node *clause, bool refute_it)
                                                          (Expr *) pred_const,
                                                          (Expr *) clause_const);
 
+       /* Fill in opfuncids */
+       fix_opfuncids((Node *) test_expr);
+
        /* Prepare it for execution */
-       test_exprstate = ExecPrepareExpr(test_expr, estate);
+       test_exprstate = ExecInitExpr(test_expr, NULL);
 
        /* And execute it. */
        test_result = ExecEvalExprSwitchContext(test_exprstate,
index 9182d64fd494851e533e3d8a90dfd05ba0a3b102..182310e4bfd850fdac995c241a729e9a260df0eb 100644 (file)
@@ -29,9 +29,12 @@ extern PlannedStmt *planner(Query *parse, int cursorOptions,
                ParamListInfo boundParams);
 extern PlannedStmt *standard_planner(Query *parse, int cursorOptions,
                                 ParamListInfo boundParams);
+
 extern Plan *subquery_planner(PlannerGlobal *glob, Query *parse,
                                 PlannerInfo *parent_root,
                                 bool hasRecursion, double tuple_fraction,
                                 PlannerInfo **subroot);
 
+extern Expr *expression_planner(Expr *expr);
+
 #endif   /* PLANNER_H */