0003-WIP-Implement-get_partitions_for_keys.patch
text/plain
Filename: 0003-WIP-Implement-get_partitions_for_keys.patch
Type: text/plain
Part: 2
Patch
Format: format-patch
Series: patch 0003
Subject: WIP: Implement get_partitions_for_keys()
| File | + | − |
|---|---|---|
| src/backend/catalog/partition.c | 205 | 5 |
| src/backend/optimizer/util/plancat.c | 4 | 0 |
From b39fe19609c4cdec4961455540cef50beebce33a Mon Sep 17 00:00:00 2001
From: amit <amitlangote09@gmail.com>
Date: Tue, 22 Aug 2017 13:48:13 +0900
Subject: [PATCH 3/4] WIP: Implement get_partitions_for_keys()
Disable constraint exclusion that occurs using internal partition
constraints, so that it's apparent what the new partition-pruning
code still needs to do to able to create a plan matching the plain
the the traditional constraint exclusion based partition-pruning
would result in.
---
src/backend/catalog/partition.c | 210 ++++++++++++++++++++++++++++++++++-
src/backend/optimizer/util/plancat.c | 4 +
2 files changed, 209 insertions(+), 5 deletions(-)
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 0133748234..9d4b7c1a7f 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -1391,8 +1391,6 @@ get_partition_dispatch_recurse(Relation rel, Relation parent,
* datum that the query's bounding keys allow to be returned for the query.
* Similarly, *max_datum_index. *null_partition_chosen returns whether
* the null partition will be scanned.
- *
- * TODO: Implement.
*/
List *
get_partitions_for_keys(Relation rel,
@@ -1403,12 +1401,214 @@ get_partitions_for_keys(Relation rel,
bool *null_partition_chosen,
bool *default_partition_chosen)
{
+ int i,
+ minoff,
+ maxoff;
List *result = NIL;
- int i;
+ PartitionKey partkey = RelationGetPartitionKey(rel);
PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+ PartitionBoundCmpArg arg;
+ bool is_equal,
+ scan_default = false;
+ int null_partition_idx = partdesc->boundinfo->null_index;
- for (i = 0; i < partdesc->nparts; i++)
- result = lappend_int(result, i);
+ *null_partition_chosen = false;
+
+ /*
+ * Check if any of the scan keys are null. If so, return the only
+ * null-accepting partition if partdesc->boundinfo says there is one.
+ */
+ for (i = 0; i < partkey->partnatts; i++)
+ {
+ if (keynullness[i] == IS_NULL)
+ {
+ if (null_partition_idx >= 0)
+ {
+ *null_partition_chosen = true;
+ result = list_make1_int(null_partition_idx);
+ }
+ else
+ result = NIL;
+
+ return result;
+ }
+ }
+
+ /*
+ * If query provides no quals, don't forget to scan the default partition.
+ */
+ if (n_minkeys == 0 && n_maxkeys == 0)
+ scan_default = true;
+
+ if (n_minkeys > 0 && partdesc->nparts > 0)
+ {
+ memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+ arg.datums = minkeys;
+ arg.ndatums = n_minkeys;
+ minoff = partition_bound_bsearch(partkey, partdesc->boundinfo,
+ &arg, &is_equal);
+
+ if (is_equal && arg.ndatums < partkey->partnatts)
+ {
+ int32 cmpval;
+
+ is_equal = false;
+
+ do
+ {
+ if (min_inclusive)
+ minoff -= 1;
+ else
+ minoff += 1;
+ if (minoff < 0 ||
+ minoff >= partdesc->boundinfo->ndatums)
+ break;
+ cmpval = partition_bound_cmp(partkey, partdesc->boundinfo,
+ minoff, &arg);
+ } while (cmpval == 0);
+ }
+
+ /* Interpret the result per partition strategy. */
+ switch (partkey->strategy)
+ {
+ case PARTITION_STRATEGY_LIST:
+ /*
+ * Found, but if the query may have asked us to exclude it.
+ */
+ if (is_equal && !min_inclusive)
+ minoff++;
+ break;
+
+ case PARTITION_STRATEGY_RANGE:
+ /*
+ * Records returned by the query will be > bounds[minoff],
+ * because min_scankey is >= bounds[minoff], that is, no
+ * records of the partition at minoff will be returned. Go
+ * to the next bound.
+ */
+ if (minoff < partdesc->boundinfo->ndatums - 1)
+ minoff += 1;
+
+ /*
+ * Make sure to skip a gap.
+ * Note: There are ndatums + 1 lots in the indexes array.
+ */
+ if (partdesc->boundinfo->indexes[minoff] < 0 &&
+ partdesc->boundinfo->indexes[minoff + 1] >= 0)
+ minoff += 1;
+ break;
+ }
+ }
+ else
+ minoff = 0;
+
+ if (n_maxkeys > 0 && partdesc->nparts > 0)
+ {
+ memset(&arg, 0, sizeof(PartitionBoundCmpArg));
+ arg.datums = maxkeys;
+ arg.ndatums = n_maxkeys;
+ maxoff = partition_bound_bsearch(partkey, partdesc->boundinfo,
+ &arg, &is_equal);
+ if (is_equal && arg.ndatums < partkey->partnatts)
+ {
+ int32 cmpval;
+
+ is_equal = false;
+
+ do
+ {
+ if (max_inclusive)
+ maxoff += 1;
+ else
+ maxoff -= 1;
+ if (maxoff < 0 ||
+ maxoff >= partdesc->boundinfo->ndatums)
+ break;
+ cmpval = partition_bound_cmp(partkey, partdesc->boundinfo,
+ maxoff, &arg);
+ } while (cmpval == 0);
+
+ /* Back up if went too far. */
+ if (max_inclusive)
+ maxoff -= 1;
+ }
+
+ /* Interpret the result per partition strategy. */
+ switch (partkey->strategy)
+ {
+ case PARTITION_STRATEGY_LIST:
+ /*
+ * Found, but if the query may have asked us to exclude it.
+ */
+ if (is_equal && !max_inclusive)
+ maxoff--;
+ break;
+
+ case PARTITION_STRATEGY_RANGE:
+ /*
+ * Because bounds[maxoff] <= max_scankey, we may need to
+ * to consider the next partition as well, in addition to
+ * the partition at maxoff and earlier.
+ */
+ if (!is_equal || max_inclusive)
+ maxoff += 1;
+
+ /* Make sure to skip a gap. */
+ if (partdesc->boundinfo->indexes[maxoff] < 0 && maxoff >= 1)
+ maxoff -= 1;
+ break;
+ }
+ }
+ else
+ maxoff = partdesc->boundinfo->ndatums - 1;
+
+ *min_datum_index = minoff;
+ *max_datum_index = maxoff;
+
+ switch (partkey->strategy)
+ {
+ case PARTITION_STRATEGY_LIST:
+ for (i = minoff; i <= maxoff; i++)
+ {
+ int partition_idx = partdesc->boundinfo->indexes[i];
+
+ /*
+ * Multiple values may belong to the same partition, so make
+ * sure we don't add the same partition index again.
+ */
+ result = list_append_unique_int(result, partition_idx);
+ }
+
+ /* If no bounding keys exist, include the null partition too. */
+ if (null_partition_idx >= 0 &&
+ (keynullness[0] == -1 || keynullness[0] != IS_NOT_NULL))
+ {
+ *null_partition_chosen = true;
+ result = list_append_unique_int(result, null_partition_idx);
+ }
+
+ break;
+
+ case PARTITION_STRATEGY_RANGE:
+ for (i = minoff; i <= maxoff; i++)
+ {
+ int partition_idx = partdesc->boundinfo->indexes[i];
+
+ /*
+ * If a valid partition exists for this range, add its
+ * index, if not, the default partition (if any) would be
+ * covering that range, so request to include the same.
+ */
+ if (partition_idx >= 0)
+ result = lappend_int(result, partition_idx);
+ else
+ scan_default = true;
+ }
+ break;
+ }
+
+ if (scan_default && partdesc->boundinfo->default_index >= 0)
+ result = lappend_int(result, partdesc->boundinfo->default_index);
return result;
}
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index 49578c0684..ef84dac7f2 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -1160,7 +1160,9 @@ get_relation_constraints(PlannerInfo *root,
Index varno = rel->relid;
Relation relation;
TupleConstr *constr;
+#ifdef USE_PARTITION_CONSTRAINT_FOR_PRUNING
List *pcqual;
+#endif
/*
* We assume the relation has already been safely locked.
@@ -1246,6 +1248,7 @@ get_relation_constraints(PlannerInfo *root,
}
}
+#ifdef USE_PARTITION_CONSTRAINT_FOR_PRUNING
/* Append partition predicates, if any */
pcqual = RelationGetPartitionQual(relation);
if (pcqual)
@@ -1263,6 +1266,7 @@ get_relation_constraints(PlannerInfo *root,
result = list_concat(result, pcqual);
}
+#endif
heap_close(relation, NoLock);
--
2.11.0