@@ -91,8 +91,9 @@ typedef struct
9191
9292typedef struct
9393{
94- bool allow_restricted ;
95- } has_parallel_hazard_arg ;
94+ char max_hazard ; /* worst proparallel hazard found so far */
95+ char max_interesting ; /* worst proparallel hazard of interest */
96+ } max_parallel_hazard_context ;
9697
9798static bool contain_agg_clause_walker (Node * node , void * context );
9899static bool get_agg_clause_costs_walker (Node * node ,
@@ -103,8 +104,8 @@ static bool contain_subplans_walker(Node *node, void *context);
103104static bool contain_mutable_functions_walker (Node * node , void * context );
104105static bool contain_volatile_functions_walker (Node * node , void * context );
105106static bool contain_volatile_functions_not_nextval_walker (Node * node , void * context );
106- static bool has_parallel_hazard_walker (Node * node ,
107- has_parallel_hazard_arg * context );
107+ static bool max_parallel_hazard_walker (Node * node ,
108+ max_parallel_hazard_context * context );
108109static bool contain_nonstrict_functions_walker (Node * node , void * context );
109110static bool contain_context_dependent_node (Node * clause );
110111static bool contain_context_dependent_node_walker (Node * node , int * flags );
@@ -1100,46 +1101,98 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
11001101 context );
11011102}
11021103
1104+
11031105/*****************************************************************************
11041106 * Check queries for parallel unsafe and/or restricted constructs
11051107 *****************************************************************************/
11061108
11071109/*
1108- * Check whether a node tree contains parallel hazards. This is used both on
1109- * the entire query tree, to see whether the query can be parallelized at all
1110- * (with allow_restricted = true), and also to evaluate whether a particular
1111- * expression is safe to run within a parallel worker (with allow_restricted =
1112- * false). We could separate these concerns into two different functions, but
1113- * there's enough overlap that it doesn't seem worthwhile.
1110+ * max_parallel_hazard
1111+ * Find the worst parallel-hazard level in the given query
1112+ *
1113+ * Returns the worst function hazard property (the earliest in this list:
1114+ * PROPARALLEL_UNSAFE, PROPARALLEL_RESTRICTED, PROPARALLEL_SAFE) that can
1115+ * be found in the given parsetree. We use this to find out whether the query
1116+ * can be parallelized at all. The caller will also save the result in
1117+ * PlannerGlobal so as to short-circuit checks of portions of the querytree
1118+ * later, in the common case where everything is SAFE.
1119+ */
1120+ char
1121+ max_parallel_hazard (Query * parse )
1122+ {
1123+ max_parallel_hazard_context context ;
1124+
1125+ context .max_hazard = PROPARALLEL_SAFE ;
1126+ context .max_interesting = PROPARALLEL_UNSAFE ;
1127+ (void ) max_parallel_hazard_walker ((Node * ) parse , & context );
1128+ return context .max_hazard ;
1129+ }
1130+
1131+ /*
1132+ * is_parallel_safe
1133+ * Detect whether the given expr contains only parallel-safe functions
1134+ *
1135+ * root->glob->maxParallelHazard must previously have been set to the
1136+ * result of max_parallel_hazard() on the whole query.
11141137 */
11151138bool
1116- has_parallel_hazard ( Node * node , bool allow_restricted )
1139+ is_parallel_safe ( PlannerInfo * root , Node * node )
11171140{
1118- has_parallel_hazard_arg context ;
1141+ max_parallel_hazard_context context ;
11191142
1120- context .allow_restricted = allow_restricted ;
1121- return has_parallel_hazard_walker (node , & context );
1143+ /* If max_parallel_hazard found nothing unsafe, we don't need to look */
1144+ if (root -> glob -> maxParallelHazard == PROPARALLEL_SAFE )
1145+ return true;
1146+ /* Else use max_parallel_hazard's search logic, but stop on RESTRICTED */
1147+ context .max_hazard = PROPARALLEL_SAFE ;
1148+ context .max_interesting = PROPARALLEL_RESTRICTED ;
1149+ return !max_parallel_hazard_walker (node , & context );
11221150}
11231151
1152+ /* core logic for all parallel-hazard checks */
11241153static bool
1125- has_parallel_hazard_checker ( Oid func_id , void * context )
1154+ max_parallel_hazard_test ( char proparallel , max_parallel_hazard_context * context )
11261155{
1127- char proparallel = func_parallel (func_id );
1156+ switch (proparallel )
1157+ {
1158+ case PROPARALLEL_SAFE :
1159+ /* nothing to see here, move along */
1160+ break ;
1161+ case PROPARALLEL_RESTRICTED :
1162+ /* increase max_hazard to RESTRICTED */
1163+ Assert (context -> max_hazard != PROPARALLEL_UNSAFE );
1164+ context -> max_hazard = proparallel ;
1165+ /* done if we are not expecting any unsafe functions */
1166+ if (context -> max_interesting == proparallel )
1167+ return true;
1168+ break ;
1169+ case PROPARALLEL_UNSAFE :
1170+ context -> max_hazard = proparallel ;
1171+ /* we're always done at the first unsafe construct */
1172+ return true;
1173+ default :
1174+ elog (ERROR , "unrecognized proparallel value \"%c\"" , proparallel );
1175+ break ;
1176+ }
1177+ return false;
1178+ }
11281179
1129- if (((has_parallel_hazard_arg * ) context )-> allow_restricted )
1130- return (proparallel == PROPARALLEL_UNSAFE );
1131- else
1132- return (proparallel != PROPARALLEL_SAFE );
1180+ /* check_functions_in_node callback */
1181+ static bool
1182+ max_parallel_hazard_checker (Oid func_id , void * context )
1183+ {
1184+ return max_parallel_hazard_test (func_parallel (func_id ),
1185+ (max_parallel_hazard_context * ) context );
11331186}
11341187
11351188static bool
1136- has_parallel_hazard_walker (Node * node , has_parallel_hazard_arg * context )
1189+ max_parallel_hazard_walker (Node * node , max_parallel_hazard_context * context )
11371190{
11381191 if (node == NULL )
11391192 return false;
11401193
11411194 /* Check for hazardous functions in node itself */
1142- if (check_functions_in_node (node , has_parallel_hazard_checker ,
1195+ if (check_functions_in_node (node , max_parallel_hazard_checker ,
11431196 context ))
11441197 return true;
11451198
@@ -1156,7 +1209,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11561209 */
11571210 if (IsA (node , CoerceToDomain ))
11581211 {
1159- if (! context -> allow_restricted )
1212+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
11601213 return true;
11611214 }
11621215
@@ -1167,7 +1220,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11671220 {
11681221 RestrictInfo * rinfo = (RestrictInfo * ) node ;
11691222
1170- return has_parallel_hazard_walker ((Node * ) rinfo -> clause , context );
1223+ return max_parallel_hazard_walker ((Node * ) rinfo -> clause , context );
11711224 }
11721225
11731226 /*
@@ -1176,13 +1229,13 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11761229 * not worry about examining their contents; if they are unsafe, we would
11771230 * have found that out while examining the whole tree before reduction of
11781231 * sublinks to subplans. (Really we should not see SubLink during a
1179- * not-allow_restricted scan, but if we do, return true.)
1232+ * max_interesting == restricted scan, but if we do, return true.)
11801233 */
11811234 else if (IsA (node , SubLink ) ||
11821235 IsA (node , SubPlan ) ||
11831236 IsA (node , AlternativeSubPlan ))
11841237 {
1185- if (! context -> allow_restricted )
1238+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
11861239 return true;
11871240 }
11881241
@@ -1192,7 +1245,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
11921245 */
11931246 else if (IsA (node , Param ))
11941247 {
1195- if (! context -> allow_restricted )
1248+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
11961249 return true;
11971250 }
11981251
@@ -1207,20 +1260,24 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
12071260
12081261 /* SELECT FOR UPDATE/SHARE must be treated as unsafe */
12091262 if (query -> rowMarks != NULL )
1263+ {
1264+ context -> max_hazard = PROPARALLEL_UNSAFE ;
12101265 return true;
1266+ }
12111267
12121268 /* Recurse into subselects */
12131269 return query_tree_walker (query ,
1214- has_parallel_hazard_walker ,
1270+ max_parallel_hazard_walker ,
12151271 context , 0 );
12161272 }
12171273
12181274 /* Recurse to check arguments */
12191275 return expression_tree_walker (node ,
1220- has_parallel_hazard_walker ,
1276+ max_parallel_hazard_walker ,
12211277 context );
12221278}
12231279
1280+
12241281/*****************************************************************************
12251282 * Check clauses for nonstrict functions
12261283 *****************************************************************************/
0 commit comments