@@ -156,8 +156,8 @@ static PartitionPruneStep *gen_prune_step_op(GeneratePruningStepsContext *contex
156
156
static PartitionPruneStep * gen_prune_step_combine (GeneratePruningStepsContext * context ,
157
157
List * source_stepids ,
158
158
PartitionPruneCombineOp combineOp );
159
- static PartitionPruneStep * gen_prune_steps_from_opexps (GeneratePruningStepsContext * context ,
160
- List * * keyclauses , Bitmapset * nullkeys );
159
+ static List * gen_prune_steps_from_opexps (GeneratePruningStepsContext * context ,
160
+ List * * keyclauses , Bitmapset * nullkeys );
161
161
static PartClauseMatchStatus match_clause_to_partition_key (GeneratePruningStepsContext * context ,
162
162
Expr * clause , Expr * partkey , int partkeyidx ,
163
163
bool * clause_is_not_null ,
@@ -924,22 +924,34 @@ get_matching_partitions(PartitionPruneContext *context, List *pruning_steps)
924
924
925
925
/*
926
926
* gen_partprune_steps_internal
927
- * Processes 'clauses' to generate partition pruning steps.
928
- *
929
- * From OpExpr clauses that are mutually AND'd, we find combinations of those
930
- * that match to the partition key columns and for every such combination,
931
- * we emit a PartitionPruneStepOp containing a vector of expressions whose
932
- * values are used as a look up key to search partitions by comparing the
933
- * values with partition bounds. Relevant details of the operator and a
934
- * vector of (possibly cross-type) comparison functions is also included with
935
- * each step.
936
- *
937
- * For BoolExpr clauses, we recursively generate steps for each argument, and
938
- * return a PartitionPruneStepCombine of their results.
939
- *
940
- * The return value is a list of the steps generated, which are also added to
941
- * the context's steps list. Each step is assigned a step identifier, unique
942
- * even across recursive calls.
927
+ * Processes 'clauses' to generate a List of partition pruning steps. We
928
+ * return NIL when no steps were generated.
929
+ *
930
+ * These partition pruning steps come in 2 forms; operator steps and combine
931
+ * steps.
932
+ *
933
+ * Operator steps (PartitionPruneStepOp) contain details of clauses that we
934
+ * determined that we can use for partition pruning. These contain details of
935
+ * the expression which is being compared to the partition key and the
936
+ * comparison function.
937
+ *
938
+ * Combine steps (PartitionPruneStepCombine) instruct the partition pruning
939
+ * code how it should produce a single set of partitions from multiple input
940
+ * operator and other combine steps. A PARTPRUNE_COMBINE_INTERSECT type
941
+ * combine step will merge its input steps to produce a result which only
942
+ * contains the partitions which are present in all of the input operator
943
+ * steps. A PARTPRUNE_COMBINE_UNION combine step will produce a result that
944
+ * has all of the partitions from each of the input operator steps.
945
+ *
946
+ * For BoolExpr clauses, each argument is processed recursively. Steps
947
+ * generated from processing an OR BoolExpr will be combined using
948
+ * PARTPRUNE_COMBINE_UNION. AND BoolExprs get combined using
949
+ * PARTPRUNE_COMBINE_INTERSECT.
950
+ *
951
+ * Otherwise, the list of clauses we receive we assume to be mutually ANDed.
952
+ * We generate all of the pruning steps we can based on these clauses and then
953
+ * at the end, if we have more than 1 step, we combine each step with a
954
+ * PARTPRUNE_COMBINE_INTERSECT combine step. Single steps are returned as-is.
943
955
*
944
956
* If we find clauses that are mutually contradictory, or contradictory with
945
957
* the partitioning constraint, or a pseudoconstant clause that contains
@@ -1046,11 +1058,16 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1046
1058
1047
1059
if (argsteps != NIL )
1048
1060
{
1049
- PartitionPruneStep * step ;
1061
+ /*
1062
+ * gen_partprune_steps_internal() always adds a single
1063
+ * combine step when it generates multiple steps, so
1064
+ * here we can just pay attention to the last one in
1065
+ * the list. If it just generated one, then the last
1066
+ * one in the list is still the one we want.
1067
+ */
1068
+ PartitionPruneStep * last = llast (argsteps );
1050
1069
1051
- Assert (list_length (argsteps ) == 1 );
1052
- step = (PartitionPruneStep * ) linitial (argsteps );
1053
- arg_stepids = lappend_int (arg_stepids , step -> step_id );
1070
+ arg_stepids = lappend_int (arg_stepids , last -> step_id );
1054
1071
}
1055
1072
else
1056
1073
{
@@ -1089,9 +1106,7 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1089
1106
else if (is_andclause (clause ))
1090
1107
{
1091
1108
List * args = ((BoolExpr * ) clause )-> args ;
1092
- List * argsteps ,
1093
- * arg_stepids = NIL ;
1094
- ListCell * lc1 ;
1109
+ List * argsteps ;
1095
1110
1096
1111
/*
1097
1112
* args may itself contain clauses of arbitrary type, so just
@@ -1104,21 +1119,16 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1104
1119
if (context -> contradictory )
1105
1120
return NIL ;
1106
1121
1107
- foreach (lc1 , argsteps )
1108
- {
1109
- PartitionPruneStep * step = lfirst (lc1 );
1110
-
1111
- arg_stepids = lappend_int (arg_stepids , step -> step_id );
1112
- }
1113
-
1114
- if (arg_stepids != NIL )
1115
- {
1116
- PartitionPruneStep * step ;
1122
+ /*
1123
+ * gen_partprune_steps_internal() always adds a single combine
1124
+ * step when it generates multiple steps, so here we can just
1125
+ * pay attention to the last one in the list. If it just
1126
+ * generated one, then the last one in the list is still the
1127
+ * one we want.
1128
+ */
1129
+ if (argsteps != NIL )
1130
+ result = lappend (result , llast (argsteps ));
1117
1131
1118
- step = gen_prune_step_combine (context , arg_stepids ,
1119
- PARTPRUNE_COMBINE_INTERSECT );
1120
- result = lappend (result , step );
1121
- }
1122
1132
continue ;
1123
1133
}
1124
1134
@@ -1253,12 +1263,11 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1253
1263
}
1254
1264
else if (generate_opsteps )
1255
1265
{
1256
- PartitionPruneStep * step ;
1266
+ List * opsteps ;
1257
1267
1258
1268
/* Strategy 2 */
1259
- step = gen_prune_steps_from_opexps (context , keyclauses , nullkeys );
1260
- if (step != NULL )
1261
- result = lappend (result , step );
1269
+ opsteps = gen_prune_steps_from_opexps (context , keyclauses , nullkeys );
1270
+ result = list_concat (result , opsteps );
1262
1271
}
1263
1272
else if (bms_num_members (notnullkeys ) == part_scheme -> partnatts )
1264
1273
{
@@ -1271,12 +1280,14 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1271
1280
}
1272
1281
1273
1282
/*
1274
- * Finally, results from all entries appearing in result should be
1275
- * combined using an INTERSECT combine step, if more than one.
1283
+ * Finally, if there are multiple steps, since the 'clauses' are mutually
1284
+ * ANDed, add an INTERSECT step to combine the partition sets resulting
1285
+ * from them and append it to the result list.
1276
1286
*/
1277
1287
if (list_length (result ) > 1 )
1278
1288
{
1279
1289
List * step_ids = NIL ;
1290
+ PartitionPruneStep * final ;
1280
1291
1281
1292
foreach (lc , result )
1282
1293
{
@@ -1285,14 +1296,9 @@ gen_partprune_steps_internal(GeneratePruningStepsContext *context,
1285
1296
step_ids = lappend_int (step_ids , step -> step_id );
1286
1297
}
1287
1298
1288
- if (step_ids != NIL )
1289
- {
1290
- PartitionPruneStep * step ;
1291
-
1292
- step = gen_prune_step_combine (context , step_ids ,
1293
- PARTPRUNE_COMBINE_INTERSECT );
1294
- result = lappend (result , step );
1295
- }
1299
+ final = gen_prune_step_combine (context , step_ids ,
1300
+ PARTPRUNE_COMBINE_INTERSECT );
1301
+ result = lappend (result , final );
1296
1302
}
1297
1303
1298
1304
return result ;
@@ -1356,15 +1362,26 @@ gen_prune_step_combine(GeneratePruningStepsContext *context,
1356
1362
1357
1363
/*
1358
1364
* gen_prune_steps_from_opexps
1359
- * Generate pruning steps based on clauses for partition keys
1360
- *
1361
- * 'keyclauses' contains one list of clauses per partition key. We check here
1362
- * if we have found clauses for a valid subset of the partition key. In some
1363
- * cases, (depending on the type of partitioning being used) if we didn't
1364
- * find clauses for a given key, we discard clauses that may have been
1365
- * found for any subsequent keys; see specific notes below.
1365
+ * Generate and return a list of PartitionPruneStepOp that are based on
1366
+ * OpExpr and BooleanTest clauses that have been matched to the partition
1367
+ * key.
1368
+ *
1369
+ * 'keyclauses' is an array of List pointers, indexed by the partition key's
1370
+ * index. Each List element in the array can contain clauses that match to
1371
+ * the corresponding partition key column. Partition key columns without any
1372
+ * matched clauses will have an empty List.
1373
+ *
1374
+ * Some partitioning strategies allow pruning to still occur when we only have
1375
+ * clauses for a prefix of the partition key columns, for example, RANGE
1376
+ * partitioning. Other strategies, such as HASH partitioning, require clauses
1377
+ * for all partition key columns.
1378
+ *
1379
+ * When we return multiple pruning steps here, it's up to the caller to add a
1380
+ * relevant "combine" step to combine the returned steps. This is not done
1381
+ * here as callers may wish to include additional pruning steps before
1382
+ * combining them all.
1366
1383
*/
1367
- static PartitionPruneStep *
1384
+ static List *
1368
1385
gen_prune_steps_from_opexps (GeneratePruningStepsContext * context ,
1369
1386
List * * keyclauses , Bitmapset * nullkeys )
1370
1387
{
@@ -1397,7 +1414,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
1397
1414
*/
1398
1415
if (part_scheme -> strategy == PARTITION_STRATEGY_HASH &&
1399
1416
clauselist == NIL && !bms_is_member (i , nullkeys ))
1400
- return NULL ;
1417
+ return NIL ;
1401
1418
1402
1419
foreach (lc , clauselist )
1403
1420
{
@@ -1728,27 +1745,7 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
1728
1745
break ;
1729
1746
}
1730
1747
1731
- /* Lastly, add a combine step to mutually AND these op steps, if needed */
1732
- if (list_length (opsteps ) > 1 )
1733
- {
1734
- List * opstep_ids = NIL ;
1735
-
1736
- foreach (lc , opsteps )
1737
- {
1738
- PartitionPruneStep * step = lfirst (lc );
1739
-
1740
- opstep_ids = lappend_int (opstep_ids , step -> step_id );
1741
- }
1742
-
1743
- if (opstep_ids != NIL )
1744
- return gen_prune_step_combine (context , opstep_ids ,
1745
- PARTPRUNE_COMBINE_INTERSECT );
1746
- return NULL ;
1747
- }
1748
- else if (opsteps != NIL )
1749
- return linitial (opsteps );
1750
-
1751
- return NULL ;
1748
+ return opsteps ;
1752
1749
}
1753
1750
1754
1751
/*
@@ -1782,8 +1779,8 @@ gen_prune_steps_from_opexps(GeneratePruningStepsContext *context,
1782
1779
* true otherwise.
1783
1780
*
1784
1781
* * PARTCLAUSE_MATCH_STEPS if there is a match.
1785
- * Output arguments: *clause_steps is set to a list of PartitionPruneStep
1786
- * generated for the clause.
1782
+ * Output arguments: *clause_steps is set to the list of recursively
1783
+ * generated steps for the clause.
1787
1784
*
1788
1785
* * PARTCLAUSE_MATCH_CONTRADICT if the clause is self-contradictory, ie
1789
1786
* it provably returns FALSE or NULL.
0 commit comments