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

Commit97f29c8

Browse files
committed
The previous fix in CVS HEAD and 8.4 for handling the case where a cursor
being used in a PL/pgSQL FOR loop is closed was inadequate, as Tom Lanepointed out. The bug affects FOR statement variants too, because you canclose an implicitly created cursor too by guessing the "<unnamed portal X>"name created for it.To fix that, "pin" the portal to prevent it from being dropped while it'sbeing used in a PL/pgSQL FOR loop. Backpatch all the way to 7.4 which isthe oldest supported version.
1 parent5e77769 commit97f29c8

File tree

3 files changed

+58
-7
lines changed

3 files changed

+58
-7
lines changed

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

Lines changed: 40 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
* Portions Copyright (c) 1994, Regents of the University of California
1313
*
1414
* IDENTIFICATION
15-
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.62 2003/08/24 21:02:43 petere Exp $
15+
* $Header: /cvsroot/pgsql/src/backend/utils/mmgr/portalmem.c,v 1.62.2.1 2010/07/05 09:27:56 heikki Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -288,6 +288,27 @@ PortalCreateHoldStore(Portal portal)
288288
MemoryContextSwitchTo(oldcxt);
289289
}
290290

291+
/*
292+
* PinPortal
293+
*Protect a portal from dropping.
294+
*/
295+
void
296+
PinPortal(Portalportal)
297+
{
298+
if (!portal->portalReady)
299+
elog(ERROR,"cannot pin portal that's not in ready state");
300+
301+
portal->portalPinned= true;
302+
}
303+
304+
void
305+
UnpinPortal(Portalportal)
306+
{
307+
if (!portal->portalPinned)
308+
elog(ERROR,"portal not pinned");
309+
portal->portalPinned= false;
310+
}
311+
291312
/*
292313
* PortalDrop
293314
*Destroy the portal.
@@ -300,9 +321,17 @@ PortalDrop(Portal portal, bool isError)
300321
{
301322
AssertArg(PortalIsValid(portal));
302323

303-
/* Not sure if this case can validly happen or not... */
304-
if (portal->portalActive)
305-
elog(ERROR,"cannot drop active portal");
324+
/*
325+
* Don't allow dropping a pinned portal, it's still needed by whoever
326+
* pinned it. Unless we're doing post-abort cleanup; whoever pinned the
327+
* portal is going to go away at transaction abort anyway.
328+
*
329+
* Not sure if the portalActive case can validly happen or not...
330+
*/
331+
if ((portal->portalPinned&& !isError)||portal->portalActive)
332+
ereport(ERROR,
333+
(errcode(ERRCODE_INVALID_CURSOR_STATE),
334+
errmsg("cannot drop active portal \"%s\"",portal->name)));
306335

307336
/*
308337
* Remove portal from hash table. Because we do this first, we will
@@ -400,6 +429,13 @@ AtCommit_Portals(void)
400429
if (portal->portalActive)
401430
continue;
402431

432+
/*
433+
* There should be no pinned portals anymore. Complain if someone
434+
* leaked one.
435+
*/
436+
if (portal->portalPinned)
437+
elog(ERROR,"cannot commit while a portal is pinned");
438+
403439
if (portal->cursorOptions&CURSOR_OPT_HOLD)
404440
{
405441
/*

‎src/include/utils/portal.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
* Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
4040
* Portions Copyright (c) 1994, Regents of the University of California
4141
*
42-
* $Id: portal.h,v 1.47 2003/08/08 21:42:55 momjian Exp $
42+
* $Id: portal.h,v 1.47.4.1 2010/07/05 09:27:56 heikki Exp $
4343
*
4444
*-------------------------------------------------------------------------
4545
*/
@@ -117,6 +117,7 @@ typedef struct PortalData
117117
boolportalUtilReady;/* PortalRunUtility complete? */
118118
boolportalActive;/* portal is running (can't delete it) */
119119
boolportalDone;/* portal is finished (don't re-run it) */
120+
boolportalPinned;/* portal is pinned (can't delete it) */
120121

121122
/* If not NULL, Executor is active; call ExecutorEnd eventually: */
122123
QueryDesc*queryDesc;/* info needed for executor invocation */
@@ -169,6 +170,8 @@ extern void AtAbort_Portals(void);
169170
externvoidAtCleanup_Portals(void);
170171
externPortalCreatePortal(constchar*name,boolallowDup,booldupSilent);
171172
externPortalCreateNewPortal(void);
173+
externvoidPinPortal(Portalportal);
174+
externvoidUnpinPortal(Portalportal);
172175
externvoidPortalDrop(Portalportal,boolisError);
173176
externvoidDropDependentPortals(MemoryContextqueryContext);
174177
externPortalGetPortalByName(constchar*name);

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
* procedural language
44
*
55
* IDENTIFICATION
6-
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.3 2007/02/08 18:38:19 tgl Exp $
6+
* $Header: /cvsroot/pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.93.2.4 2010/07/05 09:27:57 heikki Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -1384,9 +1384,11 @@ exec_stmt_fors(PLpgSQL_execstate * estate, PLpgSQL_stmt_fors * stmt)
13841384

13851385
/*
13861386
* Open the implicit cursor for the statement and fetch the initial 10
1387-
* rows.
1387+
* rows. Pin the portal to make sure it doesn't get closed by the user
1388+
* statements we execute.
13881389
*/
13891390
exec_run_select(estate,stmt->query,0,&portal);
1391+
PinPortal(portal);
13901392

13911393
SPI_cursor_fetch(portal, true,10);
13921394
tuptab=SPI_tuptable;
@@ -1425,6 +1427,7 @@ exec_stmt_fors(PLpgSQL_execstate * estate, PLpgSQL_stmt_fors * stmt)
14251427
* (This code should match the code after the loop.)
14261428
*/
14271429
SPI_freetuptable(tuptab);
1430+
UnpinPortal(portal);
14281431
SPI_cursor_close(portal);
14291432
exec_set_found(estate,found);
14301433

@@ -1471,6 +1474,7 @@ exec_stmt_fors(PLpgSQL_execstate * estate, PLpgSQL_stmt_fors * stmt)
14711474
/*
14721475
* Close the implicit cursor
14731476
*/
1477+
UnpinPortal(portal);
14741478
SPI_cursor_close(portal);
14751479

14761480
/*
@@ -2227,6 +2231,12 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
22272231
pfree(querystr);
22282232
SPI_freeplan(plan);
22292233

2234+
/*
2235+
* Make sure the portal doesn't get closed by the user statements
2236+
* we execute.
2237+
*/
2238+
PinPortal(portal);
2239+
22302240
/*
22312241
* Fetch the initial 10 tuples
22322242
*/
@@ -2267,6 +2277,7 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
22672277
* (This code should match the code after the loop.)
22682278
*/
22692279
SPI_freetuptable(tuptab);
2280+
UnpinPortal(portal);
22702281
SPI_cursor_close(portal);
22712282
exec_set_found(estate,found);
22722283

@@ -2313,6 +2324,7 @@ exec_stmt_dynfors(PLpgSQL_execstate * estate, PLpgSQL_stmt_dynfors * stmt)
23132324
/*
23142325
* Close the implicit cursor
23152326
*/
2327+
UnpinPortal(portal);
23162328
SPI_cursor_close(portal);
23172329

23182330
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp