@@ -66,7 +66,9 @@ static bool infer_collation_opclass_match(InferenceElem *elem, Relation idxRel,
66
66
static int32 get_rel_data_width (Relation rel , int32 * attr_widths );
67
67
static List * get_relation_constraints (PlannerInfo * root ,
68
68
Oid relationObjectId , RelOptInfo * rel ,
69
- bool include_notnull );
69
+ bool include_noinherit ,
70
+ bool include_notnull ,
71
+ bool include_partition );
70
72
static List * build_index_tlist (PlannerInfo * root , IndexOptInfo * index ,
71
73
Relation heapRelation );
72
74
static List * get_relation_statistics (RelOptInfo * rel , Relation relation );
@@ -1157,24 +1159,32 @@ get_relation_data_width(Oid relid, int32 *attr_widths)
1157
1159
/*
1158
1160
* get_relation_constraints
1159
1161
*
1160
- * Retrieve the validated CHECK constraint expressions of the given relation.
1162
+ * Retrieve the applicable constraint expressions of the given relation.
1161
1163
*
1162
1164
* Returns a List (possibly empty) of constraint expressions. Each one
1163
1165
* has been canonicalized, and its Vars are changed to have the varno
1164
1166
* indicated by rel->relid. This allows the expressions to be easily
1165
1167
* compared to expressions taken from WHERE.
1166
1168
*
1169
+ * If include_noinherit is true, it's okay to include constraints that
1170
+ * are marked NO INHERIT.
1171
+ *
1167
1172
* If include_notnull is true, "col IS NOT NULL" expressions are generated
1168
1173
* and added to the result for each column that's marked attnotnull.
1169
1174
*
1175
+ * If include_partition is true, and the relation is a partition,
1176
+ * also include the partitioning constraints.
1177
+ *
1170
1178
* Note: at present this is invoked at most once per relation per planner
1171
1179
* run, and in many cases it won't be invoked at all, so there seems no
1172
1180
* point in caching the data in RelOptInfo.
1173
1181
*/
1174
1182
static List *
1175
1183
get_relation_constraints (PlannerInfo * root ,
1176
1184
Oid relationObjectId , RelOptInfo * rel ,
1177
- bool include_notnull )
1185
+ bool include_noinherit ,
1186
+ bool include_notnull ,
1187
+ bool include_partition )
1178
1188
{
1179
1189
List * result = NIL ;
1180
1190
Index varno = rel -> relid ;
@@ -1198,10 +1208,13 @@ get_relation_constraints(PlannerInfo *root,
1198
1208
1199
1209
/*
1200
1210
* If this constraint hasn't been fully validated yet, we must
1201
- * ignore it here.
1211
+ * ignore it here. Also ignore if NO INHERIT and we weren't told
1212
+ * that that's safe.
1202
1213
*/
1203
1214
if (!constr -> check [i ].ccvalid )
1204
1215
continue ;
1216
+ if (constr -> check [i ].ccnoinherit && !include_noinherit )
1217
+ continue ;
1205
1218
1206
1219
cexpr = stringToNode (constr -> check [i ].ccbin );
1207
1220
@@ -1266,13 +1279,9 @@ get_relation_constraints(PlannerInfo *root,
1266
1279
}
1267
1280
1268
1281
/*
1269
- * Append partition predicates, if any.
1270
- *
1271
- * For selects, partition pruning uses the parent table's partition bound
1272
- * descriptor, instead of constraint exclusion which is driven by the
1273
- * individual partition's partition constraint.
1282
+ * Add partitioning constraints, if requested.
1274
1283
*/
1275
- if (enable_partition_pruning && root -> parse -> commandType != CMD_SELECT )
1284
+ if (include_partition && relation -> rd_rel -> relispartition )
1276
1285
{
1277
1286
List * pcqual = RelationGetPartitionQual (relation );
1278
1287
@@ -1377,7 +1386,7 @@ get_relation_statistics(RelOptInfo *rel, Relation relation)
1377
1386
*
1378
1387
* Detect whether the relation need not be scanned because it has either
1379
1388
* self-inconsistent restrictions, or restrictions inconsistent with the
1380
- * relation's validated CHECK constraints.
1389
+ * relation's applicable constraints.
1381
1390
*
1382
1391
* Note: this examines only rel->relid, rel->reloptkind, and
1383
1392
* rel->baserestrictinfo; therefore it can be called before filling in
@@ -1387,6 +1396,9 @@ bool
1387
1396
relation_excluded_by_constraints (PlannerInfo * root ,
1388
1397
RelOptInfo * rel , RangeTblEntry * rte )
1389
1398
{
1399
+ bool include_noinherit ;
1400
+ bool include_notnull ;
1401
+ bool include_partition = false;
1390
1402
List * safe_restrictions ;
1391
1403
List * constraint_pred ;
1392
1404
List * safe_constraints ;
@@ -1395,6 +1407,13 @@ relation_excluded_by_constraints(PlannerInfo *root,
1395
1407
/* As of now, constraint exclusion works only with simple relations. */
1396
1408
Assert (IS_SIMPLE_REL (rel ));
1397
1409
1410
+ /*
1411
+ * If there are no base restriction clauses, we have no hope of proving
1412
+ * anything below, so fall out quickly.
1413
+ */
1414
+ if (rel -> baserestrictinfo == NIL )
1415
+ return false;
1416
+
1398
1417
/*
1399
1418
* Regardless of the setting of constraint_exclusion, detect
1400
1419
* constant-FALSE-or-NULL restriction clauses. Because const-folding will
@@ -1415,6 +1434,17 @@ relation_excluded_by_constraints(PlannerInfo *root,
1415
1434
return true;
1416
1435
}
1417
1436
1437
+ /*
1438
+ * Partition pruning will not have been applied to an inherited target
1439
+ * relation, so if enable_partition_pruning is true, force consideration
1440
+ * of the rel's partition constraints. (Thus constraint_exclusion will be
1441
+ * effectively forced 'on' for this case. This is done better in v12.)
1442
+ */
1443
+ if (enable_partition_pruning &&
1444
+ rel -> relid == root -> parse -> resultRelation &&
1445
+ root -> inhTargetKind != INHKIND_NONE )
1446
+ include_partition = true;
1447
+
1418
1448
/*
1419
1449
* Skip further tests, depending on constraint_exclusion.
1420
1450
*/
@@ -1423,33 +1453,43 @@ relation_excluded_by_constraints(PlannerInfo *root,
1423
1453
case CONSTRAINT_EXCLUSION_OFF :
1424
1454
1425
1455
/*
1426
- * Don't prune if feature turned off -- except if the relation is
1427
- * a partition. While partprune.c-style partition pruning is not
1428
- * yet in use for all cases (update/delete is not handled), it
1429
- * would be a UI horror to use different user-visible controls
1430
- * depending on such a volatile implementation detail. Therefore,
1431
- * for partitioned tables we use enable_partition_pruning to
1432
- * control this behavior.
1456
+ * In 'off' mode, never make any further tests, except if forcing
1457
+ * include_partition.
1433
1458
*/
1434
- if (root -> inhTargetKind == INHKIND_PARTITIONED )
1459
+ if (include_partition )
1435
1460
break ;
1436
1461
return false;
1437
1462
1438
1463
case CONSTRAINT_EXCLUSION_PARTITION :
1439
1464
1440
1465
/*
1441
1466
* When constraint_exclusion is set to 'partition' we only handle
1442
- * OTHER_MEMBER_RELs, or BASERELs in cases where the result target
1443
- * is an inheritance parent or a partitioned table.
1467
+ * appendrel members. Normally, they are RELOPT_OTHER_MEMBER_REL
1468
+ * relations, but we also consider inherited target relations as
1469
+ * appendrel members for the purposes of constraint exclusion.
1470
+ *
1471
+ * In the former case, partition pruning was already applied, so
1472
+ * there is no need to consider the rel's partition constraints
1473
+ * here. In the latter case, we already set include_partition
1474
+ * properly (i.e., do it if enable_partition_pruning).
1444
1475
*/
1445
- if ((rel -> reloptkind != RELOPT_OTHER_MEMBER_REL ) &&
1446
- !(rel -> reloptkind == RELOPT_BASEREL &&
1447
- root -> inhTargetKind != INHKIND_NONE &&
1448
- rel -> relid == root -> parse -> resultRelation ))
1449
- return false;
1450
- break ;
1476
+ if (rel -> reloptkind == RELOPT_OTHER_MEMBER_REL ||
1477
+ (rel -> relid == root -> parse -> resultRelation &&
1478
+ root -> inhTargetKind != INHKIND_NONE ))
1479
+ break ; /* appendrel member, so process it */
1480
+ return false;
1451
1481
1452
1482
case CONSTRAINT_EXCLUSION_ON :
1483
+
1484
+ /*
1485
+ * In 'on' mode, always apply constraint exclusion. If we are
1486
+ * considering a baserel that is a partition (i.e., it was
1487
+ * directly named rather than expanded from a parent table), then
1488
+ * its partition constraints haven't been considered yet, so
1489
+ * include them in the processing here.
1490
+ */
1491
+ if (rel -> reloptkind == RELOPT_BASEREL )
1492
+ include_partition = true;
1453
1493
break ; /* always try to exclude */
1454
1494
}
1455
1495
@@ -1478,24 +1518,40 @@ relation_excluded_by_constraints(PlannerInfo *root,
1478
1518
return true;
1479
1519
1480
1520
/*
1481
- * Only plain relations have constraints. In a partitioning hierarchy,
1482
- * but not with regular table inheritance, it's OK to assume that any
1483
- * constraints that hold for the parent also hold for every child; for
1484
- * instance, table inheritance allows the parent to have constraints
1485
- * marked NO INHERIT, but table partitioning does not. We choose to check
1486
- * whether the partitioning parents can be excluded here; doing so
1487
- * consumes some cycles, but potentially saves us the work of excluding
1488
- * each child individually.
1521
+ * Only plain relations have constraints, so stop here for other rtekinds.
1522
+ */
1523
+ if (rte -> rtekind != RTE_RELATION )
1524
+ return false;
1525
+
1526
+ /*
1527
+ * In a partitioning hierarchy, but not with regular table inheritance,
1528
+ * it's OK to assume that any constraints that hold for the parent also
1529
+ * hold for every child; for instance, table inheritance allows the parent
1530
+ * to have constraints marked NO INHERIT, but table partitioning does not.
1531
+ * We choose to check whether the partitioning parents can be excluded
1532
+ * here; doing so consumes some cycles, but potentially saves us the work
1533
+ * of excluding each child individually.
1534
+ *
1535
+ * This is unnecessarily stupid, but making it smarter seems out of scope
1536
+ * for v11.
1489
1537
*/
1490
- if (rte -> rtekind != RTE_RELATION ||
1491
- (rte -> inh && rte -> relkind != RELKIND_PARTITIONED_TABLE ))
1538
+ if (rte -> inh && rte -> relkind != RELKIND_PARTITIONED_TABLE )
1492
1539
return false;
1493
1540
1494
1541
/*
1495
- * OK to fetch the constraint expressions. Include "col IS NOT NULL"
1496
- * expressions for attnotnull columns, in case we can refute those.
1542
+ * Given the above restriction, we can always include NO INHERIT and NOT
1543
+ * NULL constraints.
1544
+ */
1545
+ include_noinherit = true;
1546
+ include_notnull = true;
1547
+
1548
+ /*
1549
+ * Fetch the appropriate set of constraint expressions.
1497
1550
*/
1498
- constraint_pred = get_relation_constraints (root , rte -> relid , rel , true);
1551
+ constraint_pred = get_relation_constraints (root , rte -> relid , rel ,
1552
+ include_noinherit ,
1553
+ include_notnull ,
1554
+ include_partition );
1499
1555
1500
1556
/*
1501
1557
* We do not currently enforce that CHECK constraints contain only
0 commit comments