]> granicus.if.org Git - postgresql/blob - src/backend/tcop/pquery.c
Phase 1 of read-only-plans project: cause executor state nodes to point
[postgresql] / 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.57 2002/12/05 15:50:35 tgl 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 QueryDesc *
30 CreateQueryDesc(Query *parsetree,
31                                 Plan *plantree,
32                                 CommandDest dest,
33                                 const char *portalName,
34                                 ParamListInfo params,
35                                 bool doInstrument)
36 {
37         QueryDesc  *qd = (QueryDesc *) palloc(sizeof(QueryDesc));
38
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? */
46
47         /* null these fields until set by ExecutorStart */
48         qd->tupDesc = NULL;
49         qd->estate = NULL;
50         qd->planstate = NULL;
51
52         return qd;
53 }
54
55 /* ----------------
56  *              PreparePortal
57  * ----------------
58  */
59 Portal
60 PreparePortal(char *portalName)
61 {
62         Portal          portal;
63
64         /*
65          * Check for already-in-use portal name.
66          */
67         portal = GetPortalByName(portalName);
68         if (PortalIsValid(portal))
69         {
70                 /*
71                  * XXX Should we raise an error rather than closing the old
72                  * portal?
73                  */
74                 elog(WARNING, "Closing pre-existing portal \"%s\"",
75                          portalName);
76                 PortalDrop(portal);
77         }
78
79         /*
80          * Create the new portal.
81          */
82         portal = CreatePortal(portalName);
83
84         return portal;
85 }
86
87
88 /*
89  * ProcessQuery
90  *              Execute a query
91  *
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.
97  *
98  * completionTag may be NULL if caller doesn't want a status string.
99  */
100 void
101 ProcessQuery(Query *parsetree,
102                          Plan *plan,
103                          CommandDest dest,
104                          char *completionTag)
105 {
106         int                     operation = parsetree->commandType;
107         bool            isRetrieveIntoPortal = false;
108         char       *intoName = NULL;
109         Portal          portal = NULL;
110         MemoryContext oldContext = NULL;
111         QueryDesc  *queryDesc;
112
113         /*
114          * Check for special-case destinations
115          */
116         if (operation == CMD_SELECT)
117         {
118                 if (parsetree->isPortal)
119                 {
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");
126                 }
127                 else if (parsetree->into != NULL)
128                 {
129                         /*
130                          * SELECT INTO table (a/k/a CREATE AS ... SELECT).
131                          *
132                          * Override the normal communication destination; execMain.c
133                          * special-cases this case.  (Perhaps would be cleaner to have
134                          * an additional destination type?)
135                          */
136                         dest = None;
137                 }
138         }
139
140         /*
141          * If retrieving into a portal, set up the portal and copy the
142          * parsetree and plan into its memory context.
143          */
144         if (isRetrieveIntoPortal)
145         {
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
152                                                                                                  * QueryDesc */
153
154                 /*
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
157                  * context.
158                  */
159         }
160
161         /*
162          * Now we can create the QueryDesc object.
163          */
164         queryDesc = CreateQueryDesc(parsetree, plan, dest, intoName, NULL, false);
165
166         /*
167          * call ExecStart to prepare the plan for execution
168          */
169         ExecutorStart(queryDesc);
170
171         /*
172          * If retrieve into portal, stop now; we do not run the plan until a
173          * FETCH command is received.
174          */
175         if (isRetrieveIntoPortal)
176         {
177                 /* Arrange to shut down the executor if portal is dropped */
178                 PortalSetQuery(portal, queryDesc, PortalCleanup);
179
180                 /* Now we can return to caller's memory context. */
181                 MemoryContextSwitchTo(oldContext);
182
183                 /* Set completion tag.  SQL calls this operation DECLARE CURSOR */
184                 if (completionTag)
185                         strcpy(completionTag, "DECLARE CURSOR");
186
187                 return;
188         }
189
190         /*
191          * Now we get to the important call to ExecutorRun() where we actually
192          * run the plan..
193          */
194         ExecutorRun(queryDesc, ForwardScanDirection, 0L);
195
196         /*
197          * Build command completion status string, if caller wants one.
198          */
199         if (completionTag)
200         {
201                 Oid                     lastOid;
202
203                 switch (operation)
204                 {
205                         case CMD_SELECT:
206                                 strcpy(completionTag, "SELECT");
207                                 break;
208                         case CMD_INSERT:
209                                 if (queryDesc->estate->es_processed == 1)
210                                         lastOid = queryDesc->estate->es_lastoid;
211                                 else
212                                         lastOid = InvalidOid;
213                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
214                                                  "INSERT %u %u", lastOid, queryDesc->estate->es_processed);
215                                 break;
216                         case CMD_UPDATE:
217                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
218                                                  "UPDATE %u", queryDesc->estate->es_processed);
219                                 break;
220                         case CMD_DELETE:
221                                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE,
222                                                  "DELETE %u", queryDesc->estate->es_processed);
223                                 break;
224                         default:
225                                 strcpy(completionTag, "???");
226                                 break;
227                 }
228         }
229
230         /*
231          * Now, we close down all the scans and free allocated resources.
232          */
233         ExecutorEnd(queryDesc);
234 }