foreach(lc1, raw_parsetree_list)
{
RawStmt *parsetree = lfirst_node(RawStmt, lc1);
+ MemoryContext per_parsetree_context,
+ oldcontext;
List *stmt_list;
ListCell *lc2;
+ /*
+ * We do the work for each parsetree in a short-lived context, to
+ * limit the memory used when there are many commands in the string.
+ */
+ per_parsetree_context =
+ AllocSetContextCreate(CurrentMemoryContext,
+ "execute_sql_string per-statement context",
+ ALLOCSET_DEFAULT_SIZES);
+ oldcontext = MemoryContextSwitchTo(per_parsetree_context);
+
/* Be sure parser can see any DDL done so far */
CommandCounterIncrement();
PopActiveSnapshot();
}
+
+ /* Clean up per-parsetree context. */
+ MemoryContextSwitchTo(oldcontext);
+ MemoryContextDelete(per_parsetree_context);
}
/* Be sure to advance the command counter after the last script command */
bool snapshot_set = false;
const char *commandTag;
char completionTag[COMPLETION_TAG_BUFSIZE];
+ MemoryContext per_parsetree_context = NULL;
List *querytree_list,
*plantree_list;
Portal portal;
/*
* OK to analyze, rewrite, and plan this query.
*
- * Switch to appropriate context for constructing querytrees (again,
- * these must outlive the execution context).
+ * Switch to appropriate context for constructing query and plan trees
+ * (these can't be in the transaction context, as that will get reset
+ * when the command is COMMIT/ROLLBACK). If we have multiple
+ * parsetrees, we use a separate context for each one, so that we can
+ * free that memory before moving on to the next one. But for the
+ * last (or only) parsetree, just use MessageContext, which will be
+ * reset shortly after completion anyway. In event of an error, the
+ * per_parsetree_context will be deleted when MessageContext is reset.
*/
- oldcontext = MemoryContextSwitchTo(MessageContext);
+ if (lnext(parsetree_item) != NULL)
+ {
+ per_parsetree_context =
+ AllocSetContextCreate(MessageContext,
+ "per-parsetree message context",
+ ALLOCSET_DEFAULT_SIZES);
+ oldcontext = MemoryContextSwitchTo(per_parsetree_context);
+ }
+ else
+ oldcontext = MemoryContextSwitchTo(MessageContext);
querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0, NULL);
/*
* We don't have to copy anything into the portal, because everything
- * we are passing here is in MessageContext, which will outlive the
- * portal anyway.
+ * we are passing here is in MessageContext or the
+ * per_parsetree_context, and so will outlive the portal anyway.
*/
PortalDefineQuery(portal,
NULL,
* aborted by error will not send an EndCommand report at all.)
*/
EndCommand(completionTag, dest);
+
+ /* Now we may drop the per-parsetree context, if one was created. */
+ if (per_parsetree_context)
+ MemoryContextDelete(per_parsetree_context);
} /* end loop over parsetrees */
/*