diff --git a/src/backend/commands/extension.c b/src/backend/commands/extension.c index 59ca5cd5a9..18dd22691c 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 = CurrentMemoryContext, + plancontext = NULL; /* Be sure parser can see any DDL done so far */ CommandCounterIncrement(); + /* + * If there are more queries to run, use a temporary child context + * that will be reset after executing this query. + */ + if (lnext(lc1) != NULL) + { + plancontext = AllocSetContextCreate(CurrentMemoryContext, + "statement planning context", + ALLOCSET_DEFAULT_SIZES); + MemoryContextSwitchTo(plancontext); + } + stmt_list = pg_analyze_and_rewrite(parsetree, sql, NULL, @@ -730,6 +744,10 @@ execute_sql_string(const char *sql) NULL); stmt_list = pg_plan_queries(stmt_list, CURSOR_OPT_PARALLEL_OK, NULL); + /* Switch context for execution. */ + if (plancontext) + MemoryContextSwitchTo(oldcontext); + foreach(lc2, stmt_list) { PlannedStmt *stmt = lfirst_node(PlannedStmt, lc2); @@ -772,6 +790,13 @@ execute_sql_string(const char *sql) PopActiveSnapshot(); } + + /* + * Delete the planning context unless this is the last statement, in + * which case, deleting the parent context will get the job done. + */ + if (plancontext) + MemoryContextDelete(plancontext); } /* Be sure to advance the command counter after the last script command */ diff --git a/src/backend/tcop/postgres.c b/src/backend/tcop/postgres.c index 44a59e1d4f..67b46bff8a 100644 --- a/src/backend/tcop/postgres.c +++ b/src/backend/tcop/postgres.c @@ -1075,6 +1075,7 @@ exec_simple_query(const char *query_string) Portal portal; DestReceiver *receiver; int16 format; + MemoryContext plancontext = NULL; /* * Get the command name for use in status display (it also becomes the @@ -1132,10 +1133,22 @@ 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 query and plan trees + * (again, these must outlive the execution context). Normally, it's + * MessageContext, but if there are more queries to plan, we use a + * temporary child context that will be reset after executing this + * query. We avoid that overhead of setting up a separate context + * for the common case of having just a single query. */ - oldcontext = MemoryContextSwitchTo(MessageContext); + if (lnext(parsetree_item) != NULL) + { + plancontext = AllocSetContextCreate(MessageContext, + "statement planning context", + ALLOCSET_DEFAULT_SIZES); + oldcontext = MemoryContextSwitchTo(plancontext); + } + else + oldcontext = MemoryContextSwitchTo(MessageContext); querytree_list = pg_analyze_and_rewrite(parsetree, query_string, NULL, 0, NULL); @@ -1143,6 +1156,10 @@ exec_simple_query(const char *query_string) plantree_list = pg_plan_queries(querytree_list, CURSOR_OPT_PARALLEL_OK, NULL); + /* Switch to MessageContext for creating the portal. */ + if (plancontext) + MemoryContextSwitchTo(MessageContext); + /* Done with the snapshot used for parsing/planning */ if (snapshot_set) PopActiveSnapshot(); @@ -1263,6 +1280,10 @@ exec_simple_query(const char *query_string) * aborted by error will not send an EndCommand report at all.) */ EndCommand(completionTag, dest); + + /* Delete the planning context if one was created. */ + if (plancontext) + MemoryContextDelete(plancontext); } /* end loop over parsetrees */ /*