mirror of
https://git.postgresql.org/git/postgresql.git
synced 2024-08-23 08:30:40 +02:00
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
This commit is contained in:
parent
2757865fa7
commit
5b7bf9f72a
@ -4519,7 +4519,7 @@ exec_stmt_dynfors(PLpgSQL_execstate *estate, PLpgSQL_stmt_dynfors *stmt)
|
|||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
|
portal = exec_dynquery_with_params(estate, stmt->query, stmt->params,
|
||||||
NULL, 0);
|
NULL, CURSOR_OPT_NO_SCROLL);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Execute the loop
|
* Execute the loop
|
||||||
@ -5852,14 +5852,21 @@ exec_run_select(PLpgSQL_execstate *estate,
|
|||||||
* On the first call for this expression generate the plan.
|
* On the first call for this expression generate the plan.
|
||||||
*
|
*
|
||||||
* If we don't need to return a portal, then we're just going to execute
|
* If we don't need to return a portal, then we're just going to execute
|
||||||
* the query once, which means it's OK to use a parallel plan, even if the
|
* the query immediately, which means it's OK to use a parallel plan, even
|
||||||
* number of rows being fetched is limited. If we do need to return a
|
* if the number of rows being fetched is limited. If we do need to
|
||||||
* portal, the caller might do cursor operations, which parallel query
|
* return a portal (i.e., this is for a FOR loop), the user's code might
|
||||||
* can't support.
|
* invoke additional operations inside the FOR loop, making parallel query
|
||||||
|
* unsafe. In any case, we don't expect any cursor operations to be done,
|
||||||
|
* so specify NO_SCROLL for efficiency and semantic safety.
|
||||||
*/
|
*/
|
||||||
if (expr->plan == NULL)
|
if (expr->plan == NULL)
|
||||||
exec_prepare_plan(estate, expr,
|
{
|
||||||
portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0, true);
|
int cursorOptions = CURSOR_OPT_NO_SCROLL;
|
||||||
|
|
||||||
|
if (portalP == NULL)
|
||||||
|
cursorOptions |= CURSOR_OPT_PARALLEL_OK;
|
||||||
|
exec_prepare_plan(estate, expr, cursorOptions, true);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up ParamListInfo to pass to executor
|
* Set up ParamListInfo to pass to executor
|
||||||
|
Loading…
Reference in New Issue
Block a user