aboutsummaryrefslogtreecommitdiff
path: root/src/backend/executor
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-04-02 18:31:50 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-04-02 18:31:50 +0000
commit1591fcbec77f6544a0f665758bae912c68e6fa42 (patch)
tree164febe5a5dac789fc6194235312c15c3ce4e1fe /src/backend/executor
parentad6bf716baa7c4c1d0c2fbece0344046e3ce1173 (diff)
downloadpostgresql-1591fcbec77f6544a0f665758bae912c68e6fa42.tar.gz
postgresql-1591fcbec77f6544a0f665758bae912c68e6fa42.zip
Revert my bad decision of about a year ago to make PortalDefineQuery
responsible for copying the query string into the new Portal. Such copying is unnecessary in the common code path through exec_simple_query, and in this case it can be enormously expensive because the string might contain a large number of individual commands; we were copying the entire, long string for each command, resulting in O(N^2) behavior for N commands. (This is the cause of bug #4079.) A second problem with it is that PortalDefineQuery really can't risk error, because if it elog's before having set up the Portal, we will leak the plancache refcount that the caller is trying to hand off to the portal. So go back to the design in which the caller is responsible for making sure everything is copied into the portal if necessary.
Diffstat (limited to 'src/backend/executor')
-rw-r--r--src/backend/executor/spi.c22
1 files changed, 18 insertions, 4 deletions
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);