-<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.51 2004/03/21 22:29:10 tgl Exp $ -->
+<!-- $PostgreSQL: pgsql/doc/src/sgml/protocol.sgml,v 1.52 2004/06/11 01:08:33 tgl Exp $ -->
<chapter id="protocol">
<title>Frontend/Backend Protocol</title>
</para>
</note>
+ <para>
+ Query planning for 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.
+ </para>
+
+ <para>
+ The unnamed prepared statement is likewise planned during Parse processing
+ if the Parse message defines no parameters. But if there are parameters,
+ query planning is delayed until the first Bind message for the statement
+ is received. The planner will consider the actual values of the parameters
+ provided in the Bind message when planning the query.
+ </para>
+
+ <note>
+ <para>
+ 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. This possible penalty is avoided when using the unnamed
+ statement, since it is not planned until actual parameter values are
+ available.
+ </para>
+
+ <para>
+ If 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 for a fresh set of
+ parameters, send another Parse message to replace the unnamed
+ prepared-statement object.
+ </para>
+ </note>
+
<para>
If successfully created, a named portal object lasts till the end of the
current transaction, unless explicitly destroyed. An unnamed portal is
* 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 $
*
*-------------------------------------------------------------------------
*/
}
/* 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,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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
* 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 $
*
*-------------------------------------------------------------------------
*/
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,
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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)
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
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);
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
}
}
}
- 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 */
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
#include "utils/syscache.h"
+ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
+
+
/* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1
*
*****************************************************************************/
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
*/
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)
/* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList;
+ PlannerBoundParamList = save_PlannerBoundParamList;
return result_plan;
}
*
*
* 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
#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 "utils/syscache.h"
+typedef struct
+{
+ List *active_fns;
+ bool estimate;
+} eval_const_expressions_context;
+
typedef struct
{
int nargs;
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,
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;
*/
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;
*/
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
* a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype, args,
- true, active_fns);
+ true, context);
if (simple) /* successfully simplified it */
return (Node *) simple;
*/
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
* as a separate function.
*/
simple = simplify_function(expr->opfuncid, expr->opresulttype,
- args, false, active_fns);
+ args, false, context);
if (simple) /* successfully simplified it */
{
/*
*/
args = (List *) expression_tree_mutator((Node *) expr->args,
eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
switch (expr->boolop)
{
Node *arg;
arg = eval_const_expressions_mutator((Node *) relabel->arg,
- active_fns);
+ context);
/*
* If we find stacked RelabelTypes (eg, from foo :: int :: oid) we
/* Simplify the test expression, if any */
newarg = eval_const_expressions_mutator((Node *) caseexpr->arg,
- active_fns);
+ context);
/* Simplify the WHEN clauses */
newargs = NIL;
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 ||
/* 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
Node *e;
e = eval_const_expressions_mutator((Node *) lfirst(element),
- active_fns);
+ context);
if (!IsA(e, Const))
all_const = false;
newelems = lappend(newelems, e);
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
Node *arg;
arg = eval_const_expressions_mutator((Node *) fselect->arg,
- active_fns);
+ context);
if (arg && IsA(arg, Var) &&
((Var *) arg)->varattno == InvalidAttrNumber)
{
* simplify constant expressions in its subscripts.
*/
return expression_tree_mutator(node, eval_const_expressions_mutator,
- (void *) active_fns);
+ (void *) context);
}
/*
*
* 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;
if (!newexpr && allow_inline)
newexpr = inline_function(funcid, result_type, args,
- func_tuple, active_fns);
+ func_tuple, context);
ReleaseSysCache(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)
{
Form_pg_proc funcform = (Form_pg_proc) GETSTRUCT(func_tuple);
bool polymorphic = false;
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) */
* 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;
*
*
* 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
/* Generate a plan for a single already-rewritten query. */
Plan *
-pg_plan_query(Query *querytree)
+pg_plan_query(Query *querytree, ParamListInfo boundParams)
{
Plan *plan;
ResetUsage();
/* call the optimizer */
- plan = planner(querytree, false, 0);
+ plan = planner(querytree, false, 0, boundParams);
if (log_planner_stats)
ShowUsage("PLANNER STATISTICS");
* 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;
SetQuerySnapshot();
needSnapshot = false;
}
- plan = pg_plan_query(query);
+ plan = pg_plan_query(query, boundParams);
}
plan_list = lappend(plan_list, plan);
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();
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
{
PreparedStatement *pstmt;
Portal portal;
ParamListInfo params;
+ bool isaborted = IsAbortedTransactionBlockState();
pgstat_report_activity("<BIND>");
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.
*
*/
if (numParams > 0)
{
- bool isaborted = IsAbortedTransactionBlockState();
ListCell *l;
MemoryContext oldContext;
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);
/*
*
*
* 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 $
*
*-------------------------------------------------------------------------
*/
*
* 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.
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;
}
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;
* 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 $
*
*-------------------------------------------------------------------------
*/
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) (),
* 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 */
* 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
#include <setjmp.h>
#include "executor/execdesc.h"
+#include "nodes/params.h"
#include "tcop/dest.h"
#include "utils/guc.h"
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);