Skip to content

Commit be90098

Browse files
committed
Force NO SCROLL for plpgsql's implicit cursors.
Further thought about bug #17050 suggests that it's a good idea to use CURSOR_OPT_NO_SCROLL for the implicit cursor opened by a plpgsql FOR-over-query loop. This ensures that, if somebody commits inside the loop, PersistHoldablePortal won't try to rewind and re-read the cursor. While we'd have selected NO_SCROLL anyway if FOR UPDATE/SHARE appears in the query, there are other hazards with volatile functions; and in any case, it's silly to expend effort storing rows that we know for certain won't be needed. (While here, improve the comment in exec_run_select, which was a bit confused about the rationale for when we can use parallel mode. Cursor operations aren't a hazard for nameless portals.) This wasn't an issue until v11, which introduced the possibility of persisting such cursors. Hence, back-patch to v11. Per bug #17050 from Алексей Булгаков. Discussion: https://postgr.es/m/17050-f77aa827dc85247c@postgresql.org
1 parent ba2c6d6 commit be90098

File tree

1 file changed

+14
-7
lines changed

1 file changed

+14
-7
lines changed

src/pl/plpgsql/src/pl_exec.c

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4561,7 +4561,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
45614561
int rc;
45624562

45634563
portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
4564-
NULL, 0);
4564+
NULL, CURSOR_OPT_NO_SCROLL);
45654565

45664566
/*
45674567
* Execute the loop
@@ -5694,14 +5694,21 @@ exec_run_select(PLpgSQL_execstate *estate,
56945694
* On the first call for this expression generate the plan.
56955695
*
56965696
* If we don't need to return a portal, then we're just going to execute
5697-
* the query once, which means it's OK to use a parallel plan, even if the
5698-
* number of rows being fetched is limited. If we do need to return a
5699-
* portal, the caller might do cursor operations, which parallel query
5700-
* can't support.
5697+
* the query immediately, which means it's OK to use a parallel plan, even
5698+
* if the number of rows being fetched is limited. If we do need to
5699+
* return a portal (i.e., this is for a FOR loop), the user's code might
5700+
* invoke additional operations inside the FOR loop, making parallel query
5701+
* unsafe. In any case, we don't expect any cursor operations to be done,
5702+
* so specify NO_SCROLL for efficiency and semantic safety.
57015703
*/
57025704
if (expr->plan == NULL)
5703-
exec_prepare_plan(estate, expr,
5704-
portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0);
5705+
{
5706+
int cursorOptions = CURSOR_OPT_NO_SCROLL;
5707+
5708+
if (portalP == NULL)
5709+
cursorOptions |= CURSOR_OPT_PARALLEL_OK;
5710+
exec_prepare_plan(estate, expr, cursorOptions);
5711+
}
57055712

57065713
/*
57075714
* Set up ParamListInfo to pass to executor

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy