@@ -91,8 +91,9 @@ typedef struct
91
91
92
92
typedef struct
93
93
{
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 ;
96
97
97
98
static bool contain_agg_clause_walker (Node * node , void * context );
98
99
static bool get_agg_clause_costs_walker (Node * node ,
@@ -103,8 +104,8 @@ static bool contain_subplans_walker(Node *node, void *context);
103
104
static bool contain_mutable_functions_walker (Node * node , void * context );
104
105
static bool contain_volatile_functions_walker (Node * node , void * context );
105
106
static 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 );
108
109
static bool contain_nonstrict_functions_walker (Node * node , void * context );
109
110
static bool contain_context_dependent_node (Node * clause );
110
111
static bool contain_context_dependent_node_walker (Node * node , int * flags );
@@ -1100,46 +1101,98 @@ contain_volatile_functions_not_nextval_walker(Node *node, void *context)
1100
1101
context );
1101
1102
}
1102
1103
1104
+
1103
1105
/*****************************************************************************
1104
1106
* Check queries for parallel unsafe and/or restricted constructs
1105
1107
*****************************************************************************/
1106
1108
1107
1109
/*
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.
1114
1137
*/
1115
1138
bool
1116
- has_parallel_hazard ( Node * node , bool allow_restricted )
1139
+ is_parallel_safe ( PlannerInfo * root , Node * node )
1117
1140
{
1118
- has_parallel_hazard_arg context ;
1141
+ max_parallel_hazard_context context ;
1119
1142
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 );
1122
1150
}
1123
1151
1152
+ /* core logic for all parallel-hazard checks */
1124
1153
static bool
1125
- has_parallel_hazard_checker ( Oid func_id , void * context )
1154
+ max_parallel_hazard_test ( char proparallel , max_parallel_hazard_context * context )
1126
1155
{
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
C2EE
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
+ }
1128
1179
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 );
1133
1186
}
1134
1187
1135
1188
static 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 )
1137
1190
{
1138
1191
if (node == NULL )
1139
1192
return false;
1140
1193
1141
1194
/* 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 ,
1143
1196
context ))
1144
1197
return true;
1145
1198
@@ -1156,7 +1209,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
1156
1209
*/
1157
1210
if (IsA (node , CoerceToDomain ))
1158
1211
{
1159
- if (! context -> allow_restricted )
1212
+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
1160
1213
return true;
1161
1214
}
1162
1215
@@ -1167,7 +1220,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
1167
1220
{
1168
1221
RestrictInfo * rinfo = (RestrictInfo * ) node ;
1169
1222
1170
- return has_parallel_hazard_walker ((Node * ) rinfo -> clause , context );
1223
+ return max_parallel_hazard_walker ((Node * ) rinfo -> clause , context );
1171
1224
}
1172
1225
1173
1226
/*
@@ -1176,13 +1229,13 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
1176
1229
* not worry about examining their contents; if they are unsafe, we would
1177
1230
* have found that out while examining the whole tree before reduction of
1178
1231
* 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.)
1180
1233
*/
1181
1234
else if (IsA (node , SubLink ) ||
1182
1235
IsA (node , SubPlan ) ||
1183
1236
IsA (node , AlternativeSubPlan ))
1184
1237
{
1185
- if (! context -> allow_restricted )
1238
+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
1186
1239
return true;
1187
1240
}
1188
1241
@@ -1192,7 +1245,7 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
1192
1245
*/
1193
1246
else if (IsA (node , Param ))
1194
1247
{
1195
- if (! context -> allow_restricted )
1248
+ if (max_parallel_hazard_test ( PROPARALLEL_RESTRICTED , context ) )
1196
1249
return true;
1197
1250
}
1198
1251
@@ -1207,20 +1260,24 @@ has_parallel_hazard_walker(Node *node, has_parallel_hazard_arg *context)
1207
1260
1208
1261
/* SELECT FOR UPDATE/SHARE must be treated as unsafe */
1209
1262
if (query -> rowMarks != NULL )
1263
+ {
1264
+ context -> max_hazard = PROPARALLEL_UNSAFE ;
1210
1265
return true;
1266
+ }
1211
1267
1212
1268
/* Recurse into subselects */
1213
1269
return query_tree_walker (query ,
1214
- has_parallel_hazard_walker ,
1270
+ max_parallel_hazard_walker ,
1215
1271
context , 0 );
1216
1272
}
1217
1273
1218
1274
/* Recurse to check arguments */
1219
1275
return expression_tree_walker (node ,
1220
- has_parallel_hazard_walker ,
1276
+ max_parallel_hazard_walker ,
1221
1277
context );
1222
1278
}
1223
1279
1280
+
1224
1281
/*****************************************************************************
1225
1282
* Check clauses for nonstrict functions
1226
1283
*****************************************************************************/
0 commit comments