aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/backend/commands/portalcmds.c5
-rw-r--r--src/backend/commands/prepare.c8
-rw-r--r--src/backend/executor/spi.c22
-rw-r--r--src/backend/tcop/postgres.c42
-rw-r--r--src/backend/utils/mmgr/portalmem.c20
5 files changed, 73 insertions, 24 deletions
diff --git a/src/backend/commands/portalcmds.c b/src/backend/commands/portalcmds.c
index 64d0492b83e..83998233b49 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.72 2008/03/26 18:48:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/portalcmds.c,v 1.73 2008/04/02 18:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -77,6 +77,9 @@ PerformCursorOpen(PlannedStmt *stmt, ParamListInfo params,
stmt = copyObject(stmt);
stmt->utilityStmt = NULL; /* make it look like plain SELECT */
+ if (queryString) /* copy the source text too for safety */
+ queryString = pstrdup(queryString);
+
PortalDefineQuery(portal,
NULL,
queryString,
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c
index 681647fac56..575dad9fb3f 100644
--- a/src/backend/commands/prepare.c
+++ b/src/backend/commands/prepare.c
@@ -10,7 +10,7 @@
* Copyright (c) 2002-2008, PostgreSQL Global Development Group
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.84 2008/03/26 18:48:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/prepare.c,v 1.85 2008/04/02 18:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -250,9 +250,13 @@ ExecuteQuery(ExecuteStmt *stmt, const char *queryString,
plan_list = cplan->stmt_list;
}
+ /*
+ * Note: we don't bother to copy the source query string into the portal.
+ * Any errors it might be useful for will already have been reported.
+ */
PortalDefineQuery(portal,
NULL,
- entry->plansource->query_string,
+ NULL,
entry->plansource->commandTag,
plan_list,
cplan);
diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c
index 42187fe43ad..f7d41373b4a 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.192 2008/04/01 03:09:30 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/executor/spi.c,v 1.193 2008/04/02 18:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -918,6 +918,7 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
CachedPlanSource *plansource;
CachedPlan *cplan;
List *stmt_list;
+ char *query_string;
ParamListInfo paramLI;
Snapshot snapshot;
MemoryContext oldcontext;
@@ -968,10 +969,22 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
portal = CreatePortal(name, false, false);
}
+ /*
+ * Prepare to copy stuff into the portal's memory context. We do all this
+ * copying first, because it could possibly fail (out-of-memory) and we
+ * don't want a failure to occur between RevalidateCachedPlan and
+ * PortalDefineQuery; that would result in leaking our plancache refcount.
+ */
+ oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+
+ /* Copy the plan's query string, if available, into the portal */
+ query_string = plansource->query_string;
+ if (query_string)
+ query_string = pstrdup(query_string);
+
/* If the plan has parameters, copy them into the portal */
if (plan->nargs > 0)
{
- oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
/* sizeof(ParamListInfoData) includes the first array element */
paramLI = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(plan->nargs - 1) *sizeof(ParamExternData));
@@ -1000,11 +1013,12 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
paramTypByVal, paramTypLen);
}
}
- MemoryContextSwitchTo(oldcontext);
}
else
paramLI = NULL;
+ MemoryContextSwitchTo(oldcontext);
+
if (plan->saved)
{
/* Replan if needed, and increment plan refcount for portal */
@@ -1025,7 +1039,7 @@ SPI_cursor_open(const char *name, SPIPlanPtr plan,
*/
PortalDefineQuery(portal,
NULL, /* no statement name */
- plansource->query_string,
+ query_string,
plansource->commandTag,
stmt_list,
cplan);
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 95bea2ef8a9..d44e69fb10a 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.547 2008/03/26 18:48:59 alvherre Exp $
+ * $PostgreSQL: pgsql/src/backend/tcop/postgres.c,v 1.548 2008/04/02 18:31:50 tgl Exp $
*
* NOTES
* this is the "main" module of the postgres backend and
@@ -933,6 +933,11 @@ exec_simple_query(const char *query_string)
/* Don't display the portal in pg_cursors */
portal->visible = false;
+ /*
+ * We don't have to copy anything into the portal, because everything
+ * we are passsing here is in MessageContext, which will outlive the
+ * portal anyway.
+ */
PortalDefineQuery(portal,
NULL,
query_string,
@@ -1356,8 +1361,11 @@ exec_bind_message(StringInfo input_message)
CachedPlanSource *psrc;
CachedPlan *cplan;
Portal portal;
+ char *query_string;
+ char *saved_stmt_name;
ParamListInfo params;
List *plan_list;
+ MemoryContext oldContext;
bool save_log_statement_stats = log_statement_stats;
char msec_str[32];
@@ -1462,15 +1470,31 @@ exec_bind_message(StringInfo input_message)
portal = CreatePortal(portal_name, false, false);
/*
+ * Prepare to copy stuff into the portal's memory context. We do all this
+ * copying first, because it could possibly fail (out-of-memory) and we
+ * don't want a failure to occur between RevalidateCachedPlan and
+ * PortalDefineQuery; that would result in leaking our plancache refcount.
+ */
+ oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
+
+ /* Copy the plan's query string, if available, into the portal */
+ query_string = psrc->query_string;
+ if (query_string)
+ query_string = pstrdup(query_string);
+
+ /* Likewise make a copy of the statement name, unless it's unnamed */
+ if (stmt_name[0])
+ saved_stmt_name = pstrdup(stmt_name);
+ else
+ saved_stmt_name = NULL;
+
+ /*
* Fetch parameters, if any, and store in the portal's memory context.
*/
if (numParams > 0)
{
- MemoryContext oldContext;
int paramno;
- oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
-
/* sizeof(ParamListInfoData) includes the first array element */
params = (ParamListInfo) palloc(sizeof(ParamListInfoData) +
(numParams - 1) *sizeof(ParamExternData));
@@ -1595,12 +1619,13 @@ exec_bind_message(StringInfo input_message)
params->params[paramno].pflags = PARAM_FLAG_CONST;
params->params[paramno].ptype = ptype;
}
-
- MemoryContextSwitchTo(oldContext);
}
else
params = NULL;
+ /* Done storing stuff in portal's context */
+ MemoryContextSwitchTo(oldContext);
+
/* Get the result format codes */
numRFormats = pq_getmsgint(input_message, 2);
if (numRFormats > 0)
@@ -1627,7 +1652,6 @@ exec_bind_message(StringInfo input_message)
}
else
{
- MemoryContext oldContext;
List *query_list;
/*
@@ -1665,8 +1689,8 @@ exec_bind_message(StringInfo input_message)
* Define portal and start execution.
*/
PortalDefineQuery(portal,
- stmt_name[0] ? stmt_name : NULL,
- psrc->query_string,
+ saved_stmt_name,
+ query_string,
psrc->commandTag,
plan_list,
cplan);
diff --git a/src/backend/utils/mmgr/portalmem.c b/src/backend/utils/mmgr/portalmem.c
index 4940f7721f6..88bad32e29e 100644
--- a/src/backend/utils/mmgr/portalmem.c
+++ b/src/backend/utils/mmgr/portalmem.c
@@ -12,7 +12,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.108 2008/03/25 22:42:45 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.109 2008/04/02 18:31:50 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -274,9 +274,7 @@ CreateNewPortal(void)
*
* Notes: commandTag shall be NULL if and only if the original query string
* (before rewriting) was an empty string. Also, the passed commandTag must
- * be a pointer to a constant string, since it is not copied. However,
- * prepStmtName and sourceText, if provided, are copied into the portal's
- * heap context for safekeeping.
+ * be a pointer to a constant string, since it is not copied.
*
* If cplan is provided, then it is a cached plan containing the stmts,
* and the caller must have done RevalidateCachedPlan(), causing a refcount
@@ -285,6 +283,14 @@ CreateNewPortal(void)
* If cplan is NULL, then it is the caller's responsibility to ensure that
* the passed plan trees have adequate lifetime. Typically this is done by
* copying them into the portal's heap context.
+ *
+ * The caller is also responsible for ensuring that the passed prepStmtName
+ * and sourceText (if not NULL) have adequate lifetime.
+ *
+ * NB: this function mustn't do much beyond storing the passed values; in
+ * particular don't do anything that risks elog(ERROR). If that were to
+ * happen here before storing the cplan reference, we'd leak the plancache
+ * refcount that the caller is trying to hand off to us.
*/
void
PortalDefineQuery(Portal portal,
@@ -299,10 +305,8 @@ PortalDefineQuery(Portal portal,
Assert(commandTag != NULL || stmts == NIL);
- portal->prepStmtName = prepStmtName ?
- MemoryContextStrdup(PortalGetHeapMemory(portal), prepStmtName) : NULL;
- portal->sourceText = sourceText ?
- MemoryContextStrdup(PortalGetHeapMemory(portal), sourceText) : NULL;
+ portal->prepStmtName = prepStmtName;
+ portal->sourceText = sourceText;
portal->commandTag = commandTag;
portal->stmts = stmts;
portal->cplan = cplan;