aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/commands/portalcmds.c4
-rw-r--r--src/backend/commands/prepare.c4
-rw-r--r--src/backend/executor/functions.c4
-rw-r--r--src/backend/executor/spi.c4
-rw-r--r--src/backend/optimizer/path/clausesel.c23
-rw-r--r--src/backend/optimizer/plan/planner.c18
-rw-r--r--src/backend/optimizer/util/clauses.c160
-rw-r--r--src/backend/tcop/postgres.c57
-rw-r--r--src/backend/utils/adt/selfuncs.c9
-rw-r--r--src/include/optimizer/clauses.h4
-rw-r--r--src/include/optimizer/planner.h8
-rw-r--r--src/include/tcop/tcopprot.h8
13 files changed, 229 insertions, 78 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 3658a00ea21..97250289540 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.121 2004/05/26 04:41:10 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.122 2004/06/11 01:08:35 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -176,7 +176,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
}
/* plan the query */
- plan = planner(query, isCursor, cursorOptions);
+ plan = planner(query, isCursor, cursorOptions, NULL);
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index d2fa894a76e..9cb8febd311 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.27 2004/05/26 04:41:11 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.28 2004/06/11 01:08:37 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -84,7 +84,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt)
errmsg("DECLARE CURSOR ... FOR UPDATE is not supported"),
errdetail("Cursors must be READ ONLY.")));
- plan = planner(query, true, stmt->options);
+ plan = planner(query, true, stmt->options, NULL);
/*
* Create a portal and copy the query and plan into its memory
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 083ad2af5e7..9c183cb7827 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.27 2004/05/26 04:41:11 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.28 2004/06/11 01:08:38 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -91,7 +91,7 @@ PrepareQuery(PrepareStmt *stmt)
query_list = QueryRewrite(stmt->query);
/* Generate plans for queries. Snapshot is already set. */
- plan_list = pg_plan_queries(query_list, false);
+ plan_list = pg_plan_queries(query_list, NULL, false);
/* Save the results. */
StorePreparedStatement(stmt->name,
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 2e75813a2ab..9ddf6192775 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.81 2004/05/26 04:41:15 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.82 2004/06/11 01:08:42 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -100,7 +100,7 @@ init_execution_state(List *queryTree_list)
Plan *planTree;
execution_state *newes;
- planTree = pg_plan_query(queryTree);
+ planTree = pg_plan_query(queryTree, NULL);
newes = (execution_state *) palloc(sizeof(execution_state));
if (preves)
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index f5f2850b982..91b633d9bd8 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.117 2004/06/06 00:41:26 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.118 2004/06/11 01:08:43 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -1125,7 +1125,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
QueryDesc *qdesc;
DestReceiver *dest;
- planTree = pg_plan_query(queryTree);
+ planTree = pg_plan_query(queryTree, NULL);
plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
diff --git a/src/backend/optimizer/path/clausesel.c b/src/backend/optimizer/path/clausesel.c
index e736c6e309e..996c98cc469 100644
--- a/src/backend/optimizer/path/clausesel.c
+++ b/src/backend/optimizer/path/clausesel.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.67 2004/05/30 23:40:28 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/path/clausesel.c,v 1.68 2004/06/11 01:08:49 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -487,16 +487,27 @@ clause_selectivity(Query *root,
}
}
}
- else if (IsA(clause, Param))
- {
- /* XXX any way to do better? */
- s1 = 1.0;
- }
else if (IsA(clause, Const))
{
/* bool constant is pretty easy... */
s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0;
}
+ else if (IsA(clause, Param))
+ {
+ /* see if we can replace the Param */
+ Node *subst = estimate_expression_value(clause);
+
+ if (IsA(subst, Const))
+ {
+ /* bool constant is pretty easy... */
+ s1 = ((bool) ((Const *) subst)->constvalue) ? 1.0 : 0.0;
+ }
+ else
+ {
+ /* XXX any way to do better? */
+ s1 = (Selectivity) 0.5;
+ }
+ }
else if (not_clause(clause))
{
/* inverse of the selectivity of the underlying clause */
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 064981b5af0..2fc82556c32 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.171 2004/05/30 23:40:29 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/plan/planner.c,v 1.172 2004/06/11 01:08:52 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,6 +43,9 @@
#include "utils/syscache.h"
+ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
+
+
/* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
@@ -71,20 +74,24 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
*
*****************************************************************************/
Plan *
-planner(Query *parse, bool isCursor, int cursorOptions)
+planner(Query *parse, bool isCursor, int cursorOptions,
+ ParamListInfo boundParams)
{
double tuple_fraction;
Plan *result_plan;
Index save_PlannerQueryLevel;
List *save_PlannerParamList;
+ ParamListInfo save_PlannerBoundParamList;
/*
* The planner can be called recursively (an example is when
* eval_const_expressions tries to pre-evaluate an SQL function). So,
* these global state variables must be saved and restored.
*
- * These vars cannot be moved into the Query structure since their whole
- * purpose is communication across multiple sub-Queries.
+ * Query level and the param list cannot be moved into the Query structure
+ * since their whole purpose is communication across multiple sub-Queries.
+ * Also, boundParams is explicitly info from outside the Query, and so
+ * is likewise better handled as a global variable.
*
* Note we do NOT save and restore PlannerPlanId: it exists to assign
* unique IDs to SubPlan nodes, and we want those IDs to be unique for
@@ -93,10 +100,12 @@ planner(Query *parse, bool isCursor, int cursorOptions)
*/
save_PlannerQueryLevel = PlannerQueryLevel;
save_PlannerParamList = PlannerParamList;
+ save_PlannerBoundParamList = PlannerBoundParamList;
/* Initialize state for handling outer-level references and params */
PlannerQueryLevel = 0; /* will be 1 in top-level subquery_planner */
PlannerParamList = NIL;
+ PlannerBoundParamList = boundParams;
/* Determine what fraction of the plan is likely to be scanned */
if (isCursor)
@@ -139,6 +148,7 @@ planner(Query *parse, bool isCursor, int cursorOptions)
/* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList;
+ PlannerBoundParamList = save_PlannerBoundParamList;
return result_plan;
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index a3a2ddfbd83..e7088d2b761 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.175 2004/06/09 19:08:16 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.176 2004/06/11 01:08:54 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -28,6 +28,7 @@
#include "optimizer/clauses.h"
#include "optimizer/cost.h"
#include "optimizer/planmain.h"
+#include "optimizer/planner.h"
#include "optimizer/var.h"
#include "parser/analyze.h"
#include "parser/parse_clause.h"
@@ -43,6 +44,12 @@
typedef struct
{
+ List *active_fns;
+ bool estimate;
+} eval_const_expressions_context;
+
+typedef struct
+{
int nargs;
List *args;
int *usecounts;
@@ -57,17 +64,20 @@ static bool contain_mutable_functions_walker(Node *node, void *context);
static bool contain_volatile_functions_walker(Node *node, void *context);
static bool contain_nonstrict_functions_walker(Node *node, void *context);
static bool set_coercionform_dontcare_walker(Node *node, void *context);
-static Node *eval_const_expressions_mutator(Node *node, List *active_fns);
+static Node *eval_const_expressions_mutator(Node *node,
+ eval_const_expressions_context *context);
static List *simplify_or_arguments(List *args,
bool *haveNull, bool *forceTrue);
static List *simplify_and_arguments(List *args,
bool *haveNull, bool *forceFalse);
static Expr *simplify_function(Oid funcid, Oid result_type, List *args,
- bool allow_inline, List *active_fns);
+ bool allow_inline,
+ eval_const_expressions_context *context);
static Expr *evaluate_function(Oid funcid, Oid result_type, List *args,
HeapTuple func_tuple);
static Expr *inline_function(Oid funcid, Oid result_type, List *args,
- HeapTuple func_tuple, List *active_fns);
+ HeapTuple func_tuple,
+ eval_const_expressions_context *context);
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
int *usecounts);
static Node *substitute_actual_parameters_mutator(Node *node,
@@ -1070,18 +1080,101 @@ set_coercionform_dontcare_walker(Node *node, void *context)
Node *
eval_const_expressions(Node *node)
{
- /*
- * The context for the mutator is a list of SQL functions being
- * recursively simplified, so we start with an empty list.
- */
- return eval_const_expressions_mutator(node, NIL);
+ eval_const_expressions_context context;
+
+ context.active_fns = NIL; /* nothing being recursively simplified */
+ context.estimate = false; /* safe transformations only */
+ return eval_const_expressions_mutator(node, &context);
+}
+
+/*
+ * estimate_expression_value
+ *
+ * This function attempts to estimate the value of an expression for
+ * planning purposes. It is in essence a more aggressive version of
+ * eval_const_expressions(): we will perform constant reductions that are
+ * not necessarily 100% safe, but are reasonable for estimation purposes.
+ *
+ * Currently the only such transform is to substitute values for Params,
+ * when a bound Param value has been made available by the caller of planner().
+ * In future we might consider other things, such as reducing now() to current
+ * time. (XXX seems like there could be a lot of scope for ideas here...
+ * but we might need more volatility classifications ...)
+ */
+Node *
+estimate_expression_value(Node *node)
+{
+ eval_const_expressions_context context;
+
+ context.active_fns = NIL; /* nothing being recursively simplified */
+ context.estimate = true; /* unsafe transformations OK */
+ return eval_const_expressions_mutator(node, &context);
}
static Node *
-eval_const_expressions_mutator(Node *node, List *active_fns)
+eval_const_expressions_mutator(Node *node,
+ eval_const_expressions_context *context)
{
if (node == NULL)
return NULL;
+ if (IsA(node, Param))
+ {
+ Param *param = (Param *) node;
+ int thisParamKind = param->paramkind;
+
+ /* OK to try to substitute value? */
+ if (context->estimate && thisParamKind != PARAM_EXEC &&
+ PlannerBoundParamList != NULL)
+ {
+ ParamListInfo paramList = PlannerBoundParamList;
+ bool matchFound = false;
+
+ /* Search to see if we've been given a value for this Param */
+ while (paramList->kind != PARAM_INVALID && !matchFound)
+ {
+ if (thisParamKind == paramList->kind)
+ {
+ switch (thisParamKind)
+ {
+ case PARAM_NAMED:
+ if (strcmp(paramList->name, param->paramname) == 0)
+ matchFound = true;
+ break;
+ case PARAM_NUM:
+ if (paramList->id == param->paramid)
+ matchFound = true;
+ break;
+ default:
+ elog(ERROR, "unrecognized paramkind: %d",
+ thisParamKind);
+ }
+ }
+ if (!matchFound)
+ paramList++;
+ }
+ if (matchFound)
+ {
+ /*
+ * 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().
+ */
+ int16 typLen;
+ bool typByVal;
+
+ get_typlenbyval(param->paramtype, &typLen, &typByVal);
+ return (Node *) makeConst(param->paramtype,
+ (int) typLen,
+ paramList->value,
+ paramList->isnull,
+ typByVal);
+ }
+ }
+ /* Not replaceable, so just copy the Param (no need to recurse) */
+ return (Node *) copyObject(param);
+ }
if (IsA(node, FuncExpr))
{
FuncExpr *expr = (FuncExpr *) node;
@@ -1096,14 +1189,14 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* Code for op/func reduction is pretty bulky, so split it out as
* a separate function.
*/
simple = simplify_function(expr->funcid, expr->funcresulttype, args,
- true, active_fns);
+ true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
@@ -1134,7 +1227,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* Need to get OID of underlying function. Okay to scribble on
@@ -1147,7 +1240,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
- true, active_fns);
+ true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
@@ -1182,7 +1275,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
/*
* We must do our own check for NULLs because DistinctExpr has
@@ -1226,7 +1319,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* as a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype,
- args, false, active_fns);
+ args, false, context);
if (simple) /* successfully simplified it */
{
/*
@@ -1267,7 +1360,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
switch (expr->boolop)
{
@@ -1360,7 +1453,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
- active_fns);
+ context);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
@@ -1424,7 +1517,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
/* Simplify the test expression, if any */
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
- active_fns);
+ context);
/* Simplify the WHEN clauses */
newargs = NIL;
@@ -1434,7 +1527,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
CaseWhen *casewhen = (CaseWhen *)
expression_tree_mutator((Node *) lfirst(arg),
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
Assert(IsA(casewhen, CaseWhen));
if (casewhen->expr == NULL ||
@@ -1464,7 +1557,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
/* Simplify the default result */
defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
- active_fns);
+ context);
/*
* If no non-FALSE alternatives, CASE reduces to the default
@@ -1494,7 +1587,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(element),
- active_fns);
+ context);
if (!IsA(e, Const))
all_const = false;
newelems = lappend(newelems, e);
@@ -1525,7 +1618,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(arg),
- active_fns);
+ context);
/*
* We can remove null constants from the list. For a non-null
@@ -1561,7 +1654,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
- active_fns);
+ context);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber)
{
@@ -1595,7 +1688,7 @@ eval_const_expressions_mutator(Node *node, List *active_fns)
* simplify constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
}
/*
@@ -1726,14 +1819,15 @@ simplify_and_arguments(List *args, bool *haveNull, bool *forceFalse)
*
* Inputs are the function OID, actual result type OID (which is needed for
* polymorphic functions), and the pre-simplified argument list;
- * also a list of already-active inline function expansions.
+ * also the context data for eval_const_expressions.
*
* Returns a simplified expression if successful, or NULL if cannot
* simplify the function call.
*/
static Expr *
simplify_function(Oid funcid, Oid result_type, List *args,
- bool allow_inline, List *active_fns)
+ bool allow_inline,
+ eval_const_expressions_context *context)
{
HeapTuple func_tuple;
Expr *newexpr;
@@ -1756,7 +1850,7 @@ simplify_function(Oid funcid, Oid result_type, List *args,
if (!newexpr && allow_inline)
newexpr = inline_function(funcid, result_type, args,
- func_tuple, active_fns);
+ func_tuple, context);
ReleaseSysCache(func_tuple);
@@ -1860,7 +1954,8 @@ evaluate_function(Oid funcid, Oid result_type, List *args,
*/
static Expr *
inline_function(Oid funcid, Oid result_type, List *args,
- HeapTuple func_tuple, List *active_fns)
+ HeapTuple func_tuple,
+ eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
bool polymorphic = false;
@@ -1890,7 +1985,7 @@ inline_function(Oid funcid, Oid result_type, List *args,
return NULL;
/* Check for recursive function, and give up trying to expand if so */
- if (list_member_oid(active_fns, funcid))
+ if (list_member_oid(context->active_fns, funcid))
return NULL;
/* Check permission to call function (fail later, if not) */
@@ -2083,8 +2178,9 @@ inline_function(Oid funcid, Oid result_type, List *args,
* Recursively try to simplify the modified expression. Here we must
* add the current function to the context list of active functions.
*/
- newexpr = eval_const_expressions_mutator(newexpr,
- lcons_oid(funcid, active_fns));
+ context->active_fns = lcons_oid(funcid, context->active_fns);
+ newexpr = eval_const_expressions_mutator(newexpr, context);
+ context->active_fns = list_delete_first(context->active_fns);
error_context_stack = sqlerrcontext.previous;
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 07b60969a45..976b417e096 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.419 2004/06/06 00:41:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.420 2004/06/11 01:09:00 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -630,7 +630,7 @@ pg_rewrite_queries(List *querytree_list)
/* Generate a plan for a single already-rewritten query. */
Plan *
-pg_plan_query(Query *querytree)
+pg_plan_query(Query *querytree, ParamListInfo boundParams)
{
Plan *plan;
@@ -642,7 +642,7 @@ pg_plan_query(Query *querytree)
ResetUsage();
/* call the optimizer */
- plan = planner(querytree, false, 0);
+ plan = planner(querytree, false, 0, boundParams);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
@@ -687,7 +687,8 @@ pg_plan_query(Query *querytree)
* statements in the rewriter's output.)
*/
List *
-pg_plan_queries(List *querytrees, bool needSnapshot)
+pg_plan_queries(List *querytrees, ParamListInfo boundParams,
+ bool needSnapshot)
{
List *plan_list = NIL;
ListCell *query_list;
@@ -709,7 +710,7 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
SetQuerySnapshot();
needSnapshot = false;
}
- plan = pg_plan_query(query);
+ plan = pg_plan_query(query, boundParams);
}
plan_list = lappend(plan_list, plan);
@@ -867,7 +868,7 @@ exec_simple_query(const char *query_string)
querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0);
- plantree_list = pg_plan_queries(querytree_list, true);
+ plantree_list = pg_plan_queries(querytree_list, NULL, true);
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
@@ -1205,7 +1206,14 @@ exec_parse_message(const char *query_string, /* string to execute */
querytree_list = pg_rewrite_queries(querytree_list);
- plantree_list = pg_plan_queries(querytree_list, true);
+ /*
+ * If this is the unnamed statement and it has parameters, defer
+ * query planning until Bind. Otherwise do it now.
+ */
+ if (!is_named && numParams > 0)
+ plantree_list = NIL;
+ else
+ plantree_list = pg_plan_queries(querytree_list, NULL, true);
}
else
{
@@ -1291,6 +1299,7 @@ exec_bind_message(StringInfo input_message)
PreparedStatement *pstmt;
Portal portal;
ParamListInfo params;
+ bool isaborted = IsAbortedTransactionBlockState();
pgstat_report_activity("<BIND>");
@@ -1356,13 +1365,6 @@ exec_bind_message(StringInfo input_message)
else
portal = CreatePortal(portal_name, false, false);
- PortalDefineQuery(portal,
- pstmt->query_string,
- pstmt->commandTag,
- pstmt->query_list,
- pstmt->plan_list,
- pstmt->context);
-
/*
* Fetch parameters, if any, and store in the portal's memory context.
*
@@ -1372,7 +1374,6 @@ exec_bind_message(StringInfo input_message)
*/
if (numParams > 0)
{
- bool isaborted = IsAbortedTransactionBlockState();
ListCell *l;
MemoryContext oldContext;
@@ -1516,8 +1517,32 @@ exec_bind_message(StringInfo input_message)
pq_getmsgend(input_message);
/*
- * Start portal execution.
+ * If we didn't plan the query before, do it now. This allows the
+ * planner to make use of the concrete parameter values we now have.
+ *
+ * This happens only for unnamed statements, and so switching into
+ * the statement context for planning is correct (see notes in
+ * exec_parse_message).
*/
+ if (pstmt->plan_list == NIL && pstmt->query_list != NIL &&
+ !isaborted)
+ {
+ MemoryContext oldContext = MemoryContextSwitchTo(pstmt->context);
+
+ pstmt->plan_list = pg_plan_queries(pstmt->query_list, params, true);
+ MemoryContextSwitchTo(oldContext);
+ }
+
+ /*
+ * Define portal and start execution.
+ */
+ PortalDefineQuery(portal,
+ pstmt->query_string,
+ pstmt->commandTag,
+ pstmt->query_list,
+ pstmt->plan_list,
+ pstmt->context);
+
PortalStart(portal, params);
/*
diff --git a/src/backend/utils/adt/selfuncs.c b/src/backend/utils/adt/selfuncs.c
index 75eb0d2a529..c7ee847a11a 100644
--- a/src/backend/utils/adt/selfuncs.c
+++ b/src/backend/utils/adt/selfuncs.c
@@ -15,7 +15,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.160 2004/05/30 23:40:36 neilc Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/adt/selfuncs.c,v 1.161 2004/06/11 01:09:04 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -2823,7 +2823,8 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
*
* Outputs: (these are valid only if TRUE is returned)
* *vardata: gets information about variable (see examine_variable)
- * *other: gets other clause argument, stripped of binary relabeling
+ * *other: gets other clause argument, stripped of binary relabeling,
+ * and aggressively reduced to a constant
* *varonleft: set TRUE if variable is on the left, FALSE if on the right
*
* Returns TRUE if a variable is identified, otherwise FALSE.
@@ -2860,7 +2861,7 @@ get_restriction_variable(Query *root, List *args, int varRelid,
if (vardata->rel && rdata.rel == NULL)
{
*varonleft = true;
- *other = rdata.var;
+ *other = estimate_expression_value(rdata.var);
/* Assume we need no ReleaseVariableStats(rdata) here */
return true;
}
@@ -2868,7 +2869,7 @@ get_restriction_variable(Query *root, List *args, int varRelid,
if (vardata->rel == NULL && rdata.rel)
{
*varonleft = false;
- *other = vardata->var;
+ *other = estimate_expression_value(vardata->var);
/* Assume we need no ReleaseVariableStats(*vardata) here */
*vardata = rdata;
return true;
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 09f0822f468..4d645f43d59 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.73 2004/03/14 23:41:27 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/clauses.h,v 1.74 2004/06/11 01:09:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -67,6 +67,8 @@ extern void set_coercionform_dontcare(Node *node);
extern Node *eval_const_expressions(Node *node);
+extern Node *estimate_expression_value(Node *node);
+
extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context);
extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
diff --git a/src/include/optimizer/planner.h b/src/include/optimizer/planner.h
index 8688f3dd659..15440c24c4c 100644
--- a/src/include/optimizer/planner.h
+++ b/src/include/optimizer/planner.h
@@ -7,18 +7,22 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.28 2003/11/29 22:41:07 pgsql Exp $
+ * $PostgreSQL: pgsql/src/include/optimizer/planner.h,v 1.29 2004/06/11 01:09:12 tgl Exp $
*
*-------------------------------------------------------------------------
*/
#ifndef PLANNER_H
#define PLANNER_H
+#include "nodes/params.h"
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
-extern Plan *planner(Query *parse, bool isCursor, int cursorOptions);
+extern ParamListInfo PlannerBoundParamList; /* current boundParams */
+
+extern Plan *planner(Query *parse, bool isCursor, int cursorOptions,
+ ParamListInfo boundParams);
extern Plan *subquery_planner(Query *parse, double tuple_fraction);
#endif /* PLANNER_H */
diff --git a/src/include/tcop/tcopprot.h b/src/include/tcop/tcopprot.h
index 1218e04fdfb..0f55e9787fd 100644
--- a/src/include/tcop/tcopprot.h
+++ b/src/include/tcop/tcopprot.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.66 2004/05/29 22:48:23 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/tcop/tcopprot.h,v 1.67 2004/06/11 01:09:22 tgl Exp $
*
* OLD COMMENTS
* This file was created so that other c files could get the two
@@ -22,6 +22,7 @@
#include <setjmp.h>
#include "executor/execdesc.h"
+#include "nodes/params.h"
#include "tcop/dest.h"
#include "utils/guc.h"
@@ -55,8 +56,9 @@ extern List *pg_parse_query(const char *query_string);
extern List *pg_analyze_and_rewrite(Node *parsetree,
Oid *paramTypes, int numParams);
extern List *pg_rewrite_queries(List *querytree_list);
-extern Plan *pg_plan_query(Query *querytree);
-extern List *pg_plan_queries(List *querytrees, bool needSnapshot);
+extern Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams);
+extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams,
+ bool needSnapshot);
extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);