get_partitions_excluded_by.patch
application/octet-stream
Filename: get_partitions_excluded_by.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
| File | + | − |
|---|---|---|
| src/backend/catalog/partition.c | 73 | 124 |
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index 0d9c774..57ea4a7 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -291,8 +291,8 @@ PG_FUNCTION_INFO_V1(satisfies_hash_partition);
static Bitmapset *get_partitions_from_clauses_recurse(Relation relation,
int rt_index, List *clauses);
-static Bitmapset *get_partitions_from_ne_clauses(Relation relation,
- List *ne_clauses);
+static Bitmapset *get_partitions_excluded_by(Relation relation,
+ List *ne_clauses);
static Bitmapset *get_partitions_from_or_clause_args(Relation relation,
int rt_index, List *or_clause_args);
static bool classify_partition_bounding_keys(Relation relation, List *clauses,
@@ -1787,15 +1787,10 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
{
Bitmapset *ne_clause_parts;
- ne_clause_parts = get_partitions_from_ne_clauses(relation, ne_clauses);
+ ne_clause_parts = get_partitions_excluded_by(relation, ne_clauses);
- /*
- * Clauses in ne_clauses are in conjunction with the clauses that
- * selected the partitions contained in result, so combine the
- * partitions thus selected with those in result using set
- * intersection.
- */
- result = bms_int_members(result, ne_clause_parts);
+ /* Remove any matched partitions */
+ result = bms_del_members(result, ne_clause_parts);
bms_free(ne_clause_parts);
}
@@ -1825,151 +1820,105 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
(0 == DatumGetInt32(FunctionCall2Coll(&partkey->partsupfunc[0],\
partkey->partcollation[0],\
(d1), (d2))))
-/*
- * Check if d is equal to some member of darray where equality is determined
- * by the partitioning comparison function.
- */
-static bool
-datum_in_array(PartitionKey partkey, Datum d, Datum *darray, int n)
-{
- int i;
-
- if (darray == NULL || n == 0)
- return false;
-
- for (i = 0; i < n; i++)
- if (partkey_datums_equal(d, darray[i]))
- return true;
-
- return false;
-}
-
-/*
- * count_partition_datums
- *
- * Returns the number of non-null datums allowed by a non-default list
- * partition with given index.
- */
-static int
-count_partition_datums(Relation rel, int index)
-{
- PartitionBoundInfo boundinfo = RelationGetPartitionDesc(rel)->boundinfo;
- int i,
- result = 0;
-
- Assert(index != boundinfo->default_index);
-
- /*
- * The answer is as many as the count of occurrence of the value index
- * in boundinfo->indexes[].
- */
- for (i = 0; i < boundinfo->ndatums; i++)
- if (index == boundinfo->indexes[i])
- result += 1;
-
- return result;
-}
/*
- * get_partitions_from_ne_clauses
+ * get_partitions_excluded_by
*
- * Return partitions of relation that satisfy all <> operator clauses in
- * ne_clauses. Only ever called if relation is a list partitioned table.
+ * Returns a Bitmapset of partition indexes of any partition that can safely
+ * be removed due to 'ne_clauses' containing not-equal clauses for all
+ * possible values that the partition can contain.
*/
static Bitmapset *
-get_partitions_from_ne_clauses(Relation relation, List *ne_clauses)
+get_partitions_excluded_by(Relation relation, List *ne_clauses)
{
- ListCell *lc;
- Bitmapset *result,
- *excluded_parts;
- PartitionKey partkey = RelationGetPartitionKey(relation);
- PartitionDesc partdesc = RelationGetPartitionDesc(relation);
+ ListCell *lc;
+ Bitmapset *excluded_parts = NULL;
+ Bitmapset *foundoffsets = NULL;
+ PartitionKey partkey = RelationGetPartitionKey(relation);
+ PartitionDesc partdesc = RelationGetPartitionDesc(relation);
PartitionBoundInfo boundinfo = partdesc->boundinfo;
- Datum *exclude_datums;
- int *count_excluded,
- n_exclude_datums,
- i;
+ PartitionBoundCmpArg arg;
+ int *datums_in_part;
+ int *datums_found;
+ int i;
Assert(partkey->strategy == PARTITION_STRATEGY_LIST);
+ Assert(partkey->partnatts == 1);
- /*
- * How this works:
- *
- * For each constant expression, we look up the partition that would
- * contain its value and mark the same as excluded partition. After
- * doing the same for all clauses we'll have set of partitions that
- * are excluded. For each excluded partition, check if there exist
- * values that it allows but are not specified in the clauses, if so
- * the partition won't actually be excluded.
- */
+ memset(&arg, 0, sizeof(arg));
- /* De-duplicate constant values. */
- exclude_datums = (Datum *) palloc0(list_length(ne_clauses) *
- sizeof(Datum));
- n_exclude_datums = 0;
+ /* build a Bitmapset to record the offsets of all datums found */
foreach(lc, ne_clauses)
{
- PartClause *pc = lfirst(lc);
+ PartClause *pc = (PartClause *) lfirst(lc);
Datum datum;
- if (partkey_datum_from_expr(partkey, 0, pc->constarg, &datum) &&
- !datum_in_array(partkey, datum, exclude_datums, n_exclude_datums))
- exclude_datums[n_exclude_datums++] = datum;
+ if (partkey_datum_from_expr(partkey, 0, pc->constarg, &datum))
+ {
+ int offset;
+ bool is_equal;
+
+ arg.datums = &datum;
+ arg.ndatums = 1;
+ offset = partition_bound_bsearch(partkey, boundinfo, &arg,
+ &is_equal);
+
+ if (offset >= 0 && is_equal && boundinfo->indexes[offset] >= 0)
+ foundoffsets = bms_add_member(foundoffsets, offset);
+ }
}
+ /* No partitions can be excluded if we found no valid offsets above */
+ if (bms_is_empty(foundoffsets))
+ return NULL;
+
/*
- * For each value, if it's found in boundinfo, increment the count of its
- * partition as excluded due to that value.
+ * Since each list partition can have multiple values in the IN clause, we
+ * must ensure that we got all values in that clause before we can
+ * eliminate the entire partition.
+ *
+ * We'll need two arrays for this, one to count the number of unique
+ * datums we found, and another to record the number of datums permitted
+ * in each partition. Once we've counted all this, we can eliminate any
+ * partition where the number of datums found match the number of datums
+ * allowed in the partition.
*/
- count_excluded = (int *) palloc0(partdesc->nparts * sizeof(int));
- for (i = 0; i < n_exclude_datums; i++)
- {
- int offset,
- excluded_part;
- bool is_equal;
- PartitionBoundCmpArg arg;
- Datum argdatums[] = {exclude_datums[i]};
-
- memset(&arg, 0, sizeof(arg));
- arg.datums = argdatums;
- arg.ndatums = 1;
- offset = partition_bound_bsearch(partkey, boundinfo, &arg, &is_equal);
- if (offset >= 0 && is_equal && boundinfo->indexes[offset] >= 0)
- {
- excluded_part = boundinfo->indexes[offset];
- count_excluded[excluded_part]++;
- }
- }
+ datums_in_part = (int *) palloc0(sizeof(int) * partdesc->nparts);
+ datums_found = (int *) palloc0(sizeof(int) * partdesc->nparts);
- excluded_parts = NULL;
+ i = -1;
+ while ((i = bms_next_member(foundoffsets, i)) >= 0)
+ datums_found[boundinfo->indexes[i]]++;
+
+ /* Now, in a single pass of the partitions, count the datums it permits */
+ for (i = 0; i < boundinfo->ndatums; i++)
+ datums_in_part[boundinfo->indexes[i]]++;
+
+ /*
+ * Compare the counts, eliminate any partition that we found clause for
+ * all possible values. We must be careful here not to include any default
+ * partition. In this case both arrays will contain zero, so we can just
+ * simply ensure we only eliminate when we found at least 1 datum.
+ */
for (i = 0; i < partdesc->nparts; i++)
{
- /*
- * If all datums of this partition appeared in ne_clauses, exclude
- * this partition.
- */
- if (count_excluded[i] > 0 &&
- count_excluded[i] == count_partition_datums(relation, i))
+ if (datums_found[i] >= datums_in_part[i] && datums_found[i] > 0)
excluded_parts = bms_add_member(excluded_parts, i);
}
/*
- * Also, exclude the "null-only" partition, because strict clauses in
- * ne_clauses will not select any rows from it.
+ * Because the above clauses are strict, we can also exclude the NULL
+ * partition providing it does not also allow non-NULL values.
*/
if (partition_bound_accepts_nulls(boundinfo) &&
- count_partition_datums(relation, boundinfo->null_index) == 0)
+ datums_in_part[boundinfo->null_index] == 0)
excluded_parts = bms_add_member(excluded_parts,
boundinfo->null_index);
- pfree(count_excluded);
- pfree(exclude_datums);
-
- result = bms_add_range(NULL, 0, partdesc->nparts - 1);
- result = bms_del_members(result, excluded_parts);
- bms_free(excluded_parts);
+ pfree(datums_in_part);
+ pfree(datums_found);
- return result;
+ return excluded_parts;
}
/*
@@ -2251,7 +2200,7 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
/*
* We don't turn a <> operator clause into a key right away.
* Instead, the caller will hand over such clauses to
- * get_partitions_from_ne_clauses().
+ * get_partitions_excluded_by().
*/
if (is_ne_listp)
*ne_clauses = lappend(*ne_clauses, pc);