]> granicus.if.org Git - postgresql/commitdiff
Improve access to parallel query from procedural languages.
authorRobert Haas <rhaas@postgresql.org>
Fri, 24 Mar 2017 18:46:33 +0000 (14:46 -0400)
committerRobert Haas <rhaas@postgresql.org>
Fri, 24 Mar 2017 18:46:33 +0000 (14:46 -0400)
In SQL, the ability to use parallel query was previous contingent on
fcache->readonly_func, which is only set for non-volatile functions;
but the volatility of a function has no bearing on whether queries
inside it can use parallelism.  Remove that condition.

SPI_execute and SPI_execute_with_args always run the plan just once,
though not necessarily to completion.  Given the changes in commit
691b8d59281b5177f16fe80858df921f77a8e955, it's sensible to pass
CURSOR_OPT_PARALLEL_OK here, so do that.  This improves access to
parallelism for any caller that uses these functions to execute
queries.  Such callers include plperl, plpython, pltcl, and plpgsql,
though it's not the case that they all use these functions
exclusively.

In plpgsql, allow parallel query for plain SELECT queries (as
opposed to PERFORM, which already worked) and for plain expressions
(which probably won't go through the executor at all, because they
will likely be simple expressions, but if they do then this helps).

Rafia Sabih and Robert Haas, reviewed by Dilip Kumar and Amit Kapila

Discussion: http://postgr.es/m/CAOGQiiMfJ+4SQwgG=6CVHWoisiU0+7jtXSuiyXBM3y=A=eJzmg@mail.gmail.com

src/backend/executor/functions.c
src/backend/executor/spi.c
src/pl/plpgsql/src/pl_exec.c

index 12214f8a15042e0482e6c706f2e19212d2445053..65e52cca630f40fec1d28875f1904f90d69e5a98 100644 (file)
@@ -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);
 
                        /*
index 72c7b4d068934e27d061a248420e3feb2438e893..eeaa4805e4d28db678158c25768b677198adc956 100644 (file)
@@ -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;
index 8e836a81494cbfd9ff0367e3e8bc26a91b7a8307..664fc425143c886ec336deba4e5ae59751856375 100644 (file)
@@ -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