From d04db370720ece56ffcad54e46cf03483c742ebb Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Fri, 9 Jan 2009 15:46:11 +0000 Subject: [PATCH] Arrange for function default arguments to be processed properly in expressions 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 | 8 ++++---- src/backend/executor/README | 5 +++-- src/backend/executor/execQual.c | 17 ++++++++-------- src/backend/optimizer/plan/planner.c | 38 ++++++++++++++++++++++++++++++++++- src/backend/optimizer/util/clauses.c | 13 +++++++++--- src/backend/optimizer/util/predtest.c | 8 ++++++-- src/include/optimizer/planner.h | 5 ++++- 7 files changed, 73 insertions(+), 21 deletions(-) diff --git a/src/backend/commands/typecmds.c b/src/backend/commands/typecmds.c index f660a57da2..1bd0ef2cd1 100644 --- a/src/backend/commands/typecmds.c +++ b/src/backend/commands/typecmds.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.129 2009/01/01 17:23:40 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/commands/typecmds.c,v 1.130 2009/01/09 15:46:10 tgl Exp $ * * DESCRIPTION * The "DefineFoo" routines take the parse tree and pick out the @@ -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; diff --git a/src/backend/executor/README b/src/backend/executor/README index 7644cc2cc4..467d6272d1 100644 --- a/src/backend/executor/README +++ b/src/backend/executor/README @@ -1,4 +1,4 @@ -$PostgreSQL: pgsql/src/backend/executor/README,v 1.7 2008/03/21 13:23:28 momjian Exp $ +$PostgreSQL: pgsql/src/backend/executor/README,v 1.8 2009/01/09 15:46:10 tgl Exp $ The Postgres Executor ===================== @@ -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: diff --git a/src/backend/executor/execQual.c b/src/backend/executor/execQual.c index ed53a62e38..f74a5da6b2 100644 --- a/src/backend/executor/execQual.c +++ b/src/backend/executor/execQual.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.240 2009/01/01 17:23:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execQual.c,v 1.241 2009/01/09 15:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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); diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index 841d85f739..34747d0f97 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.250 2009/01/01 17:23:44 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.251 2009/01/09 15:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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; +} diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index a0205d7b8c..65c9b61458 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.274 2009/01/06 01:23:21 tgl Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.275 2009/01/09 15:46:10 tgl Exp $ * * HISTORY * AUTHOR DATE MAJOR EVENT @@ -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. diff --git a/src/backend/optimizer/util/predtest.c b/src/backend/optimizer/util/predtest.c index 4bbcb2fe22..678f560978 100644 --- a/src/backend/optimizer/util/predtest.c +++ b/src/backend/optimizer/util/predtest.c @@ -9,7 +9,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.23 2009/01/01 17:23:45 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/optimizer/util/predtest.c,v 1.24 2009/01/09 15:46:10 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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, diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h index a00bc4b1cf..ec43663b29 100644 --- a/src/include/optimizer/planner.h +++ b/src/include/optimizer/planner.h @@ -7,7 +7,7 @@ * Portions Copyright (c) 1996-2009, PostgreSQL Global Development Group * Portions Copyright (c) 1994, Regents of the University of California * - * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.46 2009/01/01 17:24:00 momjian Exp $ + * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.47 2009/01/09 15:46:11 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -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 */ -- 2.11.0