mirror of
https://github.com/HypoPG/hypopg
synced 2026-05-24 01:28:51 +00:00
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:
parent
f07b82e387
commit
eefa430ed9
5 changed files with 412 additions and 13 deletions
7
hypopg.c
7
hypopg.c
|
|
@ -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
|
||||
)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
265
hypopg_import.c
265
hypopg_import.c
|
|
@ -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
|
||||
}
|
||||
|
||||
/* ----------
|
||||
|
|
|
|||
129
hypopg_table.c
129
hypopg_table.c
|
|
@ -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)
|
||||
{
|
||||
/*
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
Loading…
Reference in a new issue