On 2019/05/24 23:28, Tom Lane wrote:
> So my thought, if we want to do something about this, is not "find
> some things we can pfree at the end of planning" but "find a way
> to use a separate context for each statement in the query string".
> Maybe multi-query strings could be handled by setting up a child
> context of MessageContext (after we've done the raw parsing there
> and determined that indeed there are multiple queries), running
> parse analysis and planning in that context, and resetting that
> context after each query.
Maybe like the attached? I'm not sure if we need to likewise be concerned
about exec_sql_string() being handed multi-query strings.
Thanks,
Amit
diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c
index 44a59e1d4f..0165f794b0 100644
--- a/src/backend/tcop/postgres.c
+++ b/src/backend/tcop/postgres.c
@@ -984,7 +984,8 @@ static void
exec_simple_query(const char *query_string)
{
CommandDest dest = whereToSendOutput;
- MemoryContext oldcontext;
+ MemoryContext oldcontext,
+ stmtcontext;
List *parsetree_list;
ListCell *parsetree_item;
bool save_log_statement_stats = log_statement_stats;
@@ -1132,10 +1133,14 @@ exec_simple_query(const char *query_string)
/*
* 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 querytrees.
+ * Memory allocated during this construction is released before
+ * the generated plan is executed.
*/
- oldcontext = MemoryContextSwitchTo(MessageContext);
+ stmtcontext = AllocSetContextCreate(MessageContext,
+
"statement parse/plan context",
+
ALLOCSET_DEFAULT_SIZES);
+ oldcontext = MemoryContextSwitchTo(stmtcontext);
querytree_list = pg_analyze_and_rewrite(parsetree, query_string,
NULL, 0, NULL);
@@ -1143,6 +1148,14 @@ exec_simple_query(const char *query_string)
plantree_list = pg_plan_queries(querytree_list,
CURSOR_OPT_PARALLEL_OK, NULL);
+ /*
+ * Copy the plan trees into the longer-lived MessageContext and
delete
+ * the temporary context used to generate them.
+ */
+ MemoryContextSwitchTo(MessageContext);
+ plantree_list = copyObject(plantree_list);
+ MemoryContextDelete(stmtcontext);
+
/* Done with the snapshot used for parsing/planning */
if (snapshot_set)
PopActiveSnapshot();