8
8
*
9
9
*
10
10
* IDENTIFICATION
11
- * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.259 2010/06/21 09:47:29 heikki Exp $
11
+ * $PostgreSQL: pgsql/src/pl/plpgsql/src/pl_exec.c,v 1.260 2010/07/05 09:27:18 heikki Exp $
12
12
*
13
13
*-------------------------------------------------------------------------
14
14
*/
@@ -2002,20 +2002,11 @@ exec_stmt_forc(PLpgSQL_execstate *estate, PLpgSQL_stmt_forc *stmt)
2002
2002
rc = exec_for_query (estate , (PLpgSQL_stmt_forq * ) stmt , portal , false);
2003
2003
2004
2004
/* ----------
2005
- * Close portal. The statements executed in the loop might've closed the
2006
- * cursor already, rendering our portal pointer invalid, so we mustn't
2007
- * trust the pointer.
2005
+ * Close portal, and restore cursor variable if it was initially NULL.
2008
2006
* ----------
2009
2007
*/
2010
- portal = SPI_cursor_find (portalname );
2011
- if (portal == NULL )
2012
- ereport (ERROR ,
2013
- (errcode (ERRCODE_UNDEFINED_CURSOR ),
2014
- errmsg ("cursor \"%s\" closed unexpectedly" ,
2015
- portalname )));
2016
2008
SPI_cursor_close (portal );
2017
2009
2018
- /* Restore cursor variable if it was initially NULL. */
2019
2010
if (curname == NULL )
2020
2011
{
2021
2012
free_var (curvar );
@@ -4278,13 +4269,6 @@ exec_run_select(PLpgSQL_execstate *estate,
4278
4269
* exec_for_query --- execute body of FOR loop for each row from a portal
4279
4270
*
4280
4271
* Used by exec_stmt_fors, exec_stmt_forc and exec_stmt_dynfors
4281
- *
4282
- * If the portal is for a cursor that's visible to user code, the statements
4283
- * we execute might move or close the cursor. You must pass prefetch_ok=false
4284
- * in that case to disable optimizations that rely on the portal staying
4285
- * unchanged over execution of the user statements.
4286
- * NB: With prefetch_ok=false, the portal pointer might point to garbage
4287
- * after the call. Caller beware!
4288
4272
*/
4289
4273
static int
4290
4274
exec_for_query (PLpgSQL_execstate * estate , PLpgSQL_stmt_forq * stmt ,
@@ -4296,10 +4280,6 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
4296
4280
bool found = false;
4297
4281
int rc = PLPGSQL_RC_OK ;
4298
4282
int n ;
4299
- const char * portalname ;
4300
-
4301
- /* Remember portal name so that we can re-find it */
4302
- portalname = portal -> name ;
4303
4283
4304
4284
/*
4305
4285
* Determine if we assign to a record or a row
@@ -4311,6 +4291,12 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
4311
4291
else
4312
4292
elog (ERROR , "unsupported target" );
4313
4293
4294
+ /*
4295
+ * Make sure the portal doesn't get closed by the user statements
4296
+ * we execute.
4297
+ */
4298
+ PinPortal (portal );
4299
+
4314
4300
/*
4315
4301
* Fetch the initial tuple(s). If prefetching is allowed then we grab a
4316
4302
* few more rows to avoid multiple trips through executor startup
@@ -4408,22 +4394,8 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
4408
4394
4409
4395
/*
4410
4396
* Fetch more tuples. If prefetching is allowed, grab 50 at a time.
4411
- * Otherwise the statements executed in the loop might've moved or
4412
- * even closed the cursor, so check that the cursor is still open,
4413
- * and fetch only one row at a time.
4414
4397
*/
4415
- if (prefetch_ok )
4416
- SPI_cursor_fetch (portal , true, 50 );
4417
- else
4418
- {
4419
- portal = SPI_cursor_find (portalname );
4420
- if (portal == NULL )
4421
- ereport (ERROR ,
4422
- (errcode (ERRCODE_UNDEFINED_CURSOR ),
4423
- errmsg ("cursor \"%s\" closed unexpectedly" ,
4424
- portalname )));
4425
- SPI_cursor_fetch (portal , true, 1 );
4426
- }
4398
+ SPI_cursor_fetch (portal , true, prefetch_ok ? 50 : 1 );
4427
4399
tuptab = SPI_tuptable ;
4428
4400
n = SPI_processed ;
4429
4401
}
@@ -4435,6 +4407,8 @@ exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt,
4435
4407
*/
4436
4408
SPI_freetuptable (tuptab );
4437
4409
4410
+ UnpinPortal (portal );
4411
+
4438
4412
/*
4439
4413
* Set the FOUND variable to indicate the result of executing the loop
4440
4414
* (namely, whether we looped one or more times). This must be set last so
0 commit comments