aboutsummaryrefslogtreecommitdiff
path: root/src/backend/partitioning/partbounds.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/backend/partitioning/partbounds.c')
-rw-r--r--src/backend/partitioning/partbounds.c901
1 files changed, 2 insertions, 899 deletions
diff --git a/src/backend/partitioning/partbounds.c b/src/backend/partitioning/partbounds.c
index 4eda59767ce..c28639d2e3f 100644
--- a/src/backend/partitioning/partbounds.c
+++ b/src/backend/partitioning/partbounds.c
@@ -3214,9 +3214,8 @@ check_new_partition_bound(char *relname, Relation parent,
PartitionRangeDatum *datum;
/*
- * Point to problematic key in the list of lower
- * datums; if we have equality, point to the first
- * one.
+ * Point to problematic key in the lower datums list;
+ * if we have equality, point to the first one.
*/
datum = cmpval == 0 ? linitial(spec->lowerdatums) :
list_nth(spec->lowerdatums, abs(cmpval) - 1);
@@ -4978,899 +4977,3 @@ satisfies_hash_partition(PG_FUNCTION_ARGS)
PG_RETURN_BOOL(rowHash % modulus == remainder);
}
-
-/*
- * check_two_partitions_bounds_range
- *
- * (function for BY RANGE partitioning)
- *
- * This is a helper function for check_partitions_for_split() and
- * calculate_partition_bound_for_merge().
- * This function compares upper bound of first_bound and lower bound of
- * second_bound. These bounds should be equal except when
- * "defaultPart == true" (this means that one of split partitions is DEFAULT).
- * In this case upper bound of first_bound can be less than lower bound of
- * second_bound because space between these bounds will be included in
- * DEFAULT partition.
- *
- * parent: partitioned table
- * first_name: name of first partition
- * first_bound: bound of first partition
- * second_name: name of second partition
- * second_bound: bound of second partition
- * defaultPart: true if one of split partitions is DEFAULT
- * pstate: pointer to ParseState struct for determining error position
- */
-static void
-check_two_partitions_bounds_range(Relation parent,
- RangeVar *first_name,
- PartitionBoundSpec *first_bound,
- RangeVar *second_name,
- PartitionBoundSpec *second_bound,
- bool defaultPart,
- ParseState *pstate)
-{
- PartitionKey key = RelationGetPartitionKey(parent);
- PartitionRangeBound *first_upper;
- PartitionRangeBound *second_lower;
- int cmpval;
-
- Assert(key->strategy == PARTITION_STRATEGY_RANGE);
-
- first_upper = make_one_partition_rbound(key, -1, first_bound->upperdatums, false);
- second_lower = make_one_partition_rbound(key, -1, second_bound->lowerdatums, true);
-
- /*
- * lower1=false (the second to last argument) for correct comparison of
- * lower and upper bounds.
- */
- cmpval = partition_rbound_cmp(key->partnatts,
- key->partsupfunc,
- key->partcollation,
- second_lower->datums, second_lower->kind,
- false, first_upper);
- if ((!defaultPart && cmpval) || (defaultPart && cmpval < 0))
- {
- PartitionRangeDatum *datum = linitial(second_bound->lowerdatums);
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("lower bound of partition \"%s\" conflicts with upper bound of previous partition \"%s\"",
- second_name->relname, first_name->relname),
- parser_errposition(pstate, datum->location)));
- }
-}
-
-/*
- * check_partitions_not_overlap_list
- *
- * (function for BY LIST partitioning)
- *
- * This is a helper function for check_partitions_for_split().
- * Checks that the values of the new partitions do not overlap.
- *
- * parent: partitioned table
- * parts: array of SinglePartitionSpec structs with info about split partitions
- * nparts: size of array "parts"
- */
-static void
-check_partitions_not_overlap_list(Relation parent,
- SinglePartitionSpec **parts,
- int nparts,
- ParseState *pstate)
-{
- PartitionKey key PG_USED_FOR_ASSERTS_ONLY = RelationGetPartitionKey(parent);
- int overlap_location = -1;
- int i,
- j;
- SinglePartitionSpec *sps1,
- *sps2;
- List *overlap;
-
- Assert(key->strategy == PARTITION_STRATEGY_LIST);
-
- for (i = 0; i < nparts; i++)
- {
- sps1 = parts[i];
-
- for (j = i + 1; j < nparts; j++)
- {
- sps2 = parts[j];
-
- /*
- * Calculate intersection between values of two partitions.
- */
- overlap = list_intersection(sps1->bound->listdatums,
- sps2->bound->listdatums);
- if (list_length(overlap) > 0)
- {
- Const *val = (Const *) lfirst(list_head(overlap));
-
- overlap_location = val->location;
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partition \"%s\" would overlap with another new partition \"%s\"",
- sps1->name->relname, sps2->name->relname),
- parser_errposition(pstate, overlap_location)));
- }
- }
- }
-}
-
-/*
- * get_partition_bound_spec
- *
- * Returns description of partition with Oid "partOid" and name "name".
- *
- * partOid: partition Oid
- * name: partition name
- */
-static PartitionBoundSpec *
-get_partition_bound_spec(Oid partOid, RangeVar *name)
-{
- HeapTuple tuple;
- Datum datum;
- bool isnull;
- PartitionBoundSpec *boundspec = NULL;
-
- /* Try fetching the tuple from the catcache, for speed. */
- tuple = SearchSysCache1(RELOID, partOid);
- if (!HeapTupleIsValid(tuple))
- elog(ERROR, "cache lookup failed for relation \"%s\"",
- name->relname);
-
- datum = SysCacheGetAttr(RELOID, tuple,
- Anum_pg_class_relpartbound,
- &isnull);
- if (isnull)
- elog(ERROR, "partition bound for relation \"%s\" is null",
- name->relname);
-
- boundspec = stringToNode(TextDatumGetCString(datum));
-
- if (!IsA(boundspec, PartitionBoundSpec))
- elog(ERROR, "expected PartitionBoundSpec for relation \"%s\"",
- name->relname);
-
- ReleaseSysCache(tuple);
- return boundspec;
-}
-
-/*
- * check_partition_bounds_for_split_range
- *
- * (function for BY RANGE partitioning)
- *
- * Checks that bounds of new partition "spec" are inside bounds of split
- * partition (with Oid splitPartOid). If first=true (this means that "spec" is
- * the first of new partitions) then lower bound of "spec" should be equal (or
- * greater than or equal in case defaultPart=true) to lower bound of split
- * partition. If last=true (this means that "spec" is the last of new
- * partitions) then upper bound of "spec" should be equal (or less than or
- * equal in case defaultPart=true) to upper bound of split partition.
- *
- * parent: partitioned table
- * relname: name of the new partition
- * spec: bounds specification of the new partition
- * splitPartOid: split partition Oid
- * splitPartName: split partition name
- * first: true in case new partition "spec" is first of new partitions
- * last: true in case new partition "spec" is last of new partitions
- * defaultPart: true in case partitioned table has DEFAULT partition
- * pstate: pointer to ParseState struct for determine error position
- */
-static void
-check_partition_bounds_for_split_range(Relation parent,
- char *relname,
- PartitionBoundSpec *spec,
- Oid splitPartOid,
- RangeVar *splitPartName,
- bool first,
- bool last,
- bool defaultPart,
- ParseState *pstate)
-{
- PartitionKey key = RelationGetPartitionKey(parent);
- PartitionRangeBound *lower,
- *upper;
- int cmpval;
-
- Assert(key->strategy == PARTITION_STRATEGY_RANGE);
- Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
-
- lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
- upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
-
- /*
- * First check if the resulting range would be empty with specified lower
- * and upper bounds. partition_rbound_cmp cannot return zero here, since
- * the lower-bound flags are different.
- */
- cmpval = partition_rbound_cmp(key->partnatts,
- key->partsupfunc,
- key->partcollation,
- lower->datums, lower->kind,
- true, upper);
- Assert(cmpval != 0);
- if (cmpval > 0)
- {
- /* Point to problematic key in the lower datums list. */
- PartitionRangeDatum *datum = list_nth(spec->lowerdatums, cmpval - 1);
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("empty range bound specified for partition \"%s\"",
- relname),
- errdetail("Specified lower bound %s is greater than or equal to upper bound %s.",
- get_range_partbound_string(spec->lowerdatums),
- get_range_partbound_string(spec->upperdatums)),
- parser_errposition(pstate, datum->location)));
- }
-
- /* Need to check first and last partitions (from set of new partitions) */
- if (first || last)
- {
- PartitionBoundSpec *split_spec = get_partition_bound_spec(splitPartOid, splitPartName);
- PartitionRangeDatum *datum;
-
- if (first)
- {
- PartitionRangeBound *split_lower;
-
- split_lower = make_one_partition_rbound(key, -1, split_spec->lowerdatums, true);
-
- cmpval = partition_rbound_cmp(key->partnatts,
- key->partsupfunc,
- key->partcollation,
- lower->datums, lower->kind,
- true, split_lower);
-
- /*
- * Lower bound of "spec" should be equal (or greater than or equal
- * in case defaultPart=true) to lower bound of split partition.
- */
- if (!defaultPart)
- {
- if (cmpval != 0)
- {
- datum = list_nth(spec->lowerdatums, abs(cmpval) - 1);
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("lower bound of partition \"%s\" is not equal to lower bound of split partition",
- relname),
- parser_errposition(pstate, datum->location)));
- }
- }
- else
- {
- if (cmpval < 0)
- {
- datum = list_nth(spec->lowerdatums, abs(cmpval) - 1);
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("lower bound of partition \"%s\" is less than lower bound of split partition",
- relname),
- parser_errposition(pstate, datum->location)));
- }
- }
- }
- else
- {
- PartitionRangeBound *split_upper;
-
- split_upper = make_one_partition_rbound(key, -1, split_spec->upperdatums, false);
-
- cmpval = partition_rbound_cmp(key->partnatts,
- key->partsupfunc,
- key->partcollation,
- upper->datums, upper->kind,
- false, split_upper);
-
- /*
- * Upper bound of "spec" should be equal (or less than or equal in
- * case defaultPart=true) to upper bound of split partition.
- */
- if (!defaultPart)
- {
- if (cmpval != 0)
- {
- datum = list_nth(spec->upperdatums, abs(cmpval) - 1);
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("upper bound of partition \"%s\" is not equal to upper bound of split partition",
- relname),
- parser_errposition(pstate, datum->location)));
- }
- }
- else
- {
- if (cmpval > 0)
- {
- datum = list_nth(spec->upperdatums, abs(cmpval) - 1);
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("upper bound of partition \"%s\" is greater than upper bound of split partition",
- relname),
- parser_errposition(pstate, datum->location)));
- }
- }
- }
- }
-}
-
-/*
- * check_partition_bounds_for_split_list
- *
- * (function for BY LIST partitioning)
- *
- * Checks that bounds of new partition are inside bounds of split partition
- * (with Oid splitPartOid).
- *
- * parent: partitioned table
- * relname: name of the new partition
- * spec: bounds specification of the new partition
- * splitPartOid: split partition Oid
- * pstate: pointer to ParseState struct for determine error position
- */
-static void
-check_partition_bounds_for_split_list(Relation parent, char *relname,
- PartitionBoundSpec *spec,
- Oid splitPartOid,
- ParseState *pstate)
-{
- PartitionKey key = RelationGetPartitionKey(parent);
- PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
- PartitionBoundInfo boundinfo = partdesc->boundinfo;
- int with = -1;
- bool overlap = false;
- int overlap_location = -1;
- ListCell *cell;
-
- Assert(key->strategy == PARTITION_STRATEGY_LIST);
- Assert(spec->strategy == PARTITION_STRATEGY_LIST);
- Assert(boundinfo && boundinfo->strategy == PARTITION_STRATEGY_LIST);
-
- /*
- * Search each value of new partition "spec" in existing partitions. All
- * of them should be in split partition (with Oid splitPartOid).
- */
- foreach(cell, spec->listdatums)
- {
- Const *val = lfirst_node(Const, cell);
-
- overlap_location = val->location;
- if (!val->constisnull)
- {
- int offset;
- bool equal;
-
- offset = partition_list_bsearch(&key->partsupfunc[0],
- key->partcollation,
- boundinfo,
- val->constvalue,
- &equal);
- if (offset >= 0 && equal)
- {
- with = boundinfo->indexes[offset];
- if (partdesc->oids[with] != splitPartOid)
- {
- overlap = true;
- break;
- }
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partition \"%s\" cannot have this value because split partition does not have",
- relname),
- parser_errposition(pstate, overlap_location)));
- }
- else if (partition_bound_accepts_nulls(boundinfo))
- {
- with = boundinfo->null_index;
- if (partdesc->oids[with] != splitPartOid)
- {
- overlap = true;
- break;
- }
- }
- else
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partition \"%s\" cannot have NULL value because split partition does not have",
- relname),
- parser_errposition(pstate, overlap_location)));
- }
-
- if (overlap)
- {
- Assert(with >= 0);
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partition \"%s\" would overlap with another (not split) partition \"%s\"",
- relname, get_rel_name(partdesc->oids[with])),
- parser_errposition(pstate, overlap_location)));
- }
-}
-
-/*
- * find_value_in_new_partitions_list
- *
- * (function for BY LIST partitioning)
- *
- * Function returns true in case any of new partitions contains value "value".
- *
- * partsupfunc: information about comparison function associated with the partition key
- * partcollation: partitioning collation
- * parts: pointer to array with new partitions descriptions
- * nparts: number of new partitions
- * value: the value that we are looking for
- * isnull: true if the value that we are looking for is NULL
- */
-static bool
-find_value_in_new_partitions_list(FmgrInfo *partsupfunc,
- Oid *partcollation,
- SinglePartitionSpec **parts,
- int nparts,
- Datum value,
- bool isnull)
-{
- ListCell *valptr;
- int i;
-
- for (i = 0; i < nparts; i++)
- {
- SinglePartitionSpec *sps = parts[i];
-
- foreach(valptr, sps->bound->listdatums)
- {
- Const *val = lfirst_node(Const, valptr);
-
- if (isnull && val->constisnull)
- return true;
-
- if (!isnull && !val->constisnull)
- {
- if (DatumGetInt32(FunctionCall2Coll(&partsupfunc[0],
- partcollation[0],
- val->constvalue,
- value)) == 0)
- return true;
- }
- }
- }
- return false;
-}
-
-/*
- * check_parent_values_in_new_partitions
- *
- * (function for BY LIST partitioning)
- *
- * Checks that all values of split partition (with Oid partOid) contains in new
- * partitions.
- *
- * parent: partitioned table
- * partOid: split partition Oid
- * parts: pointer to array with new partitions descriptions
- * nparts: number of new partitions
- * pstate: pointer to ParseState struct for determine error position
- */
-static void
-check_parent_values_in_new_partitions(Relation parent,
- Oid partOid,
- SinglePartitionSpec **parts,
- int nparts,
- ParseState *pstate)
-{
- PartitionKey key = RelationGetPartitionKey(parent);
- PartitionDesc partdesc = RelationGetPartitionDesc(parent, false);
- PartitionBoundInfo boundinfo = partdesc->boundinfo;
- int i;
- bool found = true;
- bool searchNull = false;
- Datum datum = PointerGetDatum(NULL);
-
- Assert(key->strategy == PARTITION_STRATEGY_LIST);
-
- /*
- * Special processing for NULL value. Search NULL value if the split
- * partition (partOid) contains it.
- */
- if (partition_bound_accepts_nulls(boundinfo) &&
- partdesc->oids[boundinfo->null_index] == partOid)
- {
- if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
- key->partcollation, parts, nparts, datum, true))
- {
- found = false;
- searchNull = true;
- }
- }
-
- /*
- * Search all values of split partition with partOid in PartitionDesc of
- * partitioned table.
- */
- for (i = 0; i < boundinfo->ndatums; i++)
- {
- if (partdesc->oids[boundinfo->indexes[i]] == partOid)
- {
- /* We found value that split partition contains. */
- datum = boundinfo->datums[i][0];
- if (!find_value_in_new_partitions_list(&key->partsupfunc[0],
- key->partcollation, parts, nparts, datum, false))
- {
- found = false;
- break;
- }
- }
- }
-
- if (!found)
- {
- Const *notFoundVal;
-
- if (!searchNull)
-
- /*
- * Make Const for getting string representation of not found
- * value.
- */
- notFoundVal = makeConst(key->parttypid[0],
- key->parttypmod[0],
- key->parttypcoll[0],
- key->parttyplen[0],
- datum,
- false, /* isnull */
- key->parttypbyval[0]);
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partitions do not have value %s but split partition does",
- searchNull ? "NULL" : get_list_partvalue_string(notFoundVal))));
- }
-}
-
-/*
- * check_partitions_for_split
- *
- * Checks new partitions for SPLIT PARTITIONS command:
- * 1. DEFAULT partition should be one.
- * 2. New partitions should have different names
- * (with existing partitions too).
- * 3. Bounds of new partitions should not overlap with new and existing
- * partitions.
- * 4. In case split partition is DEFAULT partition, one of new partitions
- * should be DEFAULT.
- * 5. In case new partitions or existing partitions contains DEFAULT
- * partition, new partitions can have any bounds inside split
- * partition bound (can be spaces between partitions bounds).
- * 6. In case partitioned table does not have DEFAULT partition, DEFAULT
- * partition can be defined as one of new partition.
- * 7. In case new partitions not contains DEFAULT partition and
- * partitioned table does not have DEFAULT partition the following
- * should be true: sum bounds of new partitions should be equal
- * to bound of split partition.
- *
- * parent: partitioned table
- * splitPartOid: split partition Oid
- * splitPartName: split partition name
- * list: list of new partitions
- * pstate: pointer to ParseState struct for determine error position
- */
-void
-check_partitions_for_split(Relation parent,
- Oid splitPartOid,
- RangeVar *splitPartName,
- List *partlist,
- ParseState *pstate)
-{
- PartitionKey key;
- char strategy;
- Oid defaultPartOid;
- bool isSplitPartDefault;
- bool existsDefaultPart;
- ListCell *listptr;
- int default_index = -1;
- int i,
- j;
- SinglePartitionSpec **new_parts;
- SinglePartitionSpec *spsPrev = NULL;
- int nparts = 0;
-
- key = RelationGetPartitionKey(parent);
- strategy = get_partition_strategy(key);
-
- switch (strategy)
- {
- case PARTITION_STRATEGY_LIST:
- case PARTITION_STRATEGY_RANGE:
- {
- /*
- * Make array new_parts with new partitions except DEFAULT
- * partition.
- */
- new_parts = (SinglePartitionSpec **)
- palloc0(list_length(partlist) * sizeof(SinglePartitionSpec *));
- i = 0;
- foreach(listptr, partlist)
- {
- SinglePartitionSpec *sps =
- (SinglePartitionSpec *) lfirst(listptr);
-
- if (sps->bound->is_default)
- {
- if (default_index >= 0)
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("DEFAULT partition should be one")),
- parser_errposition(pstate, sps->name->location));
- default_index = i;
- }
- else
- {
- new_parts[nparts++] = sps;
- }
- i++;
- }
- }
- break;
-
- case PARTITION_STRATEGY_HASH:
- ereport(ERROR,
- (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
- errmsg("partition of hash-partitioned table cannot be split")));
- break;
-
- default:
- elog(ERROR, "unexpected partition strategy: %d",
- (int) key->strategy);
- break;
- }
-
- if (strategy == PARTITION_STRATEGY_RANGE)
- {
- PartitionRangeBound **lower_bounds;
- SinglePartitionSpec **tmp_new_parts;
-
- /*
- * For simplify check for ranges of new partitions need to sort all
- * partitions in ascending order of them bounds (we compare upper
- * bound only).
- */
- lower_bounds = (PartitionRangeBound **)
- palloc0(nparts * sizeof(PartitionRangeBound *));
-
- /* Create array of lower bounds. */
- for (i = 0; i < nparts; i++)
- {
- lower_bounds[i] = make_one_partition_rbound(key, i,
- new_parts[i]->bound->lowerdatums, true);
- }
-
- /* Sort array of lower bounds. */
- qsort_arg(lower_bounds, nparts, sizeof(PartitionRangeBound *),
- qsort_partition_rbound_cmp, (void *) key);
-
- /* Reorder array of partitions. */
- tmp_new_parts = new_parts;
- new_parts = (SinglePartitionSpec **)
- palloc0(nparts * sizeof(SinglePartitionSpec *));
- for (i = 0; i < nparts; i++)
- new_parts[i] = tmp_new_parts[lower_bounds[i]->index];
-
- pfree(tmp_new_parts);
- pfree(lower_bounds);
- }
-
- defaultPartOid =
- get_default_oid_from_partdesc(RelationGetPartitionDesc(parent, true));
-
- /* isSplitPartDefault flag: is split partition a DEFAULT partition? */
- isSplitPartDefault = (defaultPartOid == splitPartOid);
-
- if (isSplitPartDefault && default_index < 0)
- {
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("one partition in the list should be DEFAULT because split partition is DEFAULT")),
- parser_errposition(pstate, ((SinglePartitionSpec *) linitial(partlist))->name->location));
- }
- else if (!isSplitPartDefault && (default_index >= 0) && OidIsValid(defaultPartOid))
- {
- SinglePartitionSpec *spsDef =
- (SinglePartitionSpec *) list_nth(partlist, default_index);
-
- ereport(ERROR,
- (errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
- errmsg("new partition cannot be DEFAULT because DEFAULT partition already exists")),
- parser_errposition(pstate, spsDef->name->location));
- }
-
- /* Indicator that partitioned table has (or will have) DEFAULT partition */
- existsDefaultPart = OidIsValid(defaultPartOid) || (default_index >= 0);
-
- for (i = 0; i < nparts; i++)
- {
- SinglePartitionSpec *sps = new_parts[i];
-
- if (isSplitPartDefault)
- {
- /*
- * In case split partition is DEFAULT partition we can use any
- * free ranges - as when creating a new partition.
- */
- check_new_partition_bound(sps->name->relname, parent, sps->bound,
- pstate);
- }
- else
- {
- /*
- * Checks that bound of current partition is inside bound of split
- * partition. For range partitioning: checks that upper bound of
- * previous partition is equal to lower bound of current
- * partition. For list partitioning: checks that split partition
- * contains all values of current partition.
- */
- if (strategy == PARTITION_STRATEGY_RANGE)
- {
- bool first = (i == 0);
- bool last = (i == (nparts - 1));
-
- check_partition_bounds_for_split_range(parent, sps->name->relname, sps->bound,
- splitPartOid, splitPartName,
- first, last,
- existsDefaultPart, pstate);
- }
- else
- check_partition_bounds_for_split_list(parent, sps->name->relname,
- sps->bound, splitPartOid, pstate);
- }
-
- /* Ranges of new partitions should not overlap. */
- if (strategy == PARTITION_STRATEGY_RANGE && spsPrev)
- check_two_partitions_bounds_range(parent, spsPrev->name, spsPrev->bound,
- sps->name, sps->bound, existsDefaultPart, pstate);
-
- spsPrev = sps;
-
- /* Check: new partitions should have different names. */
- for (j = i + 1; j < nparts; j++)
- {
- SinglePartitionSpec *sps2 = new_parts[j];
-
- if (equal(sps->name, sps2->name))
- ereport(ERROR,
- (errcode(ERRCODE_DUPLICATE_TABLE),
- errmsg("name \"%s\" is already used", sps2->name->relname)),
- parser_errposition(pstate, sps2->name->location));
- }
- }
-
- if (strategy == PARTITION_STRATEGY_LIST)
- {
- /* Values of new partitions should not overlap. */
- check_partitions_not_overlap_list(parent, new_parts, nparts,
- pstate);
-
- /*
- * Need to check that all values of split partition contains in new
- * partitions. Skip this check if DEFAULT partition exists.
- */
- if (!existsDefaultPart)
- check_parent_values_in_new_partitions(parent, splitPartOid,
- new_parts, nparts, pstate);
- }
-
- pfree(new_parts);
-}
-
-/*
- * calculate_partition_bound_for_merge
- *
- * Calculates the bound of merged partition "spec" by using the bounds of
- * partitions to be merged.
- *
- * parent: partitioned table
- * partNames: names of partitions to be merged
- * partOids: Oids of partitions to be merged
- * spec (out): bounds specification of the merged partition
- * pstate: pointer to ParseState struct for determine error position
- */
-void
-calculate_partition_bound_for_merge(Relation parent,
- List *partNames,
- List *partOids,
- PartitionBoundSpec *spec,
- ParseState *pstate)
-{
- PartitionKey key = RelationGetPartitionKey(parent);
- PartitionBoundSpec *bound;
-
- Assert(!spec->is_default);
-
- switch (key->strategy)
- {
- case PARTITION_STRATEGY_RANGE:
- {
- int i;
- PartitionRangeBound **lower_bounds;
- int nparts = list_length(partOids);
- List *bounds = NIL;
-
- lower_bounds = (PartitionRangeBound **)
- palloc0(nparts * sizeof(PartitionRangeBound *));
-
- /*
- * Create array of lower bounds and list of
- * PartitionBoundSpec.
- */
- for (i = 0; i < nparts; i++)
- {
- bound = get_partition_bound_spec(list_nth_oid(partOids, i),
- (RangeVar *) list_nth(partNames, i));
-
- lower_bounds[i] = make_one_partition_rbound(key, i, bound->lowerdatums, true);
- bounds = lappend(bounds, bound);
- }
-
- /* Sort array of lower bounds. */
- qsort_arg(lower_bounds, nparts, sizeof(PartitionRangeBound *),
- qsort_partition_rbound_cmp, (void *) key);
-
- /* Ranges of partitions should not overlap. */
- for (i = 1; i < nparts; i++)
- {
- int index = lower_bounds[i]->index;
- int prev_index = lower_bounds[i - 1]->index;
-
- check_two_partitions_bounds_range(parent,
- (RangeVar *) list_nth(partNames, prev_index),
- (PartitionBoundSpec *) list_nth(bounds, prev_index),
- (RangeVar *) list_nth(partNames, index),
- (PartitionBoundSpec *) list_nth(bounds, index),
- false, pstate);
- }
-
- /*
- * Lower bound of first partition is the lower bound of merged
- * partition.
- */
- spec->lowerdatums =
- ((PartitionBoundSpec *) list_nth(bounds, lower_bounds[0]->index))->lowerdatums;
-
- /*
- * Upper bound of last partition is the upper bound of merged
- * partition.
- */
- spec->upperdatums =
- ((PartitionBoundSpec *) list_nth(bounds, lower_bounds[nparts - 1]->index))->upperdatums;
-
- pfree(lower_bounds);
- list_free(bounds);
- break;
- }
-
- case PARTITION_STRATEGY_LIST:
- {
- ListCell *listptr,
- *listptr2;
-
- /* Consolidate bounds for all partitions in the list. */
- forboth(listptr, partOids, listptr2, partNames)
- {
- RangeVar *name = (RangeVar *) lfirst(listptr2);
- Oid curOid = lfirst_oid(listptr);
-
- bound = get_partition_bound_spec(curOid, name);
- spec->listdatums = list_concat(spec->listdatums, bound->listdatums);
- }
- break;
- }
-
- default:
- elog(ERROR, "unexpected partition strategy: %d",
- (int) key->strategy);
- }
-}