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.55 2002/09/04 20:31:26 momjian 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"
26 /* ----------------------------------------------------------------
28 * ----------------------------------------------------------------
31 CreateQueryDesc(Query *parsetree,
34 const char *portalName)
36 QueryDesc *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
38 qd->operation = parsetree->commandType; /* operation */
39 qd->parsetree = parsetree; /* parse tree */
40 qd->plantree = plantree; /* plan */
41 qd->dest = dest; /* output dest */
42 qd->portalName = portalName; /* name, if dest is a portal */
43 qd->tupDesc = NULL; /* until set by ExecutorStart */
48 /* ----------------------------------------------------------------
51 * Note: this may someday take parameters -cim 9/18/89
52 * ----------------------------------------------------------------
55 CreateExecutorState(void)
60 * create a new executor state
62 state = makeNode(EState);
65 * initialize the Executor State structure
67 state->es_direction = ForwardScanDirection;
68 state->es_range_table = NIL;
70 state->es_result_relations = NULL;
71 state->es_num_result_relations = 0;
72 state->es_result_relation_info = NULL;
74 state->es_junkFilter = NULL;
76 state->es_into_relation_descriptor = NULL;
78 state->es_param_list_info = NULL;
79 state->es_param_exec_vals = NULL;
81 state->es_tupleTable = NULL;
83 state->es_query_cxt = CurrentMemoryContext;
85 state->es_per_tuple_exprcontext = NULL;
88 * return the executor state structure
98 PreparePortal(char *portalName)
103 * Check for already-in-use portal name.
105 portal = GetPortalByName(portalName);
106 if (PortalIsValid(portal))
109 * XXX Should we raise an error rather than closing the old
112 elog(WARNING, "Closing pre-existing portal \"%s\"",
118 * Create the new portal.
120 portal = CreatePortal(portalName);
130 * parsetree: the query tree
131 * plan: the plan tree for the query
132 * dest: where to send results
133 * completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
134 * in which to store a command completion status string.
136 * completionTag may be NULL if caller doesn't want a status string.
139 ProcessQuery(Query *parsetree,
144 int operation = parsetree->commandType;
145 bool isRetrieveIntoPortal = false;
146 char *intoName = NULL;
147 Portal portal = NULL;
148 MemoryContext oldContext = NULL;
149 QueryDesc *queryDesc;
154 * Check for special-case destinations
156 if (operation == CMD_SELECT)
158 if (parsetree->isPortal)
160 isRetrieveIntoPortal = true;
161 /* If binary portal, switch to alternate output format */
162 if (dest == Remote && parsetree->isBinary)
163 dest = RemoteInternal;
165 else if (parsetree->into != NULL)
168 * SELECT INTO table (a/k/a CREATE AS ... SELECT).
170 * Override the normal communication destination; execMain.c
171 * special-cases this case. (Perhaps would be cleaner to have
172 * an additional destination type?)
179 * If retrieving into a portal, set up the portal and copy the
180 * parsetree and plan into its memory context.
182 if (isRetrieveIntoPortal)
184 intoName = parsetree->into->relname;
185 portal = PreparePortal(intoName);
186 oldContext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
187 parsetree = copyObject(parsetree);
188 plan = copyObject(plan);
189 intoName = parsetree->into->relname; /* use copied name in
193 * We stay in portal's memory context for now, so that query desc,
194 * EState, and plan startup info are also allocated in the portal
200 * Now we can create the QueryDesc object.
202 queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
205 * create a default executor state.
207 state = CreateExecutorState();
210 * call ExecStart to prepare the plan for execution
212 attinfo = ExecutorStart(queryDesc, state);
215 * If retrieve into portal, stop now; we do not run the plan until a
216 * FETCH command is received.
218 if (isRetrieveIntoPortal)
220 PortalSetQuery(portal,
226 /* Now we can return to caller's memory context. */
227 MemoryContextSwitchTo(oldContext);
229 /* Set completion tag. SQL calls this operation DECLARE CURSOR */
231 strcpy(completionTag, "DECLARE CURSOR");
237 * Now we get to the important call to ExecutorRun() where we actually
240 ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
243 * Build command completion status string, if caller wants one.
252 strcpy(completionTag, "SELECT");
255 if (state->es_processed == 1)
256 lastOid = state->es_lastoid;
258 lastOid = InvalidOid;
259 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
260 "INSERT %u %u", lastOid, state->es_processed);
263 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
264 "UPDATE %u", state->es_processed);
267 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
268 "DELETE %u", state->es_processed);
271 strcpy(completionTag, "???");
277 * Now, we close down all the scans and free allocated resources.
279 ExecutorEnd(queryDesc, state);