aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/explain.c4
-rw-r--r--src/backend/commands/portalcmds.c4
-rw-r--r--src/backend/commands/prepare.c3
-rw-r--r--src/backend/executor/functions.c3
-rw-r--r--src/backend/executor/spi.c4
-rw-r--r--src/backend/optimizer/util/clauses.c80
-rw-r--r--src/backend/tcop/postgres.c50
-rw-r--r--src/include/nodes/params.h9
-rw-r--r--src/pl/plpgsql/src/pl_exec.c3
9 files changed, 112 insertions, 48 deletions
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 5787aa413e7..48db000ea9b 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994-5, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.150 2006/08/02 01:59:45 joe Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/explain.c,v 1.151 2006/09/06 20:40:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -191,7 +191,7 @@ ExplainOneQuery(Query *query, ExplainStmt *stmt, ParamListInfo params,
}
/* plan the query */
- plan = planner(query, isCursor, cursorOptions, NULL);
+ plan = planner(query, isCursor, cursorOptions, params);
/*
* Update snapshot command ID to ensure this query sees results of any
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 00ad5444ca0..e418fabfc51 100644
--- a/src/backend/commands/portalcmds.c
+++ b/src/backend/commands/portalcmds.c
@@ -14,7 +14,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.53 2006/09/03 03:19:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.54 2006/09/06 20:40:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -95,7 +95,7 @@ PerformCursorOpen(DeclareCursorStmt *stmt, ParamListInfo params)
errmsg("DECLARE CURSOR ... FOR UPDATE/SHARE is not supported"),
errdetail("Cursors must be READ ONLY.")));
- plan = planner(query, true, stmt->options, NULL);
+ plan = planner(query, true, stmt->options, params);
/*
* Create a portal and copy the query and plan into its memory context.
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 04445cd33ef..dc264306719 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2006, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.62 2006/08/29 02:11:29 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.63 2006/09/06 20:40:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -261,6 +261,7 @@ EvaluateParams(EState *estate, List *params, List *argtypes)
ParamExternData *prm = &paramLI->params[i];
prm->ptype = lfirst_oid(la);
+ prm->pflags = 0;
prm->value = ExecEvalExprSwitchContext(n,
GetPerTupleExprContext(estate),
&prm->isnull,
diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c
index 28462ba8b8b..e2e56543839 100644
--- a/src/backend/executor/functions.c
+++ b/src/backend/executor/functions.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.105 2006/08/12 20:05:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/functions.c,v 1.106 2006/09/06 20:40:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -442,6 +442,7 @@ postquel_sub_params(SQLFunctionCachePtr fcache,
prm->value = fcinfo->arg[i];
prm->isnull = fcinfo->argnull[i];
+ prm->pflags = 0;
prm->ptype = fcache->argtypes[i];
}
}
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index e6fcae7f0b6..dc3ab9e7c32 100644
--- a/src/backend/executor/spi.c
+++ b/src/backend/executor/spi.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.161 2006/09/03 03:19:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.162 2006/09/06 20:40:47 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -893,6 +893,7 @@ SPI_cursor_open(const char *name, void *plan,
ParamExternData *prm = &paramLI->params[k];
prm->ptype = spiplan->argtypes[k];
+ prm->pflags = 0;
prm->isnull = (Nulls && Nulls[k] == 'n');
if (prm->isnull)
{
@@ -1357,6 +1358,7 @@ _SPI_execute_plan(_SPI_plan *plan, Datum *Values, const char *Nulls,
prm->value = Values[k];
prm->isnull = (Nulls && Nulls[k] == 'n');
+ prm->pflags = 0;
prm->ptype = plan->argtypes[k];
}
}
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 71e727a7b4c..48b125a774c 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.219 2006/08/12 20:05:55 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.220 2006/09/06 20:40:47 tgl Exp $
*
* HISTORY
* AUTHOR DATE MAJOR EVENT
@@ -1462,7 +1462,9 @@ eval_const_expressions(Node *node)
*
* Currently the extra steps that are taken in this mode are:
* 1. Substitute values for Params, where a bound Param value has been made
- * available by the caller of planner().
+ * available by the caller of planner(), even if the Param isn't marked
+ * constant. This effectively means that we plan using the first supplied
+ * value of the Param.
* 2. Fold stable, as well as immutable, functions to constants.
*--------------------
*/
@@ -1487,33 +1489,38 @@ eval_const_expressions_mutator(Node *node,
{
Param *param = (Param *) node;
- /* OK to try to substitute value? */
- if (context->estimate && param->paramkind == PARAM_EXTERN &&
- PlannerBoundParamList != NULL)
+ /* Look to see if we've been given a value for this Param */
+ if (param->paramkind == PARAM_EXTERN &&
+ PlannerBoundParamList != NULL &&
+ param->paramid > 0 &&
+ param->paramid <= PlannerBoundParamList->numParams)
{
- /* Look to see if we've been given a value for this Param */
- if (param->paramid > 0 &&
- param->paramid <= PlannerBoundParamList->numParams)
- {
- ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
+ ParamExternData *prm = &PlannerBoundParamList->params[param->paramid - 1];
- if (OidIsValid(prm->ptype))
+ if (OidIsValid(prm->ptype))
+ {
+ /* OK to substitute parameter value? */
+ if (context->estimate || (prm->pflags & PARAM_FLAG_CONST))
{
/*
- * 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().
+ * Return a Const representing the param value. Must copy
+ * pass-by-ref datatypes, since the Param might be in a
+ * memory context shorter-lived than our output plan
+ * should be.
*/
int16 typLen;
bool typByVal;
+ Datum pval;
Assert(prm->ptype == param->paramtype);
get_typlenbyval(param->paramtype, &typLen, &typByVal);
+ if (prm->isnull || typByVal)
+ pval = prm->value;
+ else
+ pval = datumCopy(prm->value, typByVal, typLen);
return (Node *) makeConst(param->paramtype,
(int) typLen,
- prm->value,
+ pval,
prm->isnull,
typByVal);
}
@@ -3016,10 +3023,9 @@ evaluate_expr(Expr *expr, Oid result_type)
* stage. In particular, it handles List nodes since a cnf-ified qual clause
* will have List structure at the top level, and it handles TargetEntry nodes
* so that a scan of a target list can be handled without additional code.
- * (But only the "expr" part of a TargetEntry is examined, unless the walker
- * chooses to process TargetEntry nodes specially.) Also, RangeTblRef,
- * FromExpr, JoinExpr, and SetOperationStmt nodes are handled, so that query
- * jointrees and setOperation trees can be processed without additional code.
+ * Also, RangeTblRef, FromExpr, JoinExpr, and SetOperationStmt nodes are
+ * handled, so that query jointrees and setOperation trees can be processed
+ * without additional code.
*
* expression_tree_walker will handle SubLink nodes by recursing normally
* into the "testexpr" subtree (which is an expression belonging to the outer
@@ -3364,6 +3370,38 @@ query_tree_walker(Query *query,
return true;
if (range_table_walker(query->rtable, walker, context, flags))
return true;
+ if (query->utilityStmt)
+ {
+ /*
+ * Certain utility commands contain general-purpose Querys embedded
+ * in them --- if this is one, invoke the walker on the sub-Query.
+ */
+ if (IsA(query->utilityStmt, CopyStmt))
+ {
+ if (walker(((CopyStmt *) query->utilityStmt)->query, context))
+ return true;
+ }
+ if (IsA(query->utilityStmt, DeclareCursorStmt))
+ {
+ if (walker(((DeclareCursorStmt *) query->utilityStmt)->query, context))
+ return true;
+ }
+ if (IsA(query->utilityStmt, ExplainStmt))
+ {
+ if (walker(((ExplainStmt *) query->utilityStmt)->query, context))
+ return true;
+ }
+ if (IsA(query->utilityStmt, PrepareStmt))
+ {
+ if (walker(((PrepareStmt *) query->utilityStmt)->query, context))
+ return true;
+ }
+ if (IsA(query->utilityStmt, ViewStmt))
+ {
+ if (walker(((ViewStmt *) query->utilityStmt)->query, context))
+ return true;
+ }
+ }
return false;
}
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 6496b981cf2..2e128ece137 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.505 2006/09/03 03:19:44 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.506 2006/09/06 20:40:48 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -1168,7 +1168,7 @@ exec_parse_message(const char *query_string, /* string to execute */
* statement, we assume the statement isn't going to hang around long, so
* getting rid of temp space quickly is probably not worth the costs of
* copying parse/plan trees. So in this case, we set up a special context
- * for the unnamed statement, and do all the parsing/planning therein.
+ * for the unnamed statement, and do all the parsing work therein.
*/
is_named = (stmt_name[0] != '\0');
if (is_named)
@@ -1367,6 +1367,7 @@ exec_bind_message(StringInfo input_message)
PreparedStatement *pstmt;
Portal portal;
ParamListInfo params;
+ List *plan_list;
StringInfoData bind_values_str;
pgstat_report_activity("<BIND>");
@@ -1474,6 +1475,7 @@ exec_bind_message(StringInfo input_message)
{
Oid ptype = lfirst_oid(l);
int32 plength;
+ Datum pval;
bool isNull;
StringInfoData pbuf;
char csave;
@@ -1532,11 +1534,7 @@ exec_bind_message(StringInfo input_message)
else
pstring = pg_client_to_server(pbuf.data, plength);
- params->params[paramno].value =
- OidInputFunctionCall(typinput,
- pstring,
- typioparam,
- -1);
+ pval = OidInputFunctionCall(typinput, pstring, typioparam, -1);
/* Save the parameter values */
appendStringInfo(&bind_values_str, "%s$%d = ",
@@ -1576,10 +1574,7 @@ exec_bind_message(StringInfo input_message)
else
bufptr = &pbuf;
- params->params[paramno].value = OidReceiveFunctionCall(typreceive,
- bufptr,
- typioparam,
- -1);
+ pval = OidReceiveFunctionCall(typreceive, bufptr, typioparam, -1);
/* Trouble if it didn't eat the whole buffer */
if (!isNull && pbuf.cursor != pbuf.len)
@@ -1596,13 +1591,22 @@ exec_bind_message(StringInfo input_message)
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("unsupported format code: %d",
pformat)));
+ pval = 0; /* keep compiler quiet */
}
/* Restore message buffer contents */
if (!isNull)
pbuf.data[plength] = csave;
+ params->params[paramno].value = pval;
params->params[paramno].isnull = isNull;
+ /*
+ * We mark the params as CONST. This has no effect if we already
+ * did planning, but if we didn't, it licenses the planner to
+ * substitute the parameters directly into the one-shot plan we
+ * will generate below.
+ */
+ params->params[paramno].pflags = PARAM_FLAG_CONST;
params->params[paramno].ptype = ptype;
paramno++;
@@ -1641,19 +1645,29 @@ exec_bind_message(StringInfo input_message)
/*
* 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.
+ * to make use of the concrete parameter values we now have. Because we
+ * use PARAM_FLAG_CONST, the plan is good only for this set of param
+ * values, and so we generate the plan in the portal's own memory context
+ * where it will be thrown away after use. As in exec_parse_message,
+ * we make no attempt to recover planner temporary memory until the end
+ * of the operation.
*
- * This happens only for unnamed statements, and so switching into the
- * statement context for planning is correct (see notes in
- * exec_parse_message).
+ * XXX because the planner has a bad habit of scribbling on its input,
+ * we have to make a copy of the parse trees, just in case someone binds
+ * and executes an unnamed statement multiple times. FIXME someday
*/
if (pstmt->plan_list == NIL && pstmt->query_list != NIL)
{
- MemoryContext oldContext = MemoryContextSwitchTo(pstmt->context);
+ MemoryContext oldContext;
- pstmt->plan_list = pg_plan_queries(pstmt->query_list, params, true);
+ oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+ plan_list = pg_plan_queries(copyObject(pstmt->query_list),
+ params,
+ true);
MemoryContextSwitchTo(oldContext);
}
+ else
+ plan_list = pstmt->plan_list;
/*
* Define portal and start execution.
@@ -1664,7 +1678,7 @@ exec_bind_message(StringInfo input_message)
bind_values_str.len ? pstrdup(bind_values_str.data) : NULL,
pstmt->commandTag,
pstmt->query_list,
- pstmt->plan_list,
+ plan_list,
pstmt->context);
PortalStart(portal, params, InvalidSnapshot);
diff --git a/src/include/nodes/params.h b/src/include/nodes/params.h
index 13eb25876dd..3a93d75f301 100644
--- a/src/include/nodes/params.h
+++ b/src/include/nodes/params.h
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1996-2006, PostgreSQL Global Development Group
* Portions Copyright (c) 1994, Regents of the University of California
*
- * $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.31 2006/04/22 01:26:01 tgl Exp $
+ * $PostgreSQL: pgsql/src/include/nodes/params.h,v 1.32 2006/09/06 20:40:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -26,15 +26,22 @@
* Although parameter numbers are normally consecutive, we allow
* ptype == InvalidOid to signal an unused array entry.
*
+ * PARAM_FLAG_CONST signals the planner that it may treat this parameter
+ * as a constant (i.e., generate a plan that works only for this value
+ * of the parameter).
+ *
* Although the data structure is really an array, not a list, we keep
* the old typedef name to avoid unnecessary code changes.
* ----------------
*/
+#define PARAM_FLAG_CONST 0x0001 /* parameter is constant */
+
typedef struct ParamExternData
{
Datum value; /* parameter value */
bool isnull; /* is it NULL? */
+ uint16 pflags; /* flag bits, see above */
Oid ptype; /* parameter's datatype, or 0 */
} ParamExternData;
diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c
index dedba151178..7b350caf155 100644
--- a/src/pl/plpgsql/src/pl_exec.c
+++ b/src/pl/plpgsql/src/pl_exec.c
@@ -8,7 +8,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.177 2006/08/27 23:47:58 tgl Exp $
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.178 2006/09/06 20:40:48 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -3958,6 +3958,7 @@ exec_eval_simple_expr(PLpgSQL_execstate *estate,
ParamExternData *prm = &paramLI->params[i];
PLpgSQL_datum *datum = estate->datums[expr->params[i]];
+ prm->pflags = 0;
exec_eval_datum(estate, datum, expr->plan_argtypes[i],
&prm->ptype,
&prm->value, &prm->isnull);