Start working on hypothetical partitioning pg10 compatibility.

This is the easy part: get rid of the features added in pg11 such as
hash partitioning or default partition, and adapt the required imports.

There are still a lot of errors due to the lack of PartitionScheme and
many fields in RelOptInfo in pg10.
This commit is contained in:
Julien Rouhaud 2018-11-08 21:51:06 +01:00
parent f07b82e387
commit eefa430ed9
5 changed files with 412 additions and 13 deletions

View file

@ -538,12 +538,15 @@ hypo_get_relation_info_hook(PlannerInfo *root,
* is a hypothetical partition, root table oid is equal to
* relationObjectId, so nothing to do
*/
AppendRelInfo *appinfo;
RelOptInfo *parentrel = rel;
do
{
#if PG_VERSION_NUM >= 110000
appinfo = root->append_rel_array[parentrel->relid];
#else
appinfo = find_childrel_appendrelinfo(root, parentrel);
#endif /* pg10 only */
parentrel = find_base_rel(root, appinfo->parent_relid);
} while (parentrel->reloptkind == RELOPT_OTHER_MEMBER_REL);
parentId = appinfo->parent_reloid;
@ -556,7 +559,7 @@ hypo_get_relation_info_hook(PlannerInfo *root,
if (entry->relid == parentId
#if PG_VERSION_NUM >= 100000
&& !rel->part_scheme
&& rel->reloptkind != RELOPT_OTHER_MEMBER_REL
#endif
)
{

View file

@ -42,8 +42,10 @@
#endif
#include "utils/guc.h"
#include "utils/lsyscache.h"
#if PG_VERSION_NUM >= 100000
#if PG_VERSION_NUM >= 110000
#include "utils/partcache.h"
#endif
#if PG_VERSION_NUM >= 100000
#include "utils/ruleutils.h"
#endif
#include "utils/selfuncs.h"
@ -220,6 +222,7 @@ static void hypo_do_analyze_partition(Relation onerel, Relation pgstats,
Assert(hypoStatsHash);
#if PG_VERSION_NUM >= 110000
/*
* We can't use the same heuristics for hash partitions selectivity
* estimation, because its constraint is using satisfies_hash_partition(),
@ -234,6 +237,7 @@ static void hypo_do_analyze_partition(Relation onerel, Relation pgstats,
" skipping", part->tablename);
return;
}
#endif
/*
* Set up a working context so that we can easily free whatever junk gets

View file

@ -37,6 +37,9 @@
#include "utils/ruleutils.h"
#endif
#include "optimizer/clauses.h"
#if PG_VERSION_NUM >= 100000
#include "catalog/partition.h"
#endif
#if PG_VERSION_NUM >= 110000
#include "catalog/partition.h"
#include "optimizer/cost.h"
@ -61,6 +64,262 @@
#include "include/hypopg_import.h"
/* pg10 only imports */
#if PG_VERSION_NUM >= 100000 && PG_VERSION_NUM < 110000
static int32 partition_rbound_datum_cmp(PartitionKey key,
Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
Datum *tuple_datums);
/*
* Copied from src/backend/catalog/partition.c
*
* make_one_range_bound
*
* Return a PartitionRangeBound given a list of PartitionRangeDatum elements
* and a flag telling whether the bound is lower or not. Made into a function
* because there are multiple sites that want to use this facility.
*/
PartitionRangeBound *
make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
{
PartitionRangeBound *bound;
ListCell *lc;
int i;
bound = (PartitionRangeBound *) palloc0(sizeof(PartitionRangeBound));
bound->index = index;
bound->datums = (Datum *) palloc0(key->partnatts * sizeof(Datum));
bound->kind = (PartitionRangeDatumKind *) palloc0(key->partnatts *
sizeof(PartitionRangeDatumKind));
bound->lower = lower;
i = 0;
foreach(lc, datums)
{
PartitionRangeDatum *datum = castNode(PartitionRangeDatum, lfirst(lc));
/* What's contained in this range datum? */
bound->kind[i] = datum->kind;
if (datum->kind == PARTITION_RANGE_DATUM_VALUE)
{
Const *val = castNode(Const, datum->value);
if (val->constisnull)
elog(ERROR, "invalid range bound datum");
bound->datums[i] = val->constvalue;
}
i++;
}
return bound;
}
/*
* Copied from src/backend/catalog/partition.c
*
* Binary search on a collection of partition bounds. Returns greatest
* bound in array boundinfo->datums which is less than or equal to *probe.
* If all bounds in the array are greater than *probe, -1 is returned.
*
* *probe could either be a partition bound or a Datum array representing
* the partition key of a tuple being routed; probe_is_bound tells which.
* We pass that down to the comparison function so that it can interpret the
* contents of *probe accordingly.
*
* *is_equal is set to whether the bound at the returned index is equal with
* *probe.
*/
int
partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
void *probe, bool probe_is_bound, bool *is_equal)
{
int lo,
hi,
mid;
lo = -1;
hi = boundinfo->ndatums - 1;
while (lo < hi)
{
int32 cmpval;
mid = (lo + hi + 1) / 2;
cmpval = partition_bound_cmp(key, boundinfo, mid, probe,
probe_is_bound);
if (cmpval <= 0)
{
lo = mid;
*is_equal = (cmpval == 0);
if (*is_equal)
break;
}
else
hi = mid - 1;
}
return lo;
}
/*
* Copied from src/backend/catalog/partition.c
*
* partition_bound_cmp
*
* Return whether the bound at offset in boundinfo is <, =, or > the argument
* specified in *probe.
*/
int32
partition_bound_cmp(PartitionKey key, PartitionBoundInfo boundinfo,
int offset, void *probe, bool probe_is_bound)
{
Datum *bound_datums = boundinfo->datums[offset];
int32 cmpval = -1;
switch (key->strategy)
{
case PARTITION_STRATEGY_LIST:
cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[0],
key->partcollation[0],
bound_datums[0],
*(Datum *) probe));
break;
case PARTITION_STRATEGY_RANGE:
{
PartitionRangeDatumKind *kind = boundinfo->kind[offset];
if (probe_is_bound)
{
/*
* We need to pass whether the existing bound is a lower
* bound, so that two equal-valued lower and upper bounds
* are not regarded equal.
*/
bool lower = boundinfo->indexes[offset] < 0;
cmpval = partition_rbound_cmp(key,
bound_datums, kind, lower,
(PartitionRangeBound *) probe);
}
else
cmpval = partition_rbound_datum_cmp(key,
bound_datums, kind,
(Datum *) probe);
break;
}
default:
elog(ERROR, "unexpected partition strategy: %d",
(int) key->strategy);
}
return cmpval;
}
/*
* Imported from src/backend/catalog/partition.c, not exported in pg10
*
* partition_rbound_cmp
*
* Return for two range bounds whether the 1st one (specified in datum1,
* kind1, and lower1) is <, =, or > the bound specified in *b2.
*
* Note that if the values of the two range bounds compare equal, then we take
* into account whether they are upper or lower bounds, and an upper bound is
* considered to be smaller than a lower bound. This is important to the way
* that RelationBuildPartitionDesc() builds the PartitionBoundInfoData
* structure, which only stores the upper bound of a common boundary between
* two contiguous partitions.
*/
int32
partition_rbound_cmp(PartitionKey key,
Datum *datums1, PartitionRangeDatumKind *kind1,
bool lower1, PartitionRangeBound *b2)
{
int32 cmpval = 0; /* placate compiler */
int i;
Datum *datums2 = b2->datums;
PartitionRangeDatumKind *kind2 = b2->kind;
bool lower2 = b2->lower;
for (i = 0; i < key->partnatts; i++)
{
/*
* First, handle cases where the column is unbounded, which should not
* invoke the comparison procedure, and should not consider any later
* columns. Note that the PartitionRangeDatumKind enum elements
* compare the same way as the values they represent.
*/
if (kind1[i] < kind2[i])
return -1;
else if (kind1[i] > kind2[i])
return 1;
else if (kind1[i] != PARTITION_RANGE_DATUM_VALUE)
/*
* The column bounds are both MINVALUE or both MAXVALUE. No later
* columns should be considered, but we still need to compare
* whether they are upper or lower bounds.
*/
break;
cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
key->partcollation[i],
datums1[i],
datums2[i]));
if (cmpval != 0)
break;
}
/*
* If the comparison is anything other than equal, we're done. If they
* compare equal though, we still have to consider whether the boundaries
* are inclusive or exclusive. Exclusive one is considered smaller of the
* two.
*/
if (cmpval == 0 && lower1 != lower2)
cmpval = lower1 ? 1 : -1;
return cmpval;
}
/*
* Imported from src/backend/catalog/partition.c, not exported in pg10
*
* partition_rbound_datum_cmp
*
* Return whether range bound (specified in rb_datums, rb_kind, and rb_lower)
* is <, =, or > partition key of tuple (tuple_datums)
*/
static int32
partition_rbound_datum_cmp(PartitionKey key,
Datum *rb_datums, PartitionRangeDatumKind *rb_kind,
Datum *tuple_datums)
{
int i;
int32 cmpval = -1;
for (i = 0; i < key->partnatts; i++)
{
if (rb_kind[i] == PARTITION_RANGE_DATUM_MINVALUE)
return -1;
else if (rb_kind[i] == PARTITION_RANGE_DATUM_MAXVALUE)
return 1;
cmpval = DatumGetInt32(FunctionCall2Coll(&key->partsupfunc[i],
key->partcollation[i],
rb_datums[i],
tuple_datums[i]));
if (cmpval != 0)
break;
}
return cmpval;
}
#endif /* pg10 only imports */
/* Copied from src/backend/optimizer/util/plancat.c, not exported.
*
@ -730,6 +989,7 @@ looks_like_function(Node *node)
return false;
}
#if PG_VERSION_NUM >= 110000
/*
* Copied from src/backend/catalog/partition.c, not exported
*
@ -746,6 +1006,7 @@ qsort_partition_hbound_cmp(const void *a, const void *b)
return partition_hbound_cmp(h1->modulus, h1->remainder,
h2->modulus, h2->remainder);
}
#endif
/*
* Copied from src/backend/catalog/partition.c, not exported
@ -778,9 +1039,13 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
PartitionKey key = (PartitionKey) arg;
#if PG_VERSION_NUM < 110000
return partition_rbound_cmp(key, b1->datums, b1->kind, b1->lower, b2);
#else
return partition_rbound_cmp(key->partnatts, key->partsupfunc,
key->partcollation, b1->datums, b1->kind,
b1->lower, b2);
#endif
}
/* ----------

View file

@ -28,6 +28,9 @@
#include "catalog/namespace.h"
#include "catalog/partition.h"
#include "catalog/pg_class.h"
#if PG_VERSION_NUM < 110000
#include "catalog/pg_inherits_fn.h"
#endif
#include "catalog/pg_inherits.h"
#include "catalog/pg_opclass.h"
#include "catalog/pg_type.h"
@ -50,10 +53,12 @@
#include "utils/datum.h"
#include "utils/fmgroids.h"
#include "utils/lsyscache.h"
#if PG_VERSION_NUM >= 110000
#include "utils/partcache.h"
#include "partitioning/partbounds.h"
#endif
#include "utils/ruleutils.h"
#include "utils/syscache.h"
#include "partitioning/partbounds.h"
#endif
#include "include/hypopg.h"
@ -93,7 +98,9 @@ static PartitionScheme hypo_find_partition_scheme(PlannerInfo *root,
static void hypo_generate_partition_key_exprs(hypoTable *entry,
RelOptInfo *rel);
static PartitionBoundSpec *hypo_get_boundspec(Oid tableid);
#if PG_VERSION_NUM >= 110000
static Oid hypo_get_default_partition_oid(hypoTable *parent);
#endif
static char *hypo_get_partbounddef(hypoTable *entry);
static char *hypo_get_partkeydef(hypoTable *entry);
static hypoTable *hypo_newTable(Oid parentid);
@ -439,6 +446,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
boundspec = (Node *) hypo_get_boundspec(inhrelid);
#if PG_VERSION_NUM >= 110000
/*
* Sanity check: If the PartitionBoundSpec says this is the default
* partition, its OID should correspond to whatever's stored in
@ -453,6 +461,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
elog(ERROR, "expected partdefid %u, but got %u",
inhrelid, partdefid);
}
#endif
boundspecs = lappend(boundspecs, boundspec);
partoids = lappend_oid(partoids, inhrelid);
@ -468,6 +477,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
oids[i++] = lfirst_oid(cell);
/* Convert from node to the internal representation */
#if PG_VERSION_NUM >= 110000
if (key->strategy == PARTITION_STRATEGY_HASH)
{
ndatums = nparts;
@ -496,7 +506,9 @@ hypo_generate_partitiondesc(hypoTable *parent)
qsort(hbounds, nparts, sizeof(PartitionHashBound *),
qsort_partition_hbound_cmp);
}
else if (key->strategy == PARTITION_STRATEGY_LIST)
else
#endif
if (key->strategy == PARTITION_STRATEGY_LIST)
{
List *non_null_values = NIL;
@ -514,6 +526,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
if (spec->strategy != PARTITION_STRATEGY_LIST)
elog(ERROR, "invalid strategy in partition bound spec");
#if PG_VERSION_NUM >= 110000
/*
* Note the index of the partition bound spec for the default
* partition. There's no datum to add to the list of non-null
@ -525,6 +538,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
i++;
continue;
}
#endif
foreach(c, spec->listdatums)
{
@ -605,6 +619,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
if (spec->strategy != PARTITION_STRATEGY_RANGE)
elog(ERROR, "invalid strategy in partition bound spec");
#if PG_VERSION_NUM >= 110000
/*
* Note the index of the partition bound spec for the default
* partition. There's no datum to add to the allbounds array
@ -615,11 +630,19 @@ hypo_generate_partitiondesc(hypoTable *parent)
default_index = i++;
continue;
}
#endif
#if PG_VERSION_NUM < 110000
lower = make_one_range_bound(key, i, spec->lowerdatums,
true);
upper = make_one_range_bound(key, i, spec->upperdatums,
false);
#else
lower = make_one_partition_rbound(key, i, spec->lowerdatums,
true);
upper = make_one_partition_rbound(key, i, spec->upperdatums,
false);
#endif
all_bounds[ndatums++] = lower;
all_bounds[ndatums++] = upper;
i++;
@ -719,6 +742,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
switch (key->strategy)
{
#if PG_VERSION_NUM >= 110000
case PARTITION_STRATEGY_HASH:
{
/* Modulus are stored in ascending order */
@ -754,6 +778,7 @@ hypo_generate_partitiondesc(hypoTable *parent)
pfree(hbounds);
break;
}
#endif
case PARTITION_STRATEGY_LIST:
{
@ -978,9 +1003,13 @@ hypo_generate_partkey(CreateStmt *stmt, Oid parentid, hypoTable *entry)
MemoryContextSwitchTo(oldcontext);
#if PG_VERSION_NUM >= 110000
/* determine support function number to search for */
procnum = (key->strategy == PARTITION_STRATEGY_HASH) ?
HASHEXTENDED_PROC : BTORDER_PROC;
#else
procnum = BTORDER_PROC;
#endif
/* Copy partattrs and fill other per-attribute info */
memcpy(key->partattrs, partattrs, key->partnatts * sizeof(int16));
@ -1012,8 +1041,12 @@ hypo_generate_partkey(CreateStmt *stmt, Oid parentid, hypoTable *entry)
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
errmsg("operator class \"%s\" of access method %s is missing support function %d for type %s",
NameStr(opclassform->opcname),
#if PG_VERSION_NUM >= 110000
(key->strategy == PARTITION_STRATEGY_HASH) ?
"hash" : "btree",
#else
"btree",
#endif
procnum,
format_type_be(opclassform->opcintype))));
@ -1259,6 +1292,7 @@ hypo_get_boundspec(Oid tableid)
return NULL;
}
#if PG_VERSION_NUM >= 110000
/*
* Return the Oid of the default partition if any, otherwise return InvalidOid
*/
@ -1277,6 +1311,7 @@ hypo_get_default_partition_oid(hypoTable *parent)
return InvalidOid;
}
#endif
/*
* Deparse the stored PartitionBoundSpec data
@ -1299,14 +1334,17 @@ hypo_get_partbounddef(hypoTable *entry)
buf = &_buf;
_context.buf = &_buf;
#if PG_VERSION_NUM >= 110000
if (spec->is_default)
{
appendStringInfoString(buf, "DEFAULT");
return buf->data;
}
#endif
switch (spec->strategy)
{
#if PG_VERSION_NUM >= 110000
case PARTITION_STRATEGY_HASH:
Assert(spec->modulus > 0 && spec->remainder >= 0);
Assert(spec->modulus > spec->remainder);
@ -1315,6 +1353,7 @@ hypo_get_partbounddef(hypoTable *entry)
appendStringInfo(buf, " WITH (modulus %d, remainder %d)",
spec->modulus, spec->remainder);
break;
#endif
case PARTITION_STRATEGY_LIST:
Assert(spec->listdatums != NIL);
@ -1383,9 +1422,11 @@ hypo_get_partkeydef(hypoTable *entry)
appendStringInfo(&buf, "PARTITION BY ");
switch(partkey->strategy)
{
#if PG_VERSION_NUM >= 110000
case PARTITION_STRATEGY_HASH:
appendStringInfo(&buf, "HASH");
break;
#endif
case PARTITION_STRATEGY_LIST:
appendStringInfo(&buf, "LIST");
break;
@ -1414,7 +1455,11 @@ hypo_get_partkeydef(hypoTable *entry)
char *attname;
int32 keycoltypmod;
#if PG_VERSION_NUM < 110000
attname = get_attname(relid, attnum);
#else
attname = get_attname(relid, attnum, false);
#endif
appendStringInfoString(&buf, quote_identifier(attname));
get_atttypetypmodcoll(relid, attnum,
&keycoltype, &keycoltypmod,
@ -1839,6 +1884,7 @@ hypo_transformPartitionBound(ParseState *pstate, hypoTable *parent,
/* Avoid scribbling on input */
result_spec = copyObject(spec);
#if PG_VERSION_NUM >= 110000
if (spec->is_default)
{
if (strategy == PARTITION_STRATEGY_HASH)
@ -1876,7 +1922,9 @@ hypo_transformPartitionBound(ParseState *pstate, hypoTable *parent,
(errcode(ERRCODE_INVALID_TABLE_DEFINITION),
errmsg("remainder for hash partition must be less than modulus")));
}
else if (strategy == PARTITION_STRATEGY_LIST)
else
#endif
if (strategy == PARTITION_STRATEGY_LIST)
{
ListCell *cell;
char *colname;
@ -1891,8 +1939,13 @@ hypo_transformPartitionBound(ParseState *pstate, hypoTable *parent,
/* Get the only column's name in case we need to output an error */
if (key->partattrs[0] != 0)
#if PG_VERSION_NUM < 110000
colname = get_attname(parent->rootid,
key->partattrs[0]);
#else
colname = get_attname(parent->rootid,
key->partattrs[0], false);
#endif
else
colname = deparse_expression((Node *) linitial(partexprs),
deparse_context_for(parent->tablename,
@ -1976,8 +2029,13 @@ hypo_transformPartitionBound(ParseState *pstate, hypoTable *parent,
/* Get the column's name in case we need to output an error */
if (key->partattrs[i] != 0)
#if PG_VERSION_NUM < 110000
colname = get_attname(parent->rootid,
key->partattrs[i]);
#else
colname = get_attname(parent->rootid,
key->partattrs[i], false);
#endif
else
{
colname = deparse_expression((Node *) list_nth(partexprs, j),
@ -2075,7 +2133,10 @@ hypo_injectHypotheticalPartitioning(PlannerInfo *root,
&&HYPO_RTI_IS_TAGGED(rel->relid,root))
{
Oid partoid;
hypoTable *part, *cur_part;
hypoTable *part;
#if PG_VERSION_NUM >= 110000
hypoTable *cur_part;
#endif
RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
Selectivity selectivity;
double pages;
@ -2096,6 +2157,7 @@ hypo_injectHypotheticalPartitioning(PlannerInfo *root,
return;
}
#if PG_VERSION_NUM >= 110000
/*
* Selectivity for hash partitions cannot be done using the standard
* clauselist_selectivity(), because the underlying constraint is using
@ -2119,7 +2181,9 @@ hypo_injectHypotheticalPartitioning(PlannerInfo *root,
}
elog(DEBUG1, "hypopg: total modulus for partition %s: %d",
part->tablename, total_modulus);
#else
Assert(total_modulus == 1);
#endif
if (part->set_tuples)
{
@ -2154,6 +2218,7 @@ hypo_injectHypotheticalPartitioning(PlannerInfo *root,
}
}
#if PG_VERSION_NUM >= 110000
/*
* This is done in query_planner just before add_base_rels_to_query() is
* called, so before get_relation_info_hook is called and setup
@ -2168,6 +2233,7 @@ hypo_injectHypotheticalPartitioning(PlannerInfo *root,
root->append_rel_array = NULL;
}
setup_append_rel_array(root);
#endif
}
@ -2299,6 +2365,7 @@ hypo_get_qual_from_partbound(hypoTable *parent, PartitionBoundSpec *spec)
switch (key->strategy)
{
#if PG_VERSION_NUM >= 110000
case PARTITION_STRATEGY_HASH:
Assert(spec->strategy == PARTITION_STRATEGY_HASH);
/*
@ -2307,6 +2374,7 @@ hypo_get_qual_from_partbound(hypoTable *parent, PartitionBoundSpec *spec)
* selectivity estimation
*/
break;
#endif
case PARTITION_STRATEGY_LIST:
Assert(spec->strategy == PARTITION_STRATEGY_LIST);
@ -2362,6 +2430,7 @@ hypo_get_qual_for_list(hypoTable *parent, PartitionBoundSpec *spec)
else
keyCol = (Expr *) copyObject(linitial(key->partexprs));
#if PG_VERSION_NUM >= 110000
/*
* For default list partition, collect datums for all the partitions. The
* default partition constraint should check that the partition key is
@ -2412,6 +2481,7 @@ hypo_get_qual_for_list(hypoTable *parent, PartitionBoundSpec *spec)
}
}
else
#endif
{
/*
* Create list of Consts for the allowed values, excluding any nulls.
@ -2483,6 +2553,7 @@ hypo_get_qual_for_list(hypoTable *parent, PartitionBoundSpec *spec)
result = list_make1(nulltest);
}
#if PG_VERSION_NUM >= 110000
/*
* Note that, in general, applying NOT to a constraint expression doesn't
* necessarily invert the set of rows it accepts, because NOT (NULL) is
@ -2494,6 +2565,7 @@ hypo_get_qual_for_list(hypoTable *parent, PartitionBoundSpec *spec)
result = list_make1(make_ands_explicit(result));
result = list_make1(makeBoolExpr(NOT_EXPR, result, -1));
}
#endif
return result;
}
@ -2531,6 +2603,7 @@ hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec, bool for_de
bool need_next_lower_arm,
need_next_upper_arm;
#if PG_VERSION_NUM >= 110000
if (spec->is_default)
{
List *or_expr_args = NIL;
@ -2601,6 +2674,7 @@ hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec, bool for_de
return result;
}
#endif
lower_or_start_datum = list_head(spec->lowerdatums);
upper_or_start_datum = list_head(spec->upperdatums);
@ -2865,6 +2939,7 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
int with = -1;
bool overlap = false;
#if PG_VERSION_NUM >= 110000
if (spec->is_default)
{
/*
@ -2883,9 +2958,11 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
relname, get_rel_name(partdesc->oids[boundinfo->default_index])),
parser_errposition(pstate, spec->location)));
}
#endif
switch (key->strategy)
{
#if PG_VERSION_NUM >= 110000
case PARTITION_STRATEGY_HASH:
{
Assert(spec->strategy == PARTITION_STRATEGY_HASH);
@ -2967,6 +3044,7 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
break;
}
#endif
case PARTITION_STRATEGY_LIST:
{
@ -2979,8 +3057,11 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
Assert(boundinfo &&
boundinfo->strategy == PARTITION_STRATEGY_LIST &&
(boundinfo->ndatums > 0 ||
partition_bound_accepts_nulls(boundinfo) ||
partition_bound_has_default(boundinfo)));
partition_bound_accepts_nulls(boundinfo)
#if PG_VERSION_NUM >= 110000
|| partition_bound_has_default(boundinfo)
#endif
));
foreach(cell, spec->listdatums)
{
@ -2991,11 +3072,17 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
int offset;
bool equal;
#if PG_VERSION_NUM < 110000
offset = partition_bound_bsearch(key, boundinfo,
&val->constvalue,
true, &equal);
#else
offset = partition_list_bsearch(&key->partsupfunc[0],
key->partcollation,
boundinfo,
val->constvalue,
&equal);
#endif
if (offset >= 0 && equal)
{
overlap = true;
@ -3021,16 +3108,26 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
*upper;
Assert(spec->strategy == PARTITION_STRATEGY_RANGE);
#if PG_VERSION_NUM < 110000
lower = make_one_range_bound(key, -1, spec->lowerdatums, true);
upper = make_one_range_bound(key, -1, spec->upperdatums, false);
#else
lower = make_one_partition_rbound(key, -1, spec->lowerdatums, true);
upper = make_one_partition_rbound(key, -1, spec->upperdatums, false);
#endif
/*
* First check if the resulting range would be empty with
* specified lower and upper bounds
*/
#if PG_VERSION_NUM < 110000
if (partition_rbound_cmp(key, lower->datums,
lower->kind, true, upper) >= 0)
#else
if (partition_rbound_cmp(key->partnatts, key->partsupfunc,
key->partcollation, lower->datums,
lower->kind, true, upper) >= 0)
#endif
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_OBJECT_DEFINITION),
@ -3049,8 +3146,13 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
Assert(boundinfo &&
boundinfo->strategy == PARTITION_STRATEGY_RANGE &&
#if PG_VERSION_NUM < 110000
boundinfo->ndatums > 0
#else
(boundinfo->ndatums > 0 ||
partition_bound_has_default(boundinfo)));
partition_bound_has_default(boundinfo))
#endif
);
/*
* Test whether the new lower bound (which is treated
@ -3067,11 +3169,16 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
* since the index array is initialised with an extra -1
* at the end.
*/
#if PG_VERSION_NUM < 110000
offset = partition_bound_bsearch(key, boundinfo, lower,
true, &equal);
#else
offset = partition_range_bsearch(key->partnatts,
key->partsupfunc,
key->partcollation,
boundinfo, lower,
&equal);
#endif
if (boundinfo->indexes[offset + 1] < 0)
{
@ -3084,6 +3191,11 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
if (offset + 1 < boundinfo->ndatums)
{
int32 cmpval;
#if PG_VERSION_NUM < 110000
cmpval = partition_bound_cmp(key, boundinfo,
offset + 1, upper,
true);
#else
Datum *datums;
PartitionRangeDatumKind *kind;
bool is_lower;
@ -3097,6 +3209,7 @@ hypo_check_new_partition_bound(char *relname, hypoTable *parent,
key->partcollation,
datums, kind,
is_lower, upper);
#endif
if (cmpval < 0)
{
/*

View file

@ -16,7 +16,7 @@
#include "nodes/pg_list.h"
#include "optimizer/planner.h"
#include "optimizer/pathnode.h"
#if PG_VERSION_NUM >= 100000
#if PG_VERSION_NUM >= 110000
#include "partitioning/partbounds.h"
#endif
#include "utils/rel.h"
@ -41,6 +41,8 @@ extern char *get_am_name(Oid amOid);
extern void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf);
#if PG_VERSION_NUM >= 100000
/* pg10 only imports */
#if PG_VERSION_NUM < 110000
/*
* Imported from src/backend/catalog/partition.c, not exported
@ -83,7 +85,19 @@ typedef struct PartitionRangeBound
PartitionRangeDatumKind *kind; /* the kind of each datum */
bool lower; /* this is the lower (vs upper) bound */
} PartitionRangeBound;
#endif
PartitionRangeBound *make_one_range_bound(PartitionKey key, int index,
List *datums, bool lower);
int partition_bound_bsearch(PartitionKey key, PartitionBoundInfo boundinfo,
void *probe, bool probe_is_bound, bool *is_equal);
int32 partition_bound_cmp(PartitionKey key,
PartitionBoundInfo boundinfo,
int offset, void *probe, bool probe_is_bound);
int32 partition_rbound_cmp(PartitionKey key,
Datum *datums1, PartitionRangeDatumKind *kind1,
bool lower1, PartitionRangeBound *b2);
#endif /* pg10 only imports */
/* Context info needed for invoking a recursive querytree display routine */
typedef struct