diff options
| author | Tom Lane | 2003-05-02 20:54:36 +0000 |
|---|---|---|
| committer | Tom Lane | 2003-05-02 20:54:36 +0000 |
| commit | de28dc9a04c4df5d711815b7a518501b43535a26 (patch) | |
| tree | 1b93363ece14ded804195ff4a1c754a9b4a32306 /src/backend/commands/prepare.c | |
| parent | 1940434f1ef8475c8b59bb8ff03e3f3a10cac6ae (diff) | |
Portal and memory management infrastructure for extended query protocol.
Both plannable queries and utility commands are now always executed
within Portals, which have been revamped so that they can handle the
load (they used to be good only for single SELECT queries). Restructure
code to push command-completion-tag selection logic out of postgres.c,
so that it won't have to be duplicated between simple and extended queries.
initdb forced due to addition of a field to Query nodes.
Diffstat (limited to 'src/backend/commands/prepare.c')
| -rw-r--r-- | src/backend/commands/prepare.c | 113 |
1 files changed, 56 insertions, 57 deletions
diff --git a/src/backend/commands/prepare.c b/src/backend/commands/prepare.c index f6cd5d0a802..5a3e3f589d1 100644 --- a/src/backend/commands/prepare.c +++ b/src/backend/commands/prepare.c @@ -6,7 +6,7 @@ * Copyright (c) 2002, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.13 2003/02/02 23:46:38 tgl Exp $ + * $Header: /cvsroot/pgsql/src/backend/commands/prepare.c,v 1.14 2003/05/02 20:54:33 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -59,9 +59,8 @@ static ParamListInfo EvaluateParams(EState *estate, void PrepareQuery(PrepareStmt *stmt) { - List *plan_list = NIL; List *query_list, - *query_list_item; + *plan_list; if (!stmt->name) elog(ERROR, "No statement name given"); @@ -69,19 +68,18 @@ PrepareQuery(PrepareStmt *stmt) if (stmt->query->commandType == CMD_UTILITY) elog(ERROR, "Utility statements cannot be prepared"); + /* + * Parse analysis is already done, but we must still rewrite and plan + * the query. + */ + /* Rewrite the query. The result could be 0, 1, or many queries. */ query_list = QueryRewrite(stmt->query); - foreach(query_list_item, query_list) - { - Query *query = (Query *) lfirst(query_list_item); - Plan *plan; - - plan = pg_plan_query(query); - - plan_list = lappend(plan_list, plan); - } + /* Generate plans for queries. Snapshot is already set. */ + plan_list = pg_plan_queries(query_list, false); + /* Save the results. */ StoreQuery(stmt->name, query_list, plan_list, stmt->argtype_oids); } @@ -92,17 +90,19 @@ void ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest) { QueryHashEntry *entry; - List *l, - *query_list, + List *query_list, *plan_list; + MemoryContext qcontext; ParamListInfo paramLI = NULL; EState *estate = NULL; + Portal portal; /* Look it up in the hash table */ entry = FetchQuery(stmt->name); query_list = entry->query_list; plan_list = entry->plan_list; + qcontext = entry->context; Assert(length(query_list) == length(plan_list)); @@ -117,57 +117,53 @@ ExecuteQuery(ExecuteStmt *stmt, CommandDest outputDest) paramLI = EvaluateParams(estate, stmt->params, entry->argtype_list); } - /* Execute each query */ - foreach(l, query_list) - { - Query *query = (Query *) lfirst(l); - Plan *plan = (Plan *) lfirst(plan_list); - bool is_last_query; - - plan_list = lnext(plan_list); - is_last_query = (plan_list == NIL); - - if (query->commandType == CMD_UTILITY) - ProcessUtility(query->utilityStmt, outputDest, NULL); - else - { - QueryDesc *qdesc; - - if (log_executor_stats) - ResetUsage(); + /* + * Create a new portal to run the query in + */ + portal = CreateNewPortal(); - qdesc = CreateQueryDesc(query, plan, outputDest, NULL, - paramLI, false); + /* + * For EXECUTE INTO, make a copy of the stored query so that we can + * modify its destination (yech, but INTO has always been ugly). + * For regular EXECUTE we can just use the stored query where it sits, + * since the executor is read-only. + */ + if (stmt->into) + { + MemoryContext oldContext; + Query *query; - if (stmt->into) - { - if (qdesc->operation != CMD_SELECT) - elog(ERROR, "INTO clause specified for non-SELECT query"); + oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal)); - query->into = stmt->into; - qdesc->dest = None; - } + query_list = copyObject(query_list); + plan_list = copyObject(plan_list); + qcontext = PortalGetHeapMemory(portal); - ExecutorStart(qdesc); + if (length(query_list) != 1) + elog(ERROR, "INTO clause specified for non-SELECT query"); + query = (Query *) lfirst(query_list); + if (query->commandType != CMD_SELECT) + elog(ERROR, "INTO clause specified for non-SELECT query"); + query->into = copyObject(stmt->into); - ExecutorRun(qdesc, ForwardScanDirection, 0L); + MemoryContextSwitchTo(oldContext); + } - ExecutorEnd(qdesc); + PortalDefineQuery(portal, + NULL, /* XXX fixme: can we save query text? */ + NULL, /* no command tag known either */ + query_list, + plan_list, + qcontext); - FreeQueryDesc(qdesc); + /* + * Run the portal to completion. + */ + PortalStart(portal, paramLI); - if (log_executor_stats) - ShowUsage("EXECUTOR STATISTICS"); - } + (void) PortalRun(portal, FETCH_ALL, outputDest, outputDest, NULL); - /* - * If we're processing multiple queries, we need to increment the - * command counter between them. For the last query, there's no - * need to do this, it's done automatically. - */ - if (!is_last_query) - CommandCounterIncrement(); - } + PortalDrop(portal, false); if (estate) FreeExecutorState(estate); @@ -377,8 +373,11 @@ DeallocateQuery(DeallocateStmt *stmt) /* Find the query's hash table entry */ entry = FetchQuery(stmt->name); - /* Flush the context holding the subsidiary data */ + /* Drop any open portals that depend on this prepared statement */ Assert(MemoryContextIsValid(entry->context)); + DropDependentPortals(entry->context); + + /* Flush the context holding the subsidiary data */ MemoryContextDelete(entry->context); /* Now we can remove the hash table entry */ |
