diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 59ca5cd5a9..7a5feda2d9 100644 --- a/src/backend/commands/extension.c +++ b/src/backend/commands/extension.c @@ -719,10 +719,24 @@ execute_sql_string(const char *sql) RawStmt *parsetree = lfirst_node(RawStmt, lc1); List *stmt_list; ListCell *lc2; + MemoryContext oldcontext, + stmtcontext; /* Be sure parser can see any DDL done so far */ CommandCounterIncrement(); + /* + * OK to analyze, rewrite, and plan this raw statement. + * + * Switch to a temporary context before constructing query and plan + * trees. Memory allocated during this construction will be released + * before executing the generated plan(s). + */ + stmtcontext = AllocSetContextCreate(CurrentMemoryContext, + "statement parse/plan context", + ALLOCSET_DEFAULT_SIZES); + oldcontext = MemoryContextSwitchTo(stmtcontext); + stmt_list = pg_analyze_and_rewrite(parsetree, sql, NULL, @@ -730,6 +744,14 @@ execute_sql_string(const char *sql) NULL); stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL); + /* + * Copy the plan trees into the longer-lived context and delete the + * temporary context used to generate them. + */ + MemoryContextSwitchTo(oldcontext); + stmt_list = copyObject(stmt_list); + MemoryContextDelete(stmtcontext); + foreach(lc2, stmt_list) { PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2); diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 44a59e1d4f..207a9d6488 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 a temporary context before constructing query and plan + * trees. Memory allocated during this construction will be released + * before executing the generated plan(s). */ - 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();