Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit778a21c

Browse files
committed
Tweak portal (cursor) code so that it will not call the executor again
when user does another FETCH after reaching end of data, or anotherFETCH backwards after reaching start. This is needed because some plannodes are not very robust about being called again after they've alreadyreturned NULL; for example, MergeJoin will crash in some states but notothers. While the ideal approach would be for them all to handle thiscorrectly, it seems foolish to assume that no such bugs would creep inagain once cleaned up. Therefore, the most robust answer is to preventthe situation from arising at all.
1 parentf5ea88a commit778a21c

File tree

4 files changed

+77
-108
lines changed

4 files changed

+77
-108
lines changed

‎src/backend/commands/command.c

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.121 2001/02/14 21:35:00 tgl Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/commands/Attic/command.c,v 1.122 2001/02/27 22:07:34 tgl Exp $
1212
*
1313
* NOTES
1414
* The PerformAddAttribute() code, like most of the relation
@@ -107,8 +107,8 @@ PerformPortalFetch(char *name,
107107
CommandDestdest)
108108
{
109109
Portalportal;
110-
intfeature;
111110
QueryDesc*queryDesc;
111+
EState*estate;
112112
MemoryContextoldcontext;
113113

114114
/* ----------------
@@ -140,19 +140,14 @@ PerformPortalFetch(char *name,
140140
oldcontext=MemoryContextSwitchTo(PortalGetHeapMemory(portal));
141141

142142
/* ----------------
143-
*setup "feature" to tell the executor which direction to go in.
144-
* ----------------
145-
*/
146-
if (forward)
147-
feature=EXEC_FOR;
148-
else
149-
feature=EXEC_BACK;
150-
151-
/* ----------------
152-
*tell the destination to prepare to receive some tuples
143+
*tell the destination to prepare to receive some tuples.
144+
*
145+
*If we've been asked for a MOVE, make a temporary QueryDesc
146+
*with the appropriate dummy destination.
153147
* ----------------
154148
*/
155149
queryDesc=PortalGetQueryDesc(portal);
150+
estate=PortalGetState(portal);
156151

157152
if (dest==None)/* MOVE */
158153
{
@@ -165,7 +160,7 @@ PerformPortalFetch(char *name,
165160

166161
BeginCommand(name,
167162
queryDesc->operation,
168-
portal->attinfo,/* QueryDescGetTypeInfo(queryDesc) */
163+
PortalGetTupleDesc(portal),
169164
false,/* portal fetches don't end up in
170165
* relations */
171166
false,/* this is a portal fetch, not a "retrieve
@@ -174,18 +169,45 @@ PerformPortalFetch(char *name,
174169
dest);
175170

176171
/* ----------------
177-
*execute the portal fetch operation
172+
*Determine which direction to go in, and check to see if we're already
173+
*at the end of the available tuples in that direction. If so, do
174+
*nothing. (This check exists because not all plan node types are
175+
*robust about being called again if they've already returned NULL
176+
*once.) If it's OK to do the fetch, call the executor. Then,
177+
*update the atStart/atEnd state depending on the number of tuples
178+
*that were retrieved.
178179
* ----------------
179180
*/
180-
ExecutorRun(queryDesc,PortalGetState(portal),feature, (long)count);
181-
182-
if (dest==None)/* MOVE */
183-
pfree(queryDesc);
181+
if (forward)
182+
{
183+
if (!portal->atEnd)
184+
{
185+
ExecutorRun(queryDesc,estate,EXEC_FOR, (long)count);
186+
if (estate->es_processed>0)
187+
portal->atStart= false;/* OK to back up now */
188+
if (count <=0|| (int)estate->es_processed<count)
189+
portal->atEnd= true;/* we retrieved 'em all */
190+
}
191+
}
192+
else
193+
{
194+
if (!portal->atStart)
195+
{
196+
ExecutorRun(queryDesc,estate,EXEC_BACK, (long)count);
197+
if (estate->es_processed>0)
198+
portal->atEnd= false;/* OK to go forward now */
199+
if (count <=0|| (int)estate->es_processed<count)
200+
portal->atStart= true;/* we retrieved 'em all */
201+
}
202+
}
184203

185204
/* ----------------
186-
* Switch back to old context.
205+
*Clean up and switch back to old context.
187206
* ----------------
188207
*/
208+
if (dest==None)/* MOVE */
209+
pfree(queryDesc);
210+
189211
MemoryContextSwitchTo(oldcontext);
190212

191213
/* ----------------

‎src/backend/tcop/pquery.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.41 2001/01/24 19:43:09 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/tcop/pquery.c,v 1.42 2001/02/27 22:07:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
@@ -248,7 +248,7 @@ ProcessQuery(Query *parsetree,
248248
* ----------------
249249
*/
250250
if (isRetrieveIntoRelation)
251-
queryDesc->dest=(int)None;
251+
queryDesc->dest=None;
252252

253253
/* ----------------
254254
*create a default executor state.

‎src/backend/utils/mmgr/portalmem.c

Lines changed: 11 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -8,44 +8,26 @@
88
*
99
*
1010
* IDENTIFICATION
11-
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.39 2001/01/24 19:43:17 momjian Exp $
11+
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.40 2001/02/27 22:07:34 tgl Exp $
1212
*
1313
*-------------------------------------------------------------------------
1414
*/
1515
/*
1616
* NOTES
17-
*Do not confuse "Portal" with "PortalEntry" (or "PortalBuffer").
18-
*When a PQexec() routine is run, the resulting tuples
19-
*find their way into a "PortalEntry". The contents of the resulting
20-
*"PortalEntry" can then be inspected by other PQxxx functions.
17+
*A "Portal" is a structure used to keep track of cursor queries.
2118
*
22-
*A "Portal" is a structure used to keep track of queries of the
23-
*form:
24-
*retrieve portal FOO ( blah... ) where blah...
25-
*
26-
*When the backend sees a "retrieve portal" query, it allocates
27-
*a "PortalD" structure, plans the query and then stores the query
19+
*When the backend sees a "declare cursor" query, it allocates a
20+
*"PortalData" structure, plans the query and then stores the query
2821
*in the portal without executing it. Later, when the backend
2922
*sees a
30-
*fetch 1 into FOO
31-
*
23+
*fetch 1 from FOO
3224
*the system looks up the portal named "FOO" in the portal table,
3325
*gets the planned query and then calls the executor with a feature of
3426
*'(EXEC_FOR 1). The executor then runs the query and returns a single
3527
*tuple.The problem is that we have to hold onto the state of the
36-
*portal query until we see a "close p".This means we have to be
28+
*portal query until we see a "close".This means we have to be
3729
*careful about memory management.
3830
*
39-
*Having said all that, here is what a PortalD currently looks like:
40-
*
41-
* struct PortalD {
42-
*char*name;
43-
*classObj(MemoryContext)heap;
44-
*ListqueryDesc;
45-
*EStatestate;
46-
*void(*cleanup) ARGS((Portal portal));
47-
* };
48-
*
4931
*I hope this makes things clearer to whoever reads this -cim 2/22/91
5032
*/
5133

@@ -188,43 +170,13 @@ PortalSetQuery(Portal portal,
188170
AssertArg(IsA((Node*)state,EState));
189171

190172
portal->queryDesc=queryDesc;
191-
portal->state=state;
192173
portal->attinfo=attinfo;
174+
portal->state=state;
175+
portal->atStart= true;/* Allow fetch forward only */
176+
portal->atEnd= false;
193177
portal->cleanup=cleanup;
194178
}
195179

196-
/*
197-
* PortalGetQueryDesc
198-
*Returns query attached to portal.
199-
*
200-
* Exceptions:
201-
*BadState if called when disabled.
202-
*BadArg if portal is invalid.
203-
*/
204-
QueryDesc*
205-
PortalGetQueryDesc(Portalportal)
206-
{
207-
AssertArg(PortalIsValid(portal));
208-
209-
returnportal->queryDesc;
210-
}
211-
212-
/*
213-
* PortalGetState
214-
*Returns state attached to portal.
215-
*
216-
* Exceptions:
217-
*BadState if called when disabled.
218-
*BadArg if portal is invalid.
219-
*/
220-
EState*
221-
PortalGetState(Portalportal)
222-
{
223-
AssertArg(PortalIsValid(portal));
224-
225-
returnportal->state;
226-
}
227-
228180
/*
229181
* CreatePortal
230182
*Returns a new portal given a name.
@@ -265,7 +217,8 @@ CreatePortal(char *name)
265217
portal->queryDesc=NULL;
266218
portal->attinfo=NULL;
267219
portal->state=NULL;
268-
220+
portal->atStart= true;/* disallow fetches until query is set */
221+
portal->atEnd= true;
269222
portal->cleanup=NULL;
270223

271224
/* put portal in table */
@@ -315,13 +268,3 @@ AtEOXact_portals(void)
315268
{
316269
HashTableWalk(PortalHashTable, (HashtFunc)PortalDrop,0);
317270
}
318-
319-
/*
320-
* PortalGetHeapMemory
321-
*Returns heap memory context for a given portal.
322-
*/
323-
MemoryContext
324-
PortalGetHeapMemory(Portalportal)
325-
{
326-
returnportal->heap;
327-
}

‎src/include/utils/portal.h

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,14 @@
77
* Portions Copyright (c) 1996-2001, PostgreSQL Global Development Group
88
* Portions Copyright (c) 1994, Regents of the University of California
99
*
10-
* $Id: portal.h,v 1.25 2001/01/24 19:43:28 momjian Exp $
10+
* $Id: portal.h,v 1.26 2001/02/27 22:07:34 tgl Exp $
1111
*
1212
*-------------------------------------------------------------------------
1313
*/
1414
/*
1515
* Note:
1616
*A portal is an abstraction which represents the execution state of
17-
* a running query (or a fixed sequence of queries).
18-
*
19-
* Note:
20-
*now that PQ calls can be made from within a backend, a portal
21-
*may also be used to keep track of the tuples resulting
22-
*from the execution of a query.In this case, entryIndex
17+
* a running query (specifically, a CURSOR).
2318
*/
2419
#ifndefPORTAL_H
2520
#definePORTAL_H
@@ -28,24 +23,41 @@
2823
#include"nodes/memnodes.h"
2924

3025

31-
typedefstructPortalD*Portal;
26+
typedefstructPortalData*Portal;
3227

33-
typedefstructPortalD
28+
typedefstructPortalData
3429
{
3530
char*name;/* Portal's name */
3631
MemoryContextheap;/* subsidiary memory */
3732
QueryDesc*queryDesc;/* Info about query associated with portal */
3833
TupleDescattinfo;
39-
EState*state;
34+
EState*state;/* Execution state of query */
35+
boolatStart;/* T => fetch backwards is not allowed */
36+
boolatEnd;/* T => fetch forwards is not allowed */
4037
void(*cleanup) (Portal);/* Cleanup routine (optional) */
41-
}PortalD;
38+
}PortalData;
4239

4340
/*
4441
* PortalIsValid
4542
*True iff portal is valid.
4643
*/
4744
#definePortalIsValid(p) PointerIsValid(p)
4845

46+
/*
47+
* Access macros for Portal ... use these in preference to field access.
48+
*/
49+
#definePortalGetQueryDesc(portal) ((portal)->queryDesc)
50+
#definePortalGetTupleDesc(portal) ((portal)->attinfo)
51+
#definePortalGetState(portal) ((portal)->state)
52+
#definePortalGetHeapMemory(portal) ((portal)->heap)
53+
54+
/*
55+
* estimate of the maximum number of open portals a user would have,
56+
* used in initially sizing the PortalHashTable in EnablePortalManager()
57+
*/
58+
#definePORTALS_PER_USER 10
59+
60+
4961
externvoidEnablePortalManager(void);
5062
externvoidAtEOXact_portals(void);
5163
externPortalCreatePortal(char*name);
@@ -54,14 +66,6 @@ extern Portal GetPortalByName(char *name);
5466
externvoidPortalSetQuery(Portalportal,QueryDesc*queryDesc,
5567
TupleDescattinfo,EState*state,
5668
void (*cleanup) (Portalportal));
57-
externQueryDesc*PortalGetQueryDesc(Portalportal);
58-
externEState*PortalGetState(Portalportal);
59-
externMemoryContextPortalGetHeapMemory(Portalportal);
60-
61-
/* estimate of the maximum number of open portals a user would have,
62-
* used in initially sizing the PortalHashTable in EnablePortalManager()
63-
*/
64-
#definePORTALS_PER_USER 10
6569

6670

6771
#endif/* PORTAL_H */

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp