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

Commitc778f89

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 parent971e110 commitc778f89

File tree

3 files changed

+67
-8
lines changed

3 files changed

+67
-8
lines changed

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

Lines changed: 49 additions & 5 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-
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76.4.2 2005/04/11 19:51:31 tgl Exp $
15+
* $PostgreSQL: pgsql/src/backend/utils/mmgr/portalmem.c,v 1.76.4.3 2010/07/05 09:27:49 heikki Exp $
1616
*
1717
*-------------------------------------------------------------------------
1818
*/
@@ -295,6 +295,28 @@ PortalCreateHoldStore(Portal portal)
295295
MemoryContextSwitchTo(oldcxt);
296296
}
297297

298+
/*
299+
* PinPortal
300+
*Protect a portal from dropping.
301+
*/
302+
void
303+
PinPortal(Portalportal)
304+
{
305+
if (portal->portalPinned)
306+
elog(ERROR,"portal already pinned");
307+
308+
portal->portalPinned= true;
309+
}
310+
311+
void
312+
UnpinPortal(Portalportal)
313+
{
314+
if (!portal->portalPinned)
315+
elog(ERROR,"portal not pinned");
316+
317+
portal->portalPinned= false;
318+
}
319+
298320
/*
299321
* PortalDrop
300322
*Destroy the portal.
@@ -304,9 +326,16 @@ PortalDrop(Portal portal, bool isTopCommit)
304326
{
305327
AssertArg(PortalIsValid(portal));
306328

307-
/* Not sure if this case can validly happen or not... */
308-
if (portal->status==PORTAL_ACTIVE)
309-
elog(ERROR,"cannot drop active portal");
329+
/*
330+
* Don't allow dropping a pinned portal, it's still needed by whoever
331+
* pinned it. Not sure if the PORTAL_ACTIVE case can validly happen or
332+
* not...
333+
*/
334+
if (portal->portalPinned||
335+
portal->status==PORTAL_ACTIVE)
336+
ereport(ERROR,
337+
(errcode(ERRCODE_INVALID_CURSOR_STATE),
338+
errmsg("cannot drop active portal \"%s\"",portal->name)));
310339

311340
/*
312341
* Remove portal from hash table. Because we do this first, we will
@@ -507,6 +536,13 @@ AtCommit_Portals(void)
507536
continue;
508537
}
509538

539+
/*
540+
* There should be no pinned portals anymore. Complain if someone
541+
* leaked one.
542+
*/
543+
if (portal->portalPinned)
544+
elog(ERROR,"cannot commit while a portal is pinned");
545+
510546
/*
511547
* Do nothing to cursors held over from a previous transaction
512548
* (including holdable ones just frozen by CommitHoldablePortals).
@@ -590,7 +626,15 @@ AtCleanup_Portals(void)
590626
continue;
591627
}
592628

593-
/* Else zap it. */
629+
/*
630+
* If a portal is still pinned, forcibly unpin it. PortalDrop will
631+
* not let us drop the portal otherwise. Whoever pinned the portal
632+
* was interrupted by the abort too and won't try to use it anymore.
633+
*/
634+
if (portal->portalPinned)
635+
portal->portalPinned= false;
636+
637+
/* Zap it. */
594638
PortalDrop(portal, false);
595639
}
596640
}

‎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-2005, PostgreSQL Global Development Group
4040
* Portions Copyright (c) 1994, Regents of the University of California
4141
*
42-
* $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.54.4.1 2005/04/11 19:51:32 tgl Exp $
42+
* $PostgreSQL: pgsql/src/include/utils/portal.h,v 1.54.4.2 2010/07/05 09:27:49 heikki Exp $
4343
*
4444
*-------------------------------------------------------------------------
4545
*/
@@ -135,6 +135,7 @@ typedef struct PortalData
135135
/* Status data */
136136
PortalStatusstatus;/* see above */
137137
boolportalUtilReady;/* PortalRunUtility complete? */
138+
boolportalPinned;/* a pinned portal can't be dropped */
138139

139140
/* If not NULL, Executor is active; call ExecutorEnd eventually: */
140141
QueryDesc*queryDesc;/* info needed for executor invocation */
@@ -195,6 +196,8 @@ extern void AtSubAbort_Portals(SubTransactionId mySubid,
195196
externvoidAtSubCleanup_Portals(SubTransactionIdmySubid);
196197
externPortalCreatePortal(constchar*name,boolallowDup,booldupSilent);
197198
externPortalCreateNewPortal(void);
199+
externvoidPinPortal(Portalportal);
200+
externvoidUnpinPortal(Portalportal);
198201
externvoidPortalDrop(Portalportal,boolisTopCommit);
199202
externvoidDropDependentPortals(MemoryContextqueryContext);
200203
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-
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.8 2010/02/12 19:38:15 tgl Exp $
6+
* $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.127.4.9 2010/07/05 09:27:49 heikki Exp $
77
*
88
* This software is copyrighted by Jan Wieck - Hamburg.
99
*
@@ -1525,9 +1525,11 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
15251525

15261526
/*
15271527
* Open the implicit cursor for the statement and fetch the initial 10
1528-
* rows.
1528+
* rows. Pin the portal to make sure it doesn't get closed by the user
1529+
* statements we execute.
15291530
*/
15301531
exec_run_select(estate,stmt->query,0,&portal);
1532+
PinPortal(portal);
15311533

15321534
SPI_cursor_fetch(portal, true,10);
15331535
tuptab=SPI_tuptable;
@@ -1566,6 +1568,7 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
15661568
* (This code should match the code after the loop.)
15671569
*/
15681570
SPI_freetuptable(tuptab);
1571+
UnpinPortal(portal);
15691572
SPI_cursor_close(portal);
15701573
exec_set_found(estate,found);
15711574

@@ -1612,6 +1615,7 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt)
16121615
/*
16131616
* Close the implicit cursor
16141617
*/
1618+
UnpinPortal(portal);
16151619
SPI_cursor_close(portal);
16161620

16171621
/*
@@ -2415,6 +2419,12 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
24152419
pfree(querystr);
24162420
SPI_freeplan(plan);
24172421

2422+
/*
2423+
* Make sure the portal doesn't get closed by the user statements
2424+
* we execute.
2425+
*/
2426+
PinPortal(portal);
2427+
24182428
/*
24192429
* Fetch the initial 10 tuples
24202430
*/
@@ -2455,6 +2465,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
24552465
* (This code should match the code after the loop.)
24562466
*/
24572467
SPI_freetuptable(tuptab);
2468+
UnpinPortal(portal);
24582469
SPI_cursor_close(portal);
24592470
exec_set_found(estate,found);
24602471

@@ -2501,6 +2512,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
25012512
/*
25022513
* Close the implicit cursor
25032514
*/
2515+
UnpinPortal(portal);
25042516
SPI_cursor_close(portal);
25052517

25062518
/*

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp