Index: doc/src/sgml/protocol.sgml
===================================================================
RCS file: /projects/cvsroot/pgsql-server/doc/src/sgml/protocol.sgml,v
retrieving revision 1.51
diff -u -c -r1.51 protocol.sgml
*** doc/src/sgml/protocol.sgml 21 Mar 2004 22:29:10 -0000 1.51
--- doc/src/sgml/protocol.sgml 24 May 2004 14:42:10 -0000
***************
*** 663,668 ****
--- 663,688 ----
+ Query planning of named prepared-statement objects occurs when the Parse
+ message is received. If a query will be repeatedly executed with
+ different parameters, it may be beneficial to send a single Parse message
+ containing a parameterized query, followed by multiple Bind
+ and Execute messages. This will avoid replanning the query on each
+ execution.
+
+
+
+
+ Query plans generated from a parameterized query may be less
+ efficient than query plans generated from an equivalent query with actual
+ parameter values substituted. The query planner cannot make decisions
+ based on actual parameter values (for example, index selectivity) when
+ planning a parameterized query assigned to a named prepared-statement
+ object.
+
+
+
+
Once a prepared statement exists, it can be readied for execution using a
Bind message. The Bind message gives the name of the source prepared
statement (empty string denotes the unnamed prepared statement), the name
***************
*** 674,679 ****
--- 694,720 ----
by the query; the format can be specified overall, or per-column.
The response is either BindComplete or ErrorResponse.
+
+
+ Query planning of the unnamed prepared-statement object occurs when the
+ first Bind message after a Parse message is received. The planner will
+ consider the actual values of any parameters provided in the Bind message
+ when planning the query. A Parse followed by Bind of the unnamed
+ prepared-statement object will produce the same query plan as for the
+ equivalent unparameterized query.
+
+
+
+
+ When a second or subsequent Bind referencing the unnamed prepared-
+ statement object is received without an intervening Parse, the query is
+ not replanned. The parameter values used in the first Bind message may
+ produce a query plan that is only efficient for a subset of possible
+ parameter values. To force replanning of the query on each execution, send
+ a Parse message to replace the unnamed prepared-statement object before
+ each Bind.
+
+
Index: src/backend/commands/explain.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/explain.c,v
retrieving revision 1.120
diff -u -c -r1.120 explain.c
*** src/backend/commands/explain.c 1 Apr 2004 21:28:44 -0000 1.120
--- src/backend/commands/explain.c 24 May 2004 14:42:10 -0000
***************
*** 176,182 ****
}
/* plan the query */
! plan = planner(query, isCursor, cursorOptions);
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
--- 176,182 ----
}
/* plan the query */
! plan = planner(query, isCursor, cursorOptions, NULL);
/* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
Index: src/backend/commands/portalcmds.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/portalcmds.c,v
retrieving revision 1.26
diff -u -c -r1.26 portalcmds.c
*** src/backend/commands/portalcmds.c 21 Mar 2004 22:29:10 -0000 1.26
--- src/backend/commands/portalcmds.c 24 May 2004 14:42:10 -0000
***************
*** 84,90 ****
errmsg("DECLARE CURSOR ... FOR UPDATE is not supported"),
errdetail("Cursors must be READ ONLY.")));
! plan = planner(query, true, stmt->options);
/*
* Create a portal and copy the query and plan into its memory
--- 84,90 ----
errmsg("DECLARE CURSOR ... FOR UPDATE is not supported"),
errdetail("Cursors must be READ ONLY.")));
! plan = planner(query, true, stmt->options, NULL);
/*
* Create a portal and copy the query and plan into its memory
Index: src/backend/commands/prepare.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/commands/prepare.c,v
retrieving revision 1.26
diff -u -c -r1.26 prepare.c
*** src/backend/commands/prepare.c 22 Apr 2004 02:58:20 -0000 1.26
--- src/backend/commands/prepare.c 24 May 2004 14:42:10 -0000
***************
*** 91,97 ****
query_list = QueryRewrite(stmt->query);
/* Generate plans for queries. Snapshot is already set. */
! plan_list = pg_plan_queries(query_list, false);
/* Save the results. */
StorePreparedStatement(stmt->name,
--- 91,97 ----
query_list = QueryRewrite(stmt->query);
/* Generate plans for queries. Snapshot is already set. */
! plan_list = pg_plan_queries(query_list, false, NULL);
/* Save the results. */
StorePreparedStatement(stmt->name,
Index: src/backend/executor/functions.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/functions.c,v
retrieving revision 1.80
diff -u -c -r1.80 functions.c
*** src/backend/executor/functions.c 2 Apr 2004 23:14:08 -0000 1.80
--- src/backend/executor/functions.c 24 May 2004 14:42:10 -0000
***************
*** 100,106 ****
Plan *planTree;
execution_state *newes;
! planTree = pg_plan_query(queryTree);
newes = (execution_state *) palloc(sizeof(execution_state));
if (preves)
--- 100,106 ----
Plan *planTree;
execution_state *newes;
! planTree = pg_plan_query(queryTree, NULL);
newes = (execution_state *) palloc(sizeof(execution_state));
if (preves)
Index: src/backend/executor/spi.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/executor/spi.c,v
retrieving revision 1.113
diff -u -c -r1.113 spi.c
*** src/backend/executor/spi.c 1 Apr 2004 21:28:44 -0000 1.113
--- src/backend/executor/spi.c 24 May 2004 14:42:10 -0000
***************
*** 1130,1136 ****
QueryDesc *qdesc;
DestReceiver *dest;
! planTree = pg_plan_query(queryTree);
plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
--- 1130,1136 ----
QueryDesc *qdesc;
DestReceiver *dest;
! planTree = pg_plan_query(queryTree, NULL);
plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
Index: src/backend/optimizer/path/clausesel.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/path/clausesel.c,v
retrieving revision 1.65
diff -u -c -r1.65 clausesel.c
*** src/backend/optimizer/path/clausesel.c 10 May 2004 22:44:45 -0000 1.65
--- src/backend/optimizer/path/clausesel.c 24 May 2004 14:42:11 -0000
***************
*** 489,496 ****
}
else if (IsA(clause, Param))
{
! /* XXX any way to do better? */
! s1 = 1.0;
}
else if (IsA(clause, Const))
{
--- 489,504 ----
}
else if (IsA(clause, Param))
{
! /* Try to collapse to Const. */
! Node *collapsed_clause = collapse_parameters_to_const(clause);
! if (IsA(collapsed_clause, Const)) {
! /* bool constant is pretty easy... */
! s1 = ((bool) ((Const *) collapsed_clause)->constvalue) ? 1.0 : 0.0;
! } else {
! /* Can't collapse to Const. */
! /* XXX any way to do better? */
! s1 = 1.0;
! }
}
else if (IsA(clause, Const))
{
Index: src/backend/optimizer/path/indxpath.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/path/indxpath.c,v
retrieving revision 1.158
diff -u -c -r1.158 indxpath.c
*** src/backend/optimizer/path/indxpath.c 27 Mar 2004 00:24:28 -0000 1.158
--- src/backend/optimizer/path/indxpath.c 24 May 2004 14:42:11 -0000
***************
*** 1068,1073 ****
--- 1068,1076 ----
rightop = get_rightop(predicate);
if (rightop == NULL)
return false; /* not a binary opclause */
+
+ rightop = collapse_parameters_to_const(rightop);
+ leftop = collapse_parameters_to_const(leftop);
if (IsA(rightop, Const))
{
pred_var = leftop;
***************
*** 1091,1096 ****
--- 1094,1102 ----
rightop = get_rightop((Expr *) clause);
if (rightop == NULL)
return false; /* not a binary opclause */
+
+ rightop = collapse_parameters_to_const(rightop);
+ leftop = collapse_parameters_to_const(leftop);
if (IsA(rightop, Const))
{
clause_var = leftop;
***************
*** 1873,1878 ****
--- 1879,1885 ----
expr_op = ((OpExpr *) clause)->opno;
/* again, required for all current special ops: */
+ rightop = collapse_parameters_to_const(rightop);
if (!IsA(rightop, Const) ||
((Const *) rightop)->constisnull)
return false;
***************
*** 2056,2062 ****
Node *leftop = get_leftop(clause);
Node *rightop = get_rightop(clause);
Oid expr_op = ((OpExpr *) clause)->opno;
! Const *patt = (Const *) rightop;
Const *prefix = NULL;
Const *rest = NULL;
Pattern_Prefix_Status pstatus;
--- 2063,2069 ----
Node *leftop = get_leftop(clause);
Node *rightop = get_rightop(clause);
Oid expr_op = ((OpExpr *) clause)->opno;
! Const *patt = (Const *) collapse_parameters_to_const(rightop);
Const *prefix = NULL;
Const *rest = NULL;
Pattern_Prefix_Status pstatus;
Index: src/backend/optimizer/plan/createplan.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/plan/createplan.c,v
retrieving revision 1.169
diff -u -c -r1.169 createplan.c
*** src/backend/optimizer/plan/createplan.c 25 Apr 2004 18:23:56 -0000 1.169
--- src/backend/optimizer/plan/createplan.c 24 May 2004 14:42:11 -0000
***************
*** 2330,2335 ****
--- 2330,2337 ----
* level, but if we are building a subquery then it's important to
* report correct info to the outer planner.
*/
+ if (limitOffset)
+ limitOffset = collapse_parameters_to_const(limitOffset);
if (limitOffset && IsA(limitOffset, Const))
{
Const *limito = (Const *) limitOffset;
***************
*** 2348,2353 ****
--- 2350,2357 ----
plan->plan_rows = 1;
}
}
+ if (limitCount)
+ limitCount = collapse_parameters_to_const(limitCount);
if (limitCount && IsA(limitCount, Const))
{
Const *limitc = (Const *) limitCount;
Index: src/backend/optimizer/plan/planner.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/plan/planner.c,v
retrieving revision 1.169
diff -u -c -r1.169 planner.c
*** src/backend/optimizer/plan/planner.c 11 May 2004 02:21:37 -0000 1.169
--- src/backend/optimizer/plan/planner.c 24 May 2004 14:42:11 -0000
***************
*** 71,82 ****
*
*****************************************************************************/
Plan *
! planner(Query *parse, bool isCursor, int cursorOptions)
{
double tuple_fraction;
Plan *result_plan;
Index save_PlannerQueryLevel;
List *save_PlannerParamList;
/*
* The planner can be called recursively (an example is when
--- 71,83 ----
*
*****************************************************************************/
Plan *
! 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
***************
*** 93,102 ****
--- 94,105 ----
*/
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,144 ****
--- 142,148 ----
/* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList;
+ PlannerBoundParamList = save_PlannerBoundParamList;
return result_plan;
}
***************
*** 401,407 ****
/*
* Simplify constant expressions.
*/
! expr = eval_const_expressions(expr);
/* Expand SubLinks to SubPlans */
if (parse->hasSubLinks)
--- 405,411 ----
/*
* Simplify constant expressions.
*/
! expr = eval_const_expressions(expr, NULL);
/* Expand SubLinks to SubPlans */
if (parse->hasSubLinks)
***************
*** 762,770 ****
*/
double limit_fraction = 0.0;
! if (IsA(parse->limitCount, Const))
{
! Const *limitc = (Const *) parse->limitCount;
int32 count = DatumGetInt32(limitc->constvalue);
/*
--- 766,775 ----
*/
double limit_fraction = 0.0;
! Node *limitCount = collapse_parameters_to_const(parse->limitCount);
! if (IsA(limitCount, Const))
{
! Const *limitc = (Const *) limitCount;
int32 count = DatumGetInt32(limitc->constvalue);
/*
***************
*** 778,788 ****
/* We must also consider the OFFSET, if present */
if (parse->limitOffset != NULL)
{
! if (IsA(parse->limitOffset, Const))
{
int32 offset;
! limitc = (Const *) parse->limitOffset;
offset = DatumGetInt32(limitc->constvalue);
if (!limitc->constisnull && offset > 0)
limit_fraction += (double) offset;
--- 783,794 ----
/* We must also consider the OFFSET, if present */
if (parse->limitOffset != NULL)
{
! Node *limitOffset = collapse_parameters_to_const(parse->limitCount);
! if (IsA(limitOffset, Const))
{
int32 offset;
! limitc = (Const *) limitOffset;
offset = DatumGetInt32(limitc->constvalue);
if (!limitc->constisnull && offset > 0)
limit_fraction += (double) offset;
Index: src/backend/optimizer/prep/prepunion.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/prep/prepunion.c,v
retrieving revision 1.110
diff -u -c -r1.110 prepunion.c
*** src/backend/optimizer/prep/prepunion.c 11 May 2004 22:43:55 -0000 1.110
--- src/backend/optimizer/prep/prepunion.c 24 May 2004 14:42:11 -0000
***************
*** 430,435 ****
--- 430,436 ----
TargetEntry *inputtle = (TargetEntry *) lfirst(input_tlist);
TargetEntry *reftle = (TargetEntry *) lfirst(refnames_tlist);
int32 colTypmod;
+ Node *collapsed_expr;
Assert(inputtle->resdom->resno == resno);
Assert(reftle->resdom->resno == resno);
***************
*** 449,456 ****
* subquery-scan plans; we don't want phony constants appearing in
* the output tlists of upper-level nodes!
*/
! if (hack_constants && inputtle->expr && IsA(inputtle->expr, Const))
! expr = (Node *) inputtle->expr;
else
expr = (Node *) makeVar(0,
inputtle->resdom->resno,
--- 450,459 ----
* subquery-scan plans; we don't want phony constants appearing in
* the output tlists of upper-level nodes!
*/
! if (hack_constants && inputtle->expr &&
! NULL != (collapsed_expr = collapse_parameters_to_const((Node *) inputtle->expr)) &&
! IsA(collapsed_expr, Const))
! expr = collapsed_expr;
else
expr = (Node *) makeVar(0,
inputtle->resdom->resno,
Index: src/backend/optimizer/util/clauses.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/optimizer/util/clauses.c,v
retrieving revision 1.170
diff -u -c -r1.170 clauses.c
*** src/backend/optimizer/util/clauses.c 10 May 2004 22:44:45 -0000 1.170
--- src/backend/optimizer/util/clauses.c 24 May 2004 14:42:12 -0000
***************
*** 28,37 ****
--- 28,39 ----
#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"
#include "parser/parse_expr.h"
+ #include "parser/parse_type.h"
#include "tcop/tcopprot.h"
#include "utils/acl.h"
#include "utils/builtins.h"
***************
*** 41,48 ****
--- 43,61 ----
#include "utils/syscache.h"
+ ParamListInfo PlannerBoundParamList = NULL; /* to keep track of currently-bound parameter values */
+
+
+ typedef struct
+ {
+ List *active_fns;
+ ParamListInfo params;
+ int nparams;
+ } eval_const_expressions_context;
+
typedef struct
{
+
int nargs;
List *args;
int *usecounts;
***************
*** 57,73 ****
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 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);
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);
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
int *usecounts);
static Node *substitute_actual_parameters_mutator(Node *node,
--- 70,86 ----
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, 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, eval_const_expressions_context *active_fns);
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, eval_const_expressions_context *active_fns);
static Node *substitute_actual_parameters(Node *expr, int nargs, List *args,
int *usecounts);
static Node *substitute_actual_parameters_mutator(Node *node,
***************
*** 1062,1078 ****
*--------------------
*/
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);
}
static Node *
! eval_const_expressions_mutator(Node *node, List *active_fns)
{
if (node == NULL)
return NULL;
--- 1075,1128 ----
*--------------------
*/
Node *
! eval_const_expressions(Node *node, ParamListInfo params)
{
/*
! * The context for the mutator is the parameter list plus
! * a list of SQL functions being recursively simplified.
! * The function list is initially empty.
*/
! int i;
! eval_const_expressions_context context;
! context.active_fns = NIL;
! context.params = params;
!
! if (params != NULL) {
! /* Count and check parameters. */
! for (i = 0; params[i].kind != PARAM_INVALID; ++i) {
! if (params[i].id != (i + 1))
! elog(ERROR, "param id mismatch: expected %d but was %d", i+1, params[i].id);
! }
!
! context.nparams = i;
! } else {
! context.nparams = 0;
! }
!
! return eval_const_expressions_mutator(node, &context);
! }
!
! /*
! * Helper for selectivity functions: apply a Param to Const replacement,
! * using parameters from PlannerBoundParamList, and return the new tree. Might
! * not copy the tree if it's obvious no change will happen.
! */
! Node *
! collapse_parameters_to_const(Node *node)
! {
! /* Already a leaf? */
! if (IsA(node, Const) || IsA(node, Var))
! return node;
!
! /* No parameters? */
! if (PlannerBoundParamList == NULL || PlannerBoundParamList[0].kind == PARAM_INVALID)
! return node;
!
! return eval_const_expressions(node, PlannerBoundParamList);
}
static Node *
! eval_const_expressions_mutator(Node *node, eval_const_expressions_context *context)
{
if (node == NULL)
return NULL;
***************
*** 1090,1103 ****
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) active_fns);
/*
* 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);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 1140,1153 ----
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (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, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 1128,1134 ****
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) active_fns);
/*
* Need to get OID of underlying function. Okay to scribble on
--- 1178,1184 ----
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) context);
/*
* Need to get OID of underlying function. Okay to scribble on
***************
*** 1141,1147 ****
* a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
! true, active_fns);
if (simple) /* successfully simplified it */
return (Node *) simple;
--- 1191,1197 ----
* a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
! true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
***************
*** 1176,1182 ****
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) active_fns);
/*
* We must do our own check for NULLs because DistinctExpr has
--- 1226,1232 ----
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) context);
/*
* We must do our own check for NULLs because DistinctExpr has
***************
*** 1220,1226 ****
* as a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype,
! args, false, active_fns);
if (simple) /* successfully simplified it */
{
/*
--- 1270,1276 ----
* as a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype,
! args, false, context);
if (simple) /* successfully simplified it */
{
/*
***************
*** 1261,1267 ****
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) active_fns);
switch (expr->boolop)
{
--- 1311,1317 ----
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
! (void *) context);
switch (expr->boolop)
{
***************
*** 1354,1360 ****
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
! active_fns);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
--- 1404,1410 ----
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
! context);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
***************
*** 1418,1424 ****
/* Simplify the test expression, if any */
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
! active_fns);
/* Simplify the WHEN clauses */
FastListInit(&newargs);
--- 1468,1474 ----
/* Simplify the test expression, if any */
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
! context);
/* Simplify the WHEN clauses */
FastListInit(&newargs);
***************
*** 1428,1434 ****
CaseWhen *casewhen = (CaseWhen *)
expression_tree_mutator((Node *) lfirst(arg),
eval_const_expressions_mutator,
! (void *) active_fns);
Assert(IsA(casewhen, CaseWhen));
if (casewhen->expr == NULL ||
--- 1478,1484 ----
CaseWhen *casewhen = (CaseWhen *)
expression_tree_mutator((Node *) lfirst(arg),
eval_const_expressions_mutator,
! (void *) context);
Assert(IsA(casewhen, CaseWhen));
if (casewhen->expr == NULL ||
***************
*** 1458,1464 ****
/* Simplify the default result */
defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
! active_fns);
/*
* If no non-FALSE alternatives, CASE reduces to the default
--- 1508,1514 ----
/* Simplify the default result */
defresult = eval_const_expressions_mutator((Node *) caseexpr->defresult,
! context);
/*
* If no non-FALSE alternatives, CASE reduces to the default
***************
*** 1488,1494 ****
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(element),
! active_fns);
if (!IsA(e, Const))
all_const = false;
FastAppend(&newelems, e);
--- 1538,1544 ----
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(element),
! context);
if (!IsA(e, Const))
all_const = false;
FastAppend(&newelems, e);
***************
*** 1519,1525 ****
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(arg),
! active_fns);
/*
* We can remove null constants from the list. For a non-null
--- 1569,1575 ----
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(arg),
! context);
/*
* We can remove null constants from the list. For a non-null
***************
*** 1555,1561 ****
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
! active_fns);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber)
{
--- 1605,1611 ----
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
! context);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber)
{
***************
*** 1580,1585 ****
--- 1630,1665 ----
newfselect->resulttypmod = fselect->resulttypmod;
return (Node *) newfselect;
}
+ if (IsA(node, Param))
+ {
+ /*
+ * Attempt to substitute concrete parameter values in, if we have them.
+ */
+
+ Param *param = (Param *) node;
+
+ if (param->paramkind == PARAM_NUM && context->params != NULL) {
+ /*
+ * Return a Constant in place of this Param.
+ */
+
+ Type type;
+ Const *replacement;
+
+ if (param->paramid <= 0 || param->paramid > context->nparams)
+ elog(ERROR, "invalid paramid: %d", param->paramid);
+
+ type = typeidType(param->paramtype);
+ replacement = makeConst(param->paramtype,
+ typeLen(type),
+ context->params[param->paramid - 1].value,
+ context->params[param->paramid - 1].isnull,
+ typeByVal(type));
+
+ ReleaseSysCache(type);
+ return (Node *) replacement;
+ }
+ }
/*
* For any node type not handled above, we recurse using
***************
*** 1589,1595 ****
* simplify constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
! (void *) active_fns);
}
/*
--- 1669,1675 ----
* simplify constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
! (void *) context);
}
/*
***************
*** 1727,1733 ****
*/
static Expr *
simplify_function(Oid funcid, Oid result_type, List *args,
! bool allow_inline, List *active_fns)
{
HeapTuple func_tuple;
Expr *newexpr;
--- 1807,1813 ----
*/
static Expr *
simplify_function(Oid funcid, Oid result_type, List *args,
! bool allow_inline, eval_const_expressions_context *context)
{
HeapTuple func_tuple;
Expr *newexpr;
***************
*** 1750,1756 ****
if (!newexpr && allow_inline)
newexpr = inline_function(funcid, result_type, args,
! func_tuple, active_fns);
ReleaseSysCache(func_tuple);
--- 1830,1836 ----
if (!newexpr && allow_inline)
newexpr = inline_function(funcid, result_type, args,
! func_tuple, context);
ReleaseSysCache(func_tuple);
***************
*** 1854,1860 ****
*/
static Expr *
inline_function(Oid funcid, Oid result_type, List *args,
! HeapTuple func_tuple, List *active_fns)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
bool polymorphic = false;
--- 1934,1940 ----
*/
static Expr *
inline_function(Oid funcid, Oid result_type, List *args,
! HeapTuple func_tuple, eval_const_expressions_context *context)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
bool polymorphic = false;
***************
*** 1884,1890 ****
return NULL;
/* Check for recursive function, and give up trying to expand if so */
! if (oidMember(funcid, active_fns))
return NULL;
/* Check permission to call function (fail later, if not) */
--- 1964,1970 ----
return NULL;
/* Check for recursive function, and give up trying to expand if so */
! if (oidMember(funcid, context->active_fns))
return NULL;
/* Check permission to call function (fail later, if not) */
***************
*** 2077,2084 ****
* 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,
! lconso(funcid, active_fns));
error_context_stack = sqlerrcontext.previous;
--- 2157,2164 ----
* Recursively try to simplify the modified expression. Here we must
* add the current function to the context list of active functions.
*/
! context->active_fns = lconso(funcid, context->active_fns);
! newexpr = eval_const_expressions_mutator(newexpr, context);
error_context_stack = sqlerrcontext.previous;
Index: src/backend/tcop/postgres.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/tcop/postgres.c,v
retrieving revision 1.414
diff -u -c -r1.414 postgres.c
*** src/backend/tcop/postgres.c 23 May 2004 03:50:45 -0000 1.414
--- src/backend/tcop/postgres.c 24 May 2004 14:42:12 -0000
***************
*** 631,637 ****
/* Generate a plan for a single already-rewritten query. */
Plan *
! pg_plan_query(Query *querytree)
{
Plan *plan;
--- 631,637 ----
/* Generate a plan for a single already-rewritten query. */
Plan *
! pg_plan_query(Query *querytree, ParamListInfo params)
{
Plan *plan;
***************
*** 643,649 ****
ResetUsage();
/* call the optimizer */
! plan = planner(querytree, false, 0);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
--- 643,649 ----
ResetUsage();
/* call the optimizer */
! plan = planner(querytree, false, 0, params);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
***************
*** 688,694 ****
* statements in the rewriter's output.)
*/
List *
! pg_plan_queries(List *querytrees, bool needSnapshot)
{
List *plan_list = NIL;
List *query_list;
--- 688,694 ----
* statements in the rewriter's output.)
*/
List *
! pg_plan_queries(List *querytrees, bool needSnapshot, ParamListInfo params)
{
List *plan_list = NIL;
List *query_list;
***************
*** 710,716 ****
SetQuerySnapshot();
needSnapshot = false;
}
! plan = pg_plan_query(query);
}
plan_list = lappend(plan_list, plan);
--- 710,716 ----
SetQuerySnapshot();
needSnapshot = false;
}
! plan = pg_plan_query(query, params);
}
plan_list = lappend(plan_list, plan);
***************
*** 868,874 ****
querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0);
! plantree_list = pg_plan_queries(querytree_list, true);
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
--- 868,874 ----
querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0);
! plantree_list = pg_plan_queries(querytree_list, true, NULL);
/* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS();
***************
*** 1206,1212 ****
querytree_list = pg_rewrite_queries(querytree_list);
! plantree_list = pg_plan_queries(querytree_list, true);
}
else
{
--- 1206,1217 ----
querytree_list = pg_rewrite_queries(querytree_list);
! /* If this is the unnamed statement and we have parameters, defer query planning until Bind. */
! if (!is_named && numParams > 0) {
! plantree_list = NIL;
! } else {
! plantree_list = pg_plan_queries(querytree_list, true, NULL);
! }
}
else
{
***************
*** 1357,1368 ****
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.
--- 1362,1368 ----
else
portal = CreatePortal(portal_name, false, false);
! /* Defer portal query definition until we're sure planning is done. */
/*
* Fetch parameters, if any, and store in the portal's memory context.
***************
*** 1517,1524 ****
pq_getmsgend(input_message);
/*
! * Start portal execution.
*/
PortalStart(portal, params);
/*
--- 1517,1542 ----
pq_getmsgend(input_message);
/*
! * If this is the unnamed statement, we may not have planned the
! * query yet. In that case, do the planning (in the query's
! * memory context) now that we have concrete parameter values.
! */
! if (pstmt->plan_list == NIL && pstmt->query_list != NIL) {
! MemoryContext oldContext = MemoryContextSwitchTo(pstmt->context);
! pstmt->plan_list = pg_plan_queries(pstmt->query_list, true, params);
! 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);
/*
Index: src/backend/utils/adt/selfuncs.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/adt/selfuncs.c,v
retrieving revision 1.158
diff -u -c -r1.158 selfuncs.c
*** src/backend/utils/adt/selfuncs.c 27 Feb 2004 21:44:34 -0000 1.158
--- src/backend/utils/adt/selfuncs.c 24 May 2004 14:42:12 -0000
***************
*** 242,247 ****
--- 242,249 ----
&vardata, &other, &varonleft))
PG_RETURN_FLOAT8(DEFAULT_EQ_SEL);
+ other = collapse_parameters_to_const(other);
+
/*
* If the something is a NULL constant, assume operator is strict and
* return zero, ie, operator will never return TRUE.
***************
*** 711,716 ****
--- 713,720 ----
&vardata, &other, &varonleft))
PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+ other = collapse_parameters_to_const(other);
+
/*
* Can't do anything useful if the something is not a constant,
* either.
***************
*** 787,792 ****
--- 791,798 ----
&vardata, &other, &varonleft))
PG_RETURN_FLOAT8(DEFAULT_INEQ_SEL);
+ other = collapse_parameters_to_const(other);
+
/*
* Can't do anything useful if the something is not a constant,
* either.
***************
*** 870,876 ****
if (!get_restriction_variable(root, args, varRelid,
&vardata, &other, &varonleft))
return DEFAULT_MATCH_SEL;
! if (!varonleft || !IsA(other, Const))
{
ReleaseVariableStats(vardata);
return DEFAULT_MATCH_SEL;
--- 876,891 ----
if (!get_restriction_variable(root, args, varRelid,
&vardata, &other, &varonleft))
return DEFAULT_MATCH_SEL;
!
! if (!varonleft)
! {
! ReleaseVariableStats(vardata);
! return DEFAULT_MATCH_SEL;
! }
!
! other = collapse_parameters_to_const(other);
!
! if (!IsA(other, Const))
{
ReleaseVariableStats(vardata);
return DEFAULT_MATCH_SEL;
Index: src/backend/utils/cache/relcache.c
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/backend/utils/cache/relcache.c,v
retrieving revision 1.202
diff -u -c -r1.202 relcache.c
*** src/backend/utils/cache/relcache.c 8 May 2004 19:09:25 -0000 1.202
--- src/backend/utils/cache/relcache.c 24 May 2004 14:42:13 -0000
***************
*** 2680,2686 ****
*/
result = (List *) flatten_andors((Node *) result);
! result = (List *) eval_const_expressions((Node *) result);
/*
* Also mark any coercion format fields as "don't care", so that the
--- 2680,2686 ----
*/
result = (List *) flatten_andors((Node *) result);
! result = (List *) eval_const_expressions((Node *) result, NULL);
/*
* Also mark any coercion format fields as "don't care", so that the
***************
*** 2754,2760 ****
*/
result = (List *) canonicalize_qual((Expr *) result);
! result = (List *) eval_const_expressions((Node *) result);
/*
* Also mark any coercion format fields as "don't care", so that the
--- 2754,2760 ----
*/
result = (List *) canonicalize_qual((Expr *) result);
! result = (List *) eval_const_expressions((Node *) result, NULL);
/*
* Also mark any coercion format fields as "don't care", so that the
Index: src/include/optimizer/clauses.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/optimizer/clauses.h,v
retrieving revision 1.73
diff -u -c -r1.73 clauses.h
*** src/include/optimizer/clauses.h 14 Mar 2004 23:41:27 -0000 1.73
--- src/include/optimizer/clauses.h 24 May 2004 14:42:13 -0000
***************
*** 15,22 ****
#define CLAUSES_H
#include "nodes/relation.h"
!
#define is_opclause(clause) ((clause) != NULL && IsA(clause, OpExpr))
#define is_funcclause(clause) ((clause) != NULL && IsA(clause, FuncExpr))
--- 15,23 ----
#define CLAUSES_H
#include "nodes/relation.h"
+ #include "nodes/params.h"
! extern ParamListInfo PlannerBoundParamList; /* to keep track of externally-specified parameter values */
#define is_opclause(clause) ((clause) != NULL && IsA(clause, OpExpr))
#define is_funcclause(clause) ((clause) != NULL && IsA(clause, FuncExpr))
***************
*** 65,71 ****
extern void set_coercionform_dontcare(Node *node);
! extern Node *eval_const_expressions(Node *node);
extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context);
--- 66,74 ----
extern void set_coercionform_dontcare(Node *node);
! extern Node *eval_const_expressions(Node *node, ParamListInfo params);
!
! extern Node *collapse_parameters_to_const(Node *node);
extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context);
Index: src/include/optimizer/planner.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/optimizer/planner.h,v
retrieving revision 1.28
diff -u -c -r1.28 planner.h
*** src/include/optimizer/planner.h 29 Nov 2003 22:41:07 -0000 1.28
--- src/include/optimizer/planner.h 24 May 2004 14:42:13 -0000
***************
*** 16,24 ****
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
!
! extern Plan *planner(Query *parse, bool isCursor, int cursorOptions);
extern Plan *subquery_planner(Query *parse, double tuple_fraction);
#endif /* PLANNER_H */
--- 16,24 ----
#include "nodes/parsenodes.h"
#include "nodes/plannodes.h"
+ #include "nodes/params.h"
! extern Plan *planner(Query *parse, bool isCursor, int cursorOptions, ParamListInfo extParams);
extern Plan *subquery_planner(Query *parse, double tuple_fraction);
#endif /* PLANNER_H */
Index: src/include/tcop/tcopprot.h
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/include/tcop/tcopprot.h,v
retrieving revision 1.65
diff -u -c -r1.65 tcopprot.h
*** src/include/tcop/tcopprot.h 11 Apr 2004 00:54:45 -0000 1.65
--- src/include/tcop/tcopprot.h 24 May 2004 14:42:13 -0000
***************
*** 24,29 ****
--- 24,30 ----
#include "executor/execdesc.h"
#include "tcop/dest.h"
#include "utils/guc.h"
+ #include "nodes/params.h"
extern DLLIMPORT sigjmp_buf Warn_restart;
***************
*** 57,64 ****
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 bool assign_max_stack_depth(int newval, bool doit, GucSource source);
--- 58,65 ----
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, ParamListInfo params);
! extern List *pg_plan_queries(List *querytrees, bool needSnapshot, ParamListInfo params);
extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);