-<!-- $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>
</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
destroyed at the end of the transaction, or as soon as the next Bind
* 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"
typedef struct
{
+ List *active_fns;
+ bool estimate;
+} eval_const_expressions_context;
+
+typedef struct
+{
int nargs;
List *args;
int *usecounts;
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);