OSDN Git Service

pgindent run.
[pg-rex/syncrep.git] / src / backend / commands / portalcmds.c
1 /*-------------------------------------------------------------------------
2  *
3  * portalcmds.c
4  *        portal support 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/commands/portalcmds.c,v 1.3 2002/09/04 20:31:15 momjian Exp $
12  *
13  *-------------------------------------------------------------------------
14  */
15
16 #include "postgres.h"
17
18 #include "commands/portalcmds.h"
19 #include "executor/executor.h"
20
21
22 /*
23  * PortalCleanup
24  */
25 void
26 PortalCleanup(Portal portal)
27 {
28         MemoryContext oldcontext;
29
30         /*
31          * sanity checks
32          */
33         AssertArg(PortalIsValid(portal));
34         AssertArg(portal->cleanup == PortalCleanup);
35
36         /*
37          * set proper portal-executor context before calling ExecMain.
38          */
39         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
40
41         /*
42          * tell the executor to shutdown the query
43          */
44         ExecutorEnd(PortalGetQueryDesc(portal), PortalGetState(portal));
45
46         /*
47          * switch back to previous context
48          */
49         MemoryContextSwitchTo(oldcontext);
50 }
51
52
53 /*
54  * PerformPortalFetch
55  *
56  *      name: name of portal
57  *      forward: forward or backward fetch?
58  *      count: # of tuples to fetch (0 implies all)
59  *      dest: where to send results
60  *      completionTag: points to a buffer of size COMPLETION_TAG_BUFSIZE
61  *              in which to store a command completion status string.
62  *
63  * completionTag may be NULL if caller doesn't want a status string.
64  */
65 void
66 PerformPortalFetch(char *name,
67                                    bool forward,
68                                    int count,
69                                    CommandDest dest,
70                                    char *completionTag)
71 {
72         Portal          portal;
73         QueryDesc  *queryDesc;
74         EState     *estate;
75         MemoryContext oldcontext;
76         ScanDirection direction;
77         bool            temp_desc = false;
78
79         /* initialize completion status in case of early exit */
80         if (completionTag)
81                 strcpy(completionTag, (dest == None) ? "MOVE 0" : "FETCH 0");
82
83         /*
84          * sanity checks
85          */
86         if (name == NULL)
87         {
88                 elog(WARNING, "PerformPortalFetch: missing portal name");
89                 return;
90         }
91
92         /*
93          * get the portal from the portal name
94          */
95         portal = GetPortalByName(name);
96         if (!PortalIsValid(portal))
97         {
98                 elog(WARNING, "PerformPortalFetch: portal \"%s\" not found",
99                          name);
100                 return;
101         }
102
103         /*
104          * switch into the portal context
105          */
106         oldcontext = MemoryContextSwitchTo(PortalGetHeapMemory(portal));
107
108         queryDesc = PortalGetQueryDesc(portal);
109         estate = PortalGetState(portal);
110
111         /*
112          * If the requested destination is not the same as the query's
113          * original destination, make a temporary QueryDesc with the proper
114          * destination.  This supports MOVE, for example, which will pass in
115          * dest = None.
116          *
117          * EXCEPTION: if the query's original dest is RemoteInternal (ie, it's a
118          * binary cursor) and the request is Remote, we do NOT override the
119          * original dest.  This is necessary since a FETCH command will pass
120          * dest = Remote, not knowing whether the cursor is binary or not.
121          */
122         if (dest != queryDesc->dest &&
123                 !(queryDesc->dest == RemoteInternal && dest == Remote))
124         {
125                 QueryDesc  *qdesc = (QueryDesc *) palloc(sizeof(QueryDesc));
126
127                 memcpy(qdesc, queryDesc, sizeof(QueryDesc));
128                 qdesc->dest = dest;
129                 queryDesc = qdesc;
130                 temp_desc = true;
131         }
132
133         /*
134          * Determine which direction to go in, and check to see if we're
135          * already at the end of the available tuples in that direction.  If
136          * so, set the direction to NoMovement to avoid trying to fetch any
137          * tuples.      (This check exists because not all plan node types are
138          * robust about being called again if they've already returned NULL
139          * once.)  Then call the executor (we must not skip this, because the
140          * destination needs to see a setup and shutdown even if no tuples are
141          * available).  Finally, update the atStart/atEnd state depending on
142          * the number of tuples that were retrieved.
143          */
144         if (forward)
145         {
146                 if (portal->atEnd)
147                         direction = NoMovementScanDirection;
148                 else
149                         direction = ForwardScanDirection;
150
151                 ExecutorRun(queryDesc, estate, direction, (long) count);
152
153                 if (estate->es_processed > 0)
154                         portal->atStart = false;        /* OK to back up now */
155                 if (count <= 0 || (int) estate->es_processed < count)
156                         portal->atEnd = true;           /* we retrieved 'em all */
157         }
158         else
159         {
160                 if (portal->atStart)
161                         direction = NoMovementScanDirection;
162                 else
163                         direction = BackwardScanDirection;
164
165                 ExecutorRun(queryDesc, estate, direction, (long) count);
166
167                 if (estate->es_processed > 0)
168                         portal->atEnd = false;          /* OK to go forward now */
169                 if (count <= 0 || (int) estate->es_processed < count)
170                         portal->atStart = true;         /* we retrieved 'em all */
171         }
172
173         /* Return command status if wanted */
174         if (completionTag)
175                 snprintf(completionTag, COMPLETION_TAG_BUFSIZE, "%s %u",
176                                  (dest == None) ? "MOVE" : "FETCH",
177                                  estate->es_processed);
178
179         /*
180          * Clean up and switch back to old context.
181          */
182         if (temp_desc)
183                 pfree(queryDesc);
184
185         MemoryContextSwitchTo(oldcontext);
186 }
187
188 /*
189  * PerformPortalClose
190  */
191 void
192 PerformPortalClose(char *name, CommandDest dest)
193 {
194         Portal          portal;
195
196         /*
197          * sanity checks
198          */
199         if (name == NULL)
200         {
201                 elog(WARNING, "PerformPortalClose: missing portal name");
202                 return;
203         }
204
205         /*
206          * get the portal from the portal name
207          */
208         portal = GetPortalByName(name);
209         if (!PortalIsValid(portal))
210         {
211                 elog(WARNING, "PerformPortalClose: portal \"%s\" not found",
212                          name);
213                 return;
214         }
215
216         /*
217          * Note: PortalCleanup is called as a side-effect
218          */
219         PortalDrop(portal);
220 }