diff --git a/src/backend/executor/functions.c b/src/backend/executor/functions.c index 12214f8a150..65e52cca630 100644 --- a/src/backend/executor/functions.c +++ b/src/backend/executor/functions.c @@ -503,7 +503,7 @@ init_execution_state(List *queryTree_list, } else stmt = pg_plan_query(queryTree, - fcache->readonly_func ? CURSOR_OPT_PARALLEL_OK : 0, + CURSOR_OPT_PARALLEL_OK, NULL); /* diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 72c7b4d0689..eeaa4805e4d 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -314,7 +314,7 @@ SPI_execute(const char *src, bool read_only, long tcount) memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; - plan.cursor_options = 0; + plan.cursor_options = CURSOR_OPT_PARALLEL_OK; _SPI_prepare_oneshot_plan(src, &plan); @@ -458,7 +458,7 @@ SPI_execute_with_args(const char *src, memset(&plan, 0, sizeof(_SPI_plan)); plan.magic = _SPI_PLAN_MAGIC; - plan.cursor_options = 0; + plan.cursor_options = CURSOR_OPT_PARALLEL_OK; plan.nargs = nargs; plan.argtypes = argtypes; plan.parserSetup = NULL; diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 8e836a81494..664fc425143 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -264,8 +264,7 @@ static Datum exec_eval_expr(PLpgSQL_execstate *estate, Oid *rettype, int32 *rettypmod); static int exec_run_select(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, long maxtuples, Portal *portalP, - bool parallelOK); + PLpgSQL_expr *expr, long maxtuples, Portal *portalP); static int exec_for_query(PLpgSQL_execstate *estate, PLpgSQL_stmt_forq *stmt, Portal portal, bool prefetch_ok); static ParamListInfo setup_param_list(PLpgSQL_execstate *estate, @@ -1685,7 +1684,7 @@ exec_stmt_perform(PLpgSQL_execstate *estate, PLpgSQL_stmt_perform *stmt) { PLpgSQL_expr *expr = stmt->expr; - (void) exec_run_select(estate, expr, 0, NULL, true); + (void) exec_run_select(estate, expr, 0, NULL); exec_set_found(estate, (estate->eval_processed != 0)); exec_eval_cleanup(estate); @@ -2238,7 +2237,7 @@ exec_stmt_fors(PLpgSQL_execstate *estate, PLpgSQL_stmt_fors *stmt) /* * Open the implicit cursor for the statement using exec_run_select */ - exec_run_select(estate, stmt->query, 0, &portal, false); + exec_run_select(estate, stmt->query, 0, &portal); /* * Execute the loop @@ -3023,7 +3022,7 @@ exec_stmt_return_query(PLpgSQL_execstate *estate, if (stmt->query != NULL) { /* static query */ - exec_run_select(estate, stmt->query, 0, &portal, false); + exec_run_select(estate, stmt->query, 0, &portal); } else { @@ -3627,7 +3626,7 @@ exec_stmt_execsql(PLpgSQL_execstate *estate, { ListCell *l; - exec_prepare_plan(estate, expr, 0); + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); stmt->mod_stmt = false; foreach(l, SPI_plan_get_plan_sources(expr->plan)) { @@ -5174,7 +5173,7 @@ exec_eval_expr(PLpgSQL_execstate *estate, * If first time through, create a plan for this expression. */ if (expr->plan == NULL) - exec_prepare_plan(estate, expr, 0); + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); /* * If this is a simple expression, bypass SPI and use the executor @@ -5187,7 +5186,7 @@ exec_eval_expr(PLpgSQL_execstate *estate, /* * Else do it the hard way via exec_run_select */ - rc = exec_run_select(estate, expr, 2, NULL, false); + rc = exec_run_select(estate, expr, 2, NULL); if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE), @@ -5243,18 +5242,23 @@ exec_eval_expr(PLpgSQL_execstate *estate, */ static int exec_run_select(PLpgSQL_execstate *estate, - PLpgSQL_expr *expr, long maxtuples, Portal *portalP, - bool parallelOK) + PLpgSQL_expr *expr, long maxtuples, Portal *portalP) { ParamListInfo paramLI; int rc; /* - * 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 + * the query once, which means it's OK to use a parallel plan, even if the + * number of rows being fetched is limited. If we do need to return a + * portal, the caller might do cursor operations, which parallel query + * can't support. */ if (expr->plan == NULL) - exec_prepare_plan(estate, expr, parallelOK ? - CURSOR_OPT_PARALLEL_OK : 0); + exec_prepare_plan(estate, expr, + portalP == NULL ? CURSOR_OPT_PARALLEL_OK : 0); /* * If a portal was requested, put the query into the portal