diff --git a/src/backend/executor/execMain.c b/src/backend/executor/execMain.c index a666391..fc5c82f 100644 --- a/src/backend/executor/execMain.c +++ b/src/backend/executor/execMain.c @@ -1596,6 +1596,22 @@ ExecutePlan(EState *estate, EnterParallelMode(); /* + * For SQL or other PL functions, the supplied numberTuples is always + * one, thus, upper condition restricts parallelism for the queries + * coming from these functions. To enable such parallelism, we ignore the + * numberTuples check and identify if the planner considers it safe to use + * parallelism for this query and it is coming only from PL or SQL + * functions. + */ + + else if (estate->es_plannedstmt->parallelModeNeeded && + (dest->mydest == DestSPI || dest->mydest == DestSQLFunction)) + { + use_parallel_mode = true; + EnterParallelMode(); + } + + /* * Loop until we've processed the proper number of tuples from the plan. */ for (;;) @@ -1660,7 +1676,16 @@ ExecutePlan(EState *estate, */ current_tuple_count++; if (numberTuples && numberTuples == current_tuple_count) + { + /* + * For the queries coming from SQL or PL functions, this condition + * will be satisfied for the first tuple and since we enabled + * parallel workers for it, a proper shutdown of the workers would + * be required. + */ + (void) ExecShutdownNode(planstate); break; + } } if (use_parallel_mode) diff --git a/src/backend/executor/spi.c b/src/backend/executor/spi.c index 55f97b1..45114d2 100644 --- a/src/backend/executor/spi.c +++ b/src/backend/executor/spi.c @@ -314,7 +314,12 @@ 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; + + /* Allow parallelism if the query is read-only */ + if(read_only) + plan.cursor_options = CURSOR_OPT_PARALLEL_OK; + else + plan.cursor_options = 0; _SPI_prepare_oneshot_plan(src, &plan); diff --git a/src/pl/plpgsql/src/pl_exec.c b/src/pl/plpgsql/src/pl_exec.c index 6fc3db0..27c9e47 100644 --- a/src/pl/plpgsql/src/pl_exec.c +++ b/src/pl/plpgsql/src/pl_exec.c @@ -3625,7 +3625,12 @@ exec_stmt_execsql(PLpgSQL_execstate *estate, { ListCell *l; - exec_prepare_plan(estate, expr, 0); + /* Allow parallelism if the function is not trigger type. */ + if (estate->func->fn_is_trigger == PLPGSQL_NOT_TRIGGER) + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); + else + exec_prepare_plan(estate, expr, 0); + stmt->mod_stmt = false; foreach(l, SPI_plan_get_plan_sources(expr->plan)) { @@ -3869,8 +3874,13 @@ exec_stmt_dynexecute(PLpgSQL_execstate *estate, estate->readonly_func, 0); } else - exec_res = SPI_execute(querystr, estate->readonly_func, 0); - + { + /* Allow parallelism if the function is not trigger type. */ + if (estate->func->fn_is_trigger == PLPGSQL_NOT_TRIGGER) + exec_res = SPI_execute(querystr, estate->readonly_func, CURSOR_OPT_PARALLEL_OK); + else + exec_res = SPI_execute(querystr, estate->readonly_func, 0); + } switch (exec_res) { case SPI_OK_SELECT: @@ -5172,8 +5182,13 @@ 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); - + { + /* Allow parallelism is the function is not trigger type. */ + if (estate->func->fn_is_trigger == PLPGSQL_NOT_TRIGGER) + exec_prepare_plan(estate, expr, CURSOR_OPT_PARALLEL_OK); + else + exec_prepare_plan(estate, expr, 0); + } /* * If this is a simple expression, bypass SPI and use the executor * directly @@ -5183,9 +5198,14 @@ exec_eval_expr(PLpgSQL_execstate *estate, return result; /* - * Else do it the hard way via exec_run_select + * Else do it the hard way via exec_run_select. Enable parallelism + * if function is not trigger type. */ - rc = exec_run_select(estate, expr, 2, NULL, false); + if (estate->func->fn_is_trigger == PLPGSQL_NOT_TRIGGER) + rc = exec_run_select(estate, expr, 2, NULL, true); + else + rc = exec_run_select(estate, expr, 2, NULL, false); + if (rc != SPI_OK_SELECT) ereport(ERROR, (errcode(ERRCODE_WRONG_OBJECT_TYPE),