Commit 7643bed5 authored by Tom Lane's avatar Tom Lane

When using extended-query protocol, postpone planning of unnamed statements

until Bind is received, so that actual parameter values are visible to the
planner.  Make use of the parameter values for estimation purposes (but
don't fold them into the actual plan).  This buys back most of the
potential loss of plan quality that ensues from using out-of-line
parameters instead of putting literal values right into the query text.

This patch creates a notion of constant-folding expressions 'for
estimation purposes only', in which case we can be more aggressive than
the normal eval_const_expressions() logic can be.  Right now the only
difference in behavior is inserting bound values for Params, but it will
be interesting to look at other possibilities.  One that we've seen
come up repeatedly is reducing now() and related functions to current
values, so that queries like ... WHERE timestampcol > now() - '1 day'
have some chance of being planned effectively.

Oliver Jowett, with some kibitzing from Tom Lane.
parent 5fe8c7d6
<!-- $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"> <chapter id="protocol">
<title>Frontend/Backend Protocol</title> <title>Frontend/Backend Protocol</title>
...@@ -684,6 +684,46 @@ ...@@ -684,6 +684,46 @@
</para> </para>
</note> </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> <para>
If successfully created, a named portal object lasts till the end of the If successfully created, a named portal object lasts till the end of the
current transaction, unless explicitly destroyed. An unnamed portal is current transaction, unless explicitly destroyed. An unnamed portal is
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California * Portions Copyright (c) 1994-5, Regents of the University of California
* *
* IDENTIFICATION * 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) ...@@ -176,7 +176,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, TupOutputState *tstate)
} }
/* plan the query */ /* plan the query */
plan = planner(query, isCursor, cursorOptions); plan = planner(query, isCursor, cursorOptions, NULL);
/* Create a QueryDesc requesting no output */ /* Create a QueryDesc requesting no output */
queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL, queryDesc = CreateQueryDesc(query, plan, None_Receiver, NULL,
......
...@@ -14,7 +14,7 @@ ...@@ -14,7 +14,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -84,7 +84,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt)
errmsg("DECLARE CURSOR ... FOR UPDATE is not supported"), errmsg("DECLARE CURSOR ... FOR UPDATE is not supported"),
errdetail("Cursors must be READ ONLY."))); 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 * Create a portal and copy the query and plan into its memory
......
...@@ -10,7 +10,7 @@ ...@@ -10,7 +10,7 @@
* Copyright (c) 2002-2003, PostgreSQL Global Development Group * Copyright (c) 2002-2003, PostgreSQL Global Development Group
* *
* IDENTIFICATION * 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) ...@@ -91,7 +91,7 @@ PrepareQuery(PrepareStmt *stmt)
query_list = QueryRewrite(stmt->query); query_list = QueryRewrite(stmt->query);
/* Generate plans for queries. Snapshot is already set. */ /* 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. */ /* Save the results. */
StorePreparedStatement(stmt->name, StorePreparedStatement(stmt->name,
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -100,7 +100,7 @@ init_execution_state(List *queryTree_list)
Plan *planTree; Plan *planTree;
execution_state *newes; execution_state *newes;
planTree = pg_plan_query(queryTree); planTree = pg_plan_query(queryTree, NULL);
newes = (execution_state *) palloc(sizeof(execution_state)); newes = (execution_state *) palloc(sizeof(execution_state));
if (preves) if (preves)
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -1125,7 +1125,7 @@ _SPI_execute(const char *src, int tcount, _SPI_plan *plan)
QueryDesc *qdesc; QueryDesc *qdesc;
DestReceiver *dest; DestReceiver *dest;
planTree = pg_plan_query(queryTree); planTree = pg_plan_query(queryTree, NULL);
plan_list = lappend(plan_list, planTree); plan_list = lappend(plan_list, planTree);
dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL); dest = CreateDestReceiver(queryTree->canSetTag ? SPI : None, NULL);
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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, ...@@ -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)) else if (IsA(clause, Const))
{ {
/* bool constant is pretty easy... */ /* bool constant is pretty easy... */
s1 = ((bool) ((Const *) clause)->constvalue) ? 1.0 : 0.0; 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)) else if (not_clause(clause))
{ {
/* inverse of the selectivity of the underlying clause */ /* inverse of the selectivity of the underlying clause */
......
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 @@ ...@@ -43,6 +43,9 @@
#include "utils/syscache.h" #include "utils/syscache.h"
ParamListInfo PlannerBoundParamList = NULL; /* current boundParams */
/* Expression kind codes for preprocess_expression */ /* Expression kind codes for preprocess_expression */
#define EXPRKIND_QUAL 0 #define EXPRKIND_QUAL 0
#define EXPRKIND_TARGET 1 #define EXPRKIND_TARGET 1
...@@ -71,20 +74,24 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist); ...@@ -71,20 +74,24 @@ static List *postprocess_setop_tlist(List *new_tlist, List *orig_tlist);
* *
*****************************************************************************/ *****************************************************************************/
Plan * Plan *
planner(Query *parse, bool isCursor, int cursorOptions) planner(Query *parse, bool isCursor, int cursorOptions,
ParamListInfo boundParams)
{ {
double tuple_fraction; double tuple_fraction;
Plan *result_plan; Plan *result_plan;
Index save_PlannerQueryLevel; Index save_PlannerQueryLevel;
List *save_PlannerParamList; List *save_PlannerParamList;
ParamListInfo save_PlannerBoundParamList;
/* /*
* The planner can be called recursively (an example is when * The planner can be called recursively (an example is when
* eval_const_expressions tries to pre-evaluate an SQL function). So, * eval_const_expressions tries to pre-evaluate an SQL function). So,
* these global state variables must be saved and restored. * these global state variables must be saved and restored.
* *
* These vars cannot be moved into the Query structure since their whole * Query level and the param list cannot be moved into the Query structure
* purpose is communication across multiple sub-Queries. * 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 * 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 * 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) ...@@ -93,10 +100,12 @@ planner(Query *parse, bool isCursor, int cursorOptions)
*/ */
save_PlannerQueryLevel = PlannerQueryLevel; save_PlannerQueryLevel = PlannerQueryLevel;
save_PlannerParamList = PlannerParamList; save_PlannerParamList = PlannerParamList;
save_PlannerBoundParamList = PlannerBoundParamList;
/* Initialize state for handling outer-level references and params */ /* Initialize state for handling outer-level references and params */
PlannerQueryLevel = 0; /* will be 1 in top-level subquery_planner */ PlannerQueryLevel = 0; /* will be 1 in top-level subquery_planner */
PlannerParamList = NIL; PlannerParamList = NIL;
PlannerBoundParamList = boundParams;
/* Determine what fraction of the plan is likely to be scanned */ /* Determine what fraction of the plan is likely to be scanned */
if (isCursor) if (isCursor)
...@@ -139,6 +148,7 @@ planner(Query *parse, bool isCursor, int cursorOptions) ...@@ -139,6 +148,7 @@ planner(Query *parse, bool isCursor, int cursorOptions)
/* restore state for outer planner, if any */ /* restore state for outer planner, if any */
PlannerQueryLevel = save_PlannerQueryLevel; PlannerQueryLevel = save_PlannerQueryLevel;
PlannerParamList = save_PlannerParamList; PlannerParamList = save_PlannerParamList;
PlannerBoundParamList = save_PlannerBoundParamList;
return result_plan; return result_plan;
} }
......
This diff is collapsed.
...@@ -8,7 +8,7 @@ ...@@ -8,7 +8,7 @@
* *
* *
* IDENTIFICATION * 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 * NOTES
* this is the "main" module of the postgres backend and * this is the "main" module of the postgres backend and
...@@ -630,7 +630,7 @@ pg_rewrite_queries(List *querytree_list) ...@@ -630,7 +630,7 @@ pg_rewrite_queries(List *querytree_list)
/* Generate a plan for a single already-rewritten query. */ /* Generate a plan for a single already-rewritten query. */
Plan * Plan *
pg_plan_query(Query *querytree) pg_plan_query(Query *querytree, ParamListInfo boundParams)
{ {
Plan *plan; Plan *plan;
...@@ -642,7 +642,7 @@ pg_plan_query(Query *querytree) ...@@ -642,7 +642,7 @@ pg_plan_query(Query *querytree)
ResetUsage(); ResetUsage();
/* call the optimizer */ /* call the optimizer */
plan = planner(querytree, false, 0); plan = planner(querytree, false, 0, boundParams);
if (log_planner_stats) if (log_planner_stats)
ShowUsage("PLANNER STATISTICS"); ShowUsage("PLANNER STATISTICS");
...@@ -687,7 +687,8 @@ pg_plan_query(Query *querytree) ...@@ -687,7 +687,8 @@ pg_plan_query(Query *querytree)
* statements in the rewriter's output.) * statements in the rewriter's output.)
*/ */
List * List *
pg_plan_queries(List *querytrees, bool needSnapshot) pg_plan_queries(List *querytrees, ParamListInfo boundParams,
bool needSnapshot)
{ {
List *plan_list = NIL; List *plan_list = NIL;
ListCell *query_list; ListCell *query_list;
...@@ -709,7 +710,7 @@ pg_plan_queries(List *querytrees, bool needSnapshot) ...@@ -709,7 +710,7 @@ pg_plan_queries(List *querytrees, bool needSnapshot)
SetQuerySnapshot(); SetQuerySnapshot();
needSnapshot = false; needSnapshot = false;
} }
plan = pg_plan_query(query); plan = pg_plan_query(query, boundParams);
} }
plan_list = lappend(plan_list, plan); plan_list = lappend(plan_list, plan);
...@@ -867,7 +868,7 @@ exec_simple_query(const char *query_string) ...@@ -867,7 +868,7 @@ exec_simple_query(const char *query_string)
querytree_list = pg_analyze_and_rewrite(parsetree, NULL, 0); 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 */ /* If we got a cancel signal in analysis or planning, quit */
CHECK_FOR_INTERRUPTS(); CHECK_FOR_INTERRUPTS();
...@@ -1205,7 +1206,14 @@ exec_parse_message(const char *query_string, /* string to execute */ ...@@ -1205,7 +1206,14 @@ exec_parse_message(const char *query_string, /* string to execute */
querytree_list = pg_rewrite_queries(querytree_list); 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 else
{ {
...@@ -1291,6 +1299,7 @@ exec_bind_message(StringInfo input_message) ...@@ -1291,6 +1299,7 @@ exec_bind_message(StringInfo input_message)
PreparedStatement *pstmt; PreparedStatement *pstmt;
Portal portal; Portal portal;
ParamListInfo params; ParamListInfo params;
bool isaborted = IsAbortedTransactionBlockState();
pgstat_report_activity("<BIND>"); pgstat_report_activity("<BIND>");
...@@ -1356,13 +1365,6 @@ exec_bind_message(StringInfo input_message) ...@@ -1356,13 +1365,6 @@ exec_bind_message(StringInfo input_message)
else else
portal = CreatePortal(portal_name, false, false); 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. * Fetch parameters, if any, and store in the portal's memory context.
* *
...@@ -1372,7 +1374,6 @@ exec_bind_message(StringInfo input_message) ...@@ -1372,7 +1374,6 @@ exec_bind_message(StringInfo input_message)
*/ */
if (numParams > 0) if (numParams > 0)
{ {
bool isaborted = IsAbortedTransactionBlockState();
ListCell *l; ListCell *l;
MemoryContext oldContext; MemoryContext oldContext;
...@@ -1516,8 +1517,32 @@ exec_bind_message(StringInfo input_message) ...@@ -1516,8 +1517,32 @@ exec_bind_message(StringInfo input_message)
pq_getmsgend(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); PortalStart(portal, params);
/* /*
......
...@@ -15,7 +15,7 @@ ...@@ -15,7 +15,7 @@
* *
* *
* IDENTIFICATION * 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) ...@@ -2823,7 +2823,8 @@ convert_timevalue_to_scalar(Datum value, Oid typid)
* *
* Outputs: (these are valid only if TRUE is returned) * Outputs: (these are valid only if TRUE is returned)
* *vardata: gets information about variable (see examine_variable) * *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 * *varonleft: set TRUE if variable is on the left, FALSE if on the right
* *
* Returns TRUE if a variable is identified, otherwise FALSE. * Returns TRUE if a variable is identified, otherwise FALSE.
...@@ -2860,7 +2861,7 @@ get_restriction_variable(Query *root, List *args, int varRelid, ...@@ -2860,7 +2861,7 @@ get_restriction_variable(Query *root, List *args, int varRelid,
if (vardata->rel && rdata.rel == NULL) if (vardata->rel && rdata.rel == NULL)
{ {
*varonleft = true; *varonleft = true;
*other = rdata.var; *other = estimate_expression_value(rdata.var);
/* Assume we need no ReleaseVariableStats(rdata) here */ /* Assume we need no ReleaseVariableStats(rdata) here */
return true; return true;
} }
...@@ -2868,7 +2869,7 @@ get_restriction_variable(Query *root, List *args, int varRelid, ...@@ -2868,7 +2869,7 @@ get_restriction_variable(Query *root, List *args, int varRelid,
if (vardata->rel == NULL && rdata.rel) if (vardata->rel == NULL && rdata.rel)
{ {
*varonleft = false; *varonleft = false;
*other = vardata->var; *other = estimate_expression_value(vardata->var);
/* Assume we need no ReleaseVariableStats(*vardata) here */ /* Assume we need no ReleaseVariableStats(*vardata) here */
*vardata = rdata; *vardata = rdata;
return true; return true;
......
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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); ...@@ -67,6 +67,8 @@ extern void set_coercionform_dontcare(Node *node);
extern Node *eval_const_expressions(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) (), extern bool expression_tree_walker(Node *node, bool (*walker) (),
void *context); void *context);
extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (), extern Node *expression_tree_mutator(Node *node, Node *(*mutator) (),
......
...@@ -7,18 +7,22 @@ ...@@ -7,18 +7,22 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 #ifndef PLANNER_H
#define PLANNER_H #define PLANNER_H
#include "nodes/params.h"
#include "nodes/parsenodes.h" #include "nodes/parsenodes.h"
#include "nodes/plannodes.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); extern Plan *subquery_planner(Query *parse, double tuple_fraction);
#endif /* PLANNER_H */ #endif /* PLANNER_H */
...@@ -7,7 +7,7 @@ ...@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California * 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 * OLD COMMENTS
* This file was created so that other c files could get the two * This file was created so that other c files could get the two
...@@ -22,6 +22,7 @@ ...@@ -22,6 +22,7 @@
#include <setjmp.h> #include <setjmp.h>
#include "executor/execdesc.h" #include "executor/execdesc.h"
#include "nodes/params.h"
#include "tcop/dest.h" #include "tcop/dest.h"
#include "utils/guc.h" #include "utils/guc.h"
...@@ -55,8 +56,9 @@ extern List *pg_parse_query(const char *query_string); ...@@ -55,8 +56,9 @@ extern List *pg_parse_query(const char *query_string);
extern List *pg_analyze_and_rewrite(Node *parsetree, extern List *pg_analyze_and_rewrite(Node *parsetree,
Oid *paramTypes, int numParams); Oid *paramTypes, int numParams);
extern List *pg_rewrite_queries(List *querytree_list); extern List *pg_rewrite_queries(List *querytree_list);
extern Plan *pg_plan_query(Query *querytree); extern Plan *pg_plan_query(Query *querytree, ParamListInfo boundParams);
extern List *pg_plan_queries(List *querytrees, bool needSnapshot); extern List *pg_plan_queries(List *querytrees, ParamListInfo boundParams,
bool needSnapshot);
extern bool assign_max_stack_depth(int newval, bool doit, GucSource source); extern bool assign_max_stack_depth(int newval, bool doit, GucSource source);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment