]> granicus.if.org Git - postgresql/blob - src/backend/tcop/pquery.c
Revise command completion tags as per hackers message on 20 March.
[postgresql] / src / backend / tcop / pquery.c
1 /*-------------------------------------------------------------------------
2  *
3  * pquery.c
4  *        POSTGRES process query command code
5  *
6  * Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
7  * Portions Copyright (c) 1994, Regents of the University of California
8  *
9  *
10  * IDENTIFICATION
11  *        $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.53 2002/05/18 15:44:48 petere Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
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"
24
25
26 /* ----------------------------------------------------------------
27  *              CreateQueryDesc
28  * ----------------------------------------------------------------
29  */
30 QueryDesc *
31 CreateQueryDesc(Query *parsetree,
32                                 Plan *plantree,
33                                 CommandDest dest,
34                                 const char *portalName)
35 {
36         QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
37
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 */
44
45         return qd;
46 }
47
48 /* ----------------------------------------------------------------
49  *              CreateExecutorState
50  *
51  *              Note: this may someday take parameters -cim 9/18/89
52  * ----------------------------------------------------------------
53  */
54 EState *
55 CreateExecutorState(void)
56 {
57         EState     *state;
58
59         /*
60          * create a new executor state
61          */
62         state = makeNode(EState);
63
64         /*
65          * initialize the Executor State structure
66          */
67         state->es_direction = ForwardScanDirection;
68         state->es_range_table = NIL;
69
70         state->es_result_relations = NULL;
71         state->es_num_result_relations = 0;
72         state->es_result_relation_info = NULL;
73
74         state->es_junkFilter = NULL;
75
76         state->es_into_relation_descriptor = NULL;
77
78         state->es_param_list_info = NULL;
79         state->es_param_exec_vals = NULL;
80
81         state->es_tupleTable = NULL;
82
83         state->es_query_cxt = CurrentMemoryContext;
84
85         state->es_per_tuple_exprcontext = NULL;
86
87         /*
88          * return the executor state structure
89          */
90         return state;
91 }
92
93 /* ----------------
94  *              PreparePortal
95  * ----------------
96  */
97 Portal
98 PreparePortal(char *portalName)
99 {
100         Portal          portal;
101
102         /*
103          * Check for already-in-use portal name.
104          */
105         portal = GetPortalByName(portalName);
106         if (PortalIsValid(portal))
107         {
108                 /*
109                  * XXX Should we raise an error rather than closing the old
110                  * portal?
111                  */
112                 elog(WARNING, "Closing pre-existing portal \"%s\"",
113                          portalName);
114                 PortalDrop(portal);
115         }
116
117         /*
118          * Create the new portal.
119          */
120         portal = CreatePortal(portalName);
121
122         return portal;
123 }
124
125
126 /*
127  * ProcessQuery
128  *              Execute a query
129  *
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.
135  *
136  * completionTag may be NULL if caller doesn't want a status string.
137  */
138 void
139 ProcessQuery(Query *parsetree,
140                          Plan *plan,
141                          CommandDest dest,
142                          char *completionTag)
143 {
144         int                     operation = parsetree->commandType;
145         bool            isRetrieveIntoPortal = false;
146         char       *intoName = NULL;
147         Portal          portal = NULL;
148         MemoryContext oldContext = NULL;
149         QueryDesc  *queryDesc;
150         EState     *state;
151         TupleDesc       attinfo;
152
153         /*
154          * Check for special-case destinations
155          */
156         if (operation == CMD_SELECT)
157         {
158                 if (parsetree->isPortal)
159                 {
160                         isRetrieveIntoPortal = true;
161                         /* If binary portal, switch to alternate output format */
162                         if (dest == Remote && parsetree->isBinary)
163                                 dest = RemoteInternal;
164                 }
165                 else if (parsetree->into != NULL)
166                 {
167                         /*
168                          * SELECT INTO table (a/k/a CREATE AS ... SELECT).
169                          *
170                          * Override the normal communication destination; execMain.c
171                          * special-cases this case.  (Perhaps would be cleaner to
172                          * have an additional destination type?)
173                          */
174                         dest = None;
175                 }
176         }
177
178         /*
179          * If retrieving into a portal, set up the portal and copy the
180          * parsetree and plan into its memory context.
181          */
182         if (isRetrieveIntoPortal)
183         {
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 QueryDesc */
190
191                 /*
192                  * We stay in portal's memory context for now, so that query desc,
193                  * EState, and plan startup info are also allocated in the portal
194                  * context.
195                  */
196         }
197
198         /*
199          * Now we can create the QueryDesc object.
200          */
201         queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
202
203         /*
204          * create a default executor state.
205          */
206         state = CreateExecutorState();
207
208         /*
209          * call ExecStart to prepare the plan for execution
210          */
211         attinfo = ExecutorStart(queryDesc, state);
212
213         /*
214          * If retrieve into portal, stop now; we do not run the plan until a
215          * FETCH command is received.
216          */
217         if (isRetrieveIntoPortal)
218         {
219                 PortalSetQuery(portal,
220                                            queryDesc,
221                                            attinfo,
222                                            state,
223                                            PortalCleanup);
224
225                 /* Now we can return to caller's memory context. */
226                 MemoryContextSwitchTo(oldContext);
227
228                 /* Set completion tag.  SQL calls this operation DECLARE CURSOR */
229                 if (completionTag)
230                         strcpy(completionTag, "DECLARE CURSOR");
231
232                 return;
233         }
234
235         /*
236          * Now we get to the important call to ExecutorRun() where we actually
237          * run the plan..
238          */
239         ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
240
241         /*
242          * Build command completion status string, if caller wants one.
243          */
244         if (completionTag)
245         {
246                 Oid             lastOid;
247
248                 switch (operation)
249                 {
250                         case CMD_SELECT:
251                                 strcpy(completionTag, "SELECT");
252                                 break;
253                         case CMD_INSERT:
254                                 if (state->es_processed == 1)
255                                         lastOid = state->es_lastoid;
256                                 else
257                                         lastOid = InvalidOid;
258                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
259                                                  "INSERT %u %u", lastOid, state->es_processed);
260                                 break;
261                         case CMD_UPDATE:
262                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
263                                                  "UPDATE %u", state->es_processed);
264                                 break;
265                         case CMD_DELETE:
266                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
267                                                  "DELETE %u", state->es_processed);
268                                 break;
269                         default:
270                                 strcpy(completionTag, "???");
271                                 break;
272                 }
273         }
274
275         /*
276          * Now, we close down all the scans and free allocated resources.
277          */
278         ExecutorEnd(queryDesc, state);
279 }