1 /*-------------------------------------------------------------------------
4 * POSTGRES process query command code
6 * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
7 * Portions Copyright (c) 1994, Regents of the University of California
11 * $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.57 2002/12/05 15:50:35 tgl Exp $
13 *-------------------------------------------------------------------------
18 #include "commands/portalcmds.h"
19 #include "executor/execdefs.h"
20 #include "executor/executor.h"
21 #include "tcop/pquery.h"
22 #include "utils/memutils.h"
23 #include "utils/ps_status.h"
30 CreateQueryDesc(Query *parsetree,
33 const char *portalName,
37 QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
39 qd->operation = parsetree->commandType; /* operation */
40 qd->parsetree = parsetree; /* parse tree */
41 qd->plantree = plantree; /* plan */
42 qd->dest = dest; /* output dest */
43 qd->portalName = portalName; /* name, if dest is a portal */
44 qd->params = params; /* parameter values passed into query */
45 qd->doInstrument = doInstrument; /* instrumentation wanted? */
47 /* null these fields until set by ExecutorStart */
60 PreparePortal(char *portalName)
65 * Check for already-in-use portal name.
67 portal = GetPortalByName(portalName);
68 if (PortalIsValid(portal))
71 * XXX Should we raise an error rather than closing the old
74 elog(WARNING, "Closing pre-existing portal \"%s\"",
80 * Create the new portal.
82 portal = CreatePortal(portalName);
92 * parsetree: the query tree
93 * plan: the plan tree for the query
94 * dest: where to send results
95 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
96 * in which to store a command completion status string.
98 * completionTag may be NULL if caller doesn't want a status string.
101 ProcessQuery(Query *parsetree,
106 int operation = parsetree->commandType;
107 bool isRetrieveIntoPortal = false;
108 char *intoName = NULL;
109 Portal portal = NULL;
110 MemoryContext oldContext = NULL;
111 QueryDesc *queryDesc;
114 * Check for special-case destinations
116 if (operation == CMD_SELECT)
118 if (parsetree->isPortal)
120 isRetrieveIntoPortal = true;
121 /* If binary portal, switch to alternate output format */
122 if (dest == Remote && parsetree->isBinary)
123 dest = RemoteInternal;
124 /* Check for invalid context (must be in transaction block) */
125 RequireTransactionChain((void *) parsetree, "DECLARE CURSOR");
127 else if (parsetree->into != NULL)
130 * SELECT INTO table (a/k/a CREATE AS ... SELECT).
132 * Override the normal communication destination; execMain.c
133 * special-cases this case. (Perhaps would be cleaner to have
134 * an additional destination type?)
141 * If retrieving into a portal, set up the portal and copy the
142 * parsetree and plan into its memory context.
144 if (isRetrieveIntoPortal)
146 intoName = parsetree->into->relname;
147 portal = PreparePortal(intoName);
148 oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
149 parsetree = copyObject(parsetree);
150 plan = copyObject(plan);
151 intoName = parsetree->into->relname; /* use copied name in
155 * We stay in portal's memory context for now, so that query desc,
156 * exec state, and plan startup info are also allocated in the portal
162 * Now we can create the QueryDesc object.
164 queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName, NULL, false);
167 * call ExecStart to prepare the plan for execution
169 ExecutorStart(queryDesc);
172 * If retrieve into portal, stop now; we do not run the plan until a
173 * FETCH command is received.
175 if (isRetrieveIntoPortal)
177 /* Arrange to shut down the executor if portal is dropped */
178 PortalSetQuery(portal, queryDesc, PortalCleanup);
180 /* Now we can return to caller's memory context. */
181 MemoryContextSwitchTo(oldContext);
183 /* Set completion tag. SQL calls this operation DECLARE CURSOR */
185 strcpy(completionTag, "DECLARE CURSOR");
191 * Now we get to the important call to ExecutorRun() where we actually
194 ExecutorRun(queryDesc, ForwardScanDirection, 0L);
197 * Build command completion status string, if caller wants one.
206 strcpy(completionTag, "SELECT");
209 if (queryDesc->estate->es_processed == 1)
210 lastOid = queryDesc->estate->es_lastoid;
212 lastOid = InvalidOid;
213 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
214 "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
217 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
218 "UPDATE %u", queryDesc->estate->es_processed);
221 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
222 "DELETE %u", queryDesc->estate->es_processed);
225 strcpy(completionTag, "???");
231 * Now, we close down all the scans and free allocated resources.
233 ExecutorEnd(queryDesc);