OSDN Git Service

pgindent run.
[pg-rex/syncrep.git] / src / backend / tcop / pquery.c
1 /*-------------------------------------------------------------------------
2  *
3  * pquery.c
4  *        POSTGRES process query command code
5  *
6  * Portions Copyright (c) 1996-2002, 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.55 2002/09/04 20:31:26 momjian 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 have
172                          * 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
190                                                                                                  * QueryDesc */
191
192                 /*
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
195                  * context.
196                  */
197         }
198
199         /*
200          * Now we can create the QueryDesc object.
201          */
202         queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName);
203
204         /*
205          * create a default executor state.
206          */
207         state = CreateExecutorState();
208
209         /*
210          * call ExecStart to prepare the plan for execution
211          */
212         attinfo = ExecutorStart(queryDesc, state);
213
214         /*
215          * If retrieve into portal, stop now; we do not run the plan until a
216          * FETCH command is received.
217          */
218         if (isRetrieveIntoPortal)
219         {
220                 PortalSetQuery(portal,
221                                            queryDesc,
222                                            attinfo,
223                                            state,
224                                            PortalCleanup);
225
226                 /* Now we can return to caller's memory context. */
227                 MemoryContextSwitchTo(oldContext);
228
229                 /* Set completion tag.  SQL calls this operation DECLARE CURSOR */
230                 if (completionTag)
231                         strcpy(completionTag, "DECLARE CURSOR");
232
233                 return;
234         }
235
236         /*
237          * Now we get to the important call to ExecutorRun() where we actually
238          * run the plan..
239          */
240         ExecutorRun(queryDesc, state, ForwardScanDirection, 0L);
241
242         /*
243          * Build command completion status string, if caller wants one.
244          */
245         if (completionTag)
246         {
247                 Oid                     lastOid;
248
249                 switch (operation)
250                 {
251                         case CMD_SELECT:
252                                 strcpy(completionTag, "SELECT");
253                                 break;
254                         case CMD_INSERT:
255                                 if (state->es_processed == 1)
256                                         lastOid = state->es_lastoid;
257                                 else
258                                         lastOid = InvalidOid;
259                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
260                                                  "INSERT %u %u", lastOid, state->es_processed);
261                                 break;
262                         case CMD_UPDATE:
263                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
264                                                  "UPDATE %u", state->es_processed);
265                                 break;
266                         case CMD_DELETE:
267                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
268                                                  "DELETE %u", state->es_processed);
269                                 break;
270                         default:
271                                 strcpy(completionTag, "???");
272                                 break;
273                 }
274         }
275
276         /*
277          * Now, we close down all the scans and free allocated resources.
278          */
279         ExecutorEnd(queryDesc, state);
280 }