mirror of
https://github.com/HypoPG/hypopg
synced 2026-05-24 01:28:51 +00:00
Add the partition estimation feature
This commit is contained in:
parent
ef5668408a
commit
7aae71d138
5 changed files with 527 additions and 464 deletions
25
hypopg.c
25
hypopg.c
|
|
@ -305,7 +305,7 @@ hypo_get_relation_info_hook(PlannerInfo *root,
|
|||
bool inhparent,
|
||||
RelOptInfo *rel)
|
||||
{
|
||||
if (HYPO_ENABLED())
|
||||
if (HYPO_ENABLED())
|
||||
{
|
||||
Relation relation;
|
||||
|
||||
|
|
@ -341,8 +341,8 @@ hypo_get_relation_info_hook(PlannerInfo *root,
|
|||
|
||||
if(hypo_table_oid_is_hypothetical(relationObjectId))
|
||||
/*
|
||||
* this relation is table we want to partition hypothetical,
|
||||
* inject hypothetical partitioning
|
||||
* this relation is table we want to partition hypothetical,
|
||||
* inject hypothetical partitioning
|
||||
*/
|
||||
hypo_injectHypotheticalPartitioning(root, relationObjectId, rel);
|
||||
|
||||
|
|
@ -354,17 +354,18 @@ hypo_get_relation_info_hook(PlannerInfo *root,
|
|||
/*
|
||||
* if this child relation is excluded by constraints, call set_dummy_rel_pathlist
|
||||
*/
|
||||
static void
|
||||
static void
|
||||
hypo_set_rel_pathlist_hook(PlannerInfo *root,
|
||||
RelOptInfo *rel,
|
||||
Index rti,
|
||||
RangeTblEntry *rte)
|
||||
RelOptInfo *rel,
|
||||
Index rti,
|
||||
RangeTblEntry *rte)
|
||||
{
|
||||
if(HYPO_ENABLED() && hypo_table_oid_is_hypothetical(rte->relid) && rte->relkind == 'r')
|
||||
hypo_markDummyIfExcluded(root,rel,rti,rte);
|
||||
|
||||
if (prev_set_rel_pathlist_hook)
|
||||
prev_set_rel_pathlist_hook(root, rel, rti, rte);
|
||||
if(HYPO_ENABLED() && hypo_table_oid_is_hypothetical(rte->relid)
|
||||
&& rte->relkind == 'r')
|
||||
hypo_setPartitionPathlist(root,rel,rti,rte);
|
||||
|
||||
if (prev_set_rel_pathlist_hook)
|
||||
prev_set_rel_pathlist_hook(root, rel, rti, rte);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
467
hypopg_import.c
467
hypopg_import.c
|
|
@ -37,6 +37,14 @@
|
|||
#include "utils/ruleutils.h"
|
||||
#endif
|
||||
#include "optimizer/clauses.h"
|
||||
#if PG_VERSION_NUM >= 110000
|
||||
#include "catalog/partition.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/paths.h"
|
||||
#include "partitioning/partbounds.h"
|
||||
#include "utils/partcache.h"
|
||||
#include "partitioning/partdefs.h"
|
||||
#endif
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parse_coerce.h"
|
||||
|
|
@ -49,12 +57,11 @@
|
|||
#include "utils/rel.h"
|
||||
#include "utils/syscache.h"
|
||||
|
||||
|
||||
#include "include/hypopg_import.h"
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Copied from src/backend/optimizer/util/plancat.c, not exported.
|
||||
*
|
||||
* Build a targetlist representing the columns of the specified index.
|
||||
|
|
@ -819,6 +826,7 @@ make_one_range_bound(PartitionKey key, int index, List *datums, bool lower)
|
|||
|
||||
return bound;
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
|
|
@ -831,74 +839,9 @@ qsort_partition_rbound_cmp(const void *a, const void *b, void *arg)
|
|||
PartitionRangeBound *b2 = (*(PartitionRangeBound *const *) b);
|
||||
PartitionKey key = (PartitionKey) arg;
|
||||
|
||||
return partition_rbound_cmp(key, b1->datums, b1->kind, b1->lower, b2);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* partition_rbound_cmp
|
||||
*
|
||||
* Return for two range bounds whether the 1st one (specified in datums1,
|
||||
* 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;
|
||||
return partition_rbound_cmp(key->partnatts, key->partsupfunc,
|
||||
key->partcollation, b1->datums, b1->kind,
|
||||
b1->lower, b2);
|
||||
}
|
||||
|
||||
/* ----------
|
||||
|
|
@ -1254,104 +1197,104 @@ Expr *
|
|||
make_partition_op_expr(PartitionKey key, int keynum,
|
||||
uint16 strategy, Expr *arg1, Expr *arg2)
|
||||
{
|
||||
Oid operoid;
|
||||
bool need_relabel = false;
|
||||
Expr *result = NULL;
|
||||
|
||||
/* Get the correct btree operator for this partitioning column */
|
||||
operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
|
||||
|
||||
/*
|
||||
* Chosen operator may be such that the non-Const operand needs to be
|
||||
* coerced, so apply the same; see the comment in
|
||||
* get_partition_operator().
|
||||
*/
|
||||
if (!IsA(arg1, Const) &&
|
||||
(need_relabel ||
|
||||
key->partcollation[keynum] != key->parttypcoll[keynum]))
|
||||
arg1 = (Expr *) makeRelabelType(arg1,
|
||||
key->partopcintype[keynum],
|
||||
-1,
|
||||
key->partcollation[keynum],
|
||||
COERCE_EXPLICIT_CAST);
|
||||
Oid operoid;
|
||||
bool need_relabel = false;
|
||||
Expr *result = NULL;
|
||||
|
||||
/* Generate the actual expression */
|
||||
switch (key->strategy)
|
||||
{
|
||||
case PARTITION_STRATEGY_LIST:
|
||||
{
|
||||
List *elems = (List *) arg2;
|
||||
int nelems = list_length(elems);
|
||||
|
||||
Assert(nelems >= 1);
|
||||
Assert(keynum == 0);
|
||||
|
||||
if (nelems > 1 &&
|
||||
!type_is_array(key->parttypid[keynum]))
|
||||
{
|
||||
ArrayExpr *arrexpr;
|
||||
ScalarArrayOpExpr *saopexpr;
|
||||
|
||||
/* Construct an ArrayExpr for the right-hand inputs */
|
||||
arrexpr = makeNode(ArrayExpr);
|
||||
arrexpr->array_typeid =
|
||||
get_array_type(key->parttypid[keynum]);
|
||||
arrexpr->array_collid = key->parttypcoll[keynum];
|
||||
arrexpr->element_typeid = key->parttypid[keynum];
|
||||
arrexpr->elements = elems;
|
||||
arrexpr->multidims = false;
|
||||
arrexpr->location = -1;
|
||||
|
||||
/* Build leftop = ANY (rightop) */
|
||||
saopexpr = makeNode(ScalarArrayOpExpr);
|
||||
saopexpr->opno = operoid;
|
||||
saopexpr->opfuncid = get_opcode(operoid);
|
||||
saopexpr->useOr = true;
|
||||
saopexpr->inputcollid = key->partcollation[keynum];
|
||||
saopexpr->args = list_make2(arg1, arrexpr);
|
||||
saopexpr->location = -1;
|
||||
|
||||
result = (Expr *) saopexpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
List *elemops = NIL;
|
||||
ListCell *lc;
|
||||
|
||||
foreach (lc, elems)
|
||||
{
|
||||
Expr *elem = lfirst(lc),
|
||||
*elemop;
|
||||
|
||||
elemop = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, elem,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
elemops = lappend(elemops, elemop);
|
||||
}
|
||||
|
||||
result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PARTITION_STRATEGY_RANGE:
|
||||
result = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, arg2,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "invalid partitioning strategy");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
/* Get the correct btree operator for this partitioning column */
|
||||
operoid = get_partition_operator(key, keynum, strategy, &need_relabel);
|
||||
|
||||
/*
|
||||
* Chosen operator may be such that the non-Const operand needs to be
|
||||
* coerced, so apply the same; see the comment in
|
||||
* get_partition_operator().
|
||||
*/
|
||||
if (!IsA(arg1, Const) &&
|
||||
(need_relabel ||
|
||||
key->partcollation[keynum] != key->parttypcoll[keynum]))
|
||||
arg1 = (Expr *) makeRelabelType(arg1,
|
||||
key->partopcintype[keynum],
|
||||
-1,
|
||||
key->partcollation[keynum],
|
||||
COERCE_EXPLICIT_CAST);
|
||||
|
||||
/* Generate the actual expression */
|
||||
switch (key->strategy)
|
||||
{
|
||||
case PARTITION_STRATEGY_LIST:
|
||||
{
|
||||
List *elems = (List *) arg2;
|
||||
int nelems = list_length(elems);
|
||||
|
||||
Assert(nelems >= 1);
|
||||
Assert(keynum == 0);
|
||||
|
||||
if (nelems > 1 &&
|
||||
!type_is_array(key->parttypid[keynum]))
|
||||
{
|
||||
ArrayExpr *arrexpr;
|
||||
ScalarArrayOpExpr *saopexpr;
|
||||
|
||||
/* Construct an ArrayExpr for the right-hand inputs */
|
||||
arrexpr = makeNode(ArrayExpr);
|
||||
arrexpr->array_typeid =
|
||||
get_array_type(key->parttypid[keynum]);
|
||||
arrexpr->array_collid = key->parttypcoll[keynum];
|
||||
arrexpr->element_typeid = key->parttypid[keynum];
|
||||
arrexpr->elements = elems;
|
||||
arrexpr->multidims = false;
|
||||
arrexpr->location = -1;
|
||||
|
||||
/* Build leftop = ANY (rightop) */
|
||||
saopexpr = makeNode(ScalarArrayOpExpr);
|
||||
saopexpr->opno = operoid;
|
||||
saopexpr->opfuncid = get_opcode(operoid);
|
||||
saopexpr->useOr = true;
|
||||
saopexpr->inputcollid = key->partcollation[keynum];
|
||||
saopexpr->args = list_make2(arg1, arrexpr);
|
||||
saopexpr->location = -1;
|
||||
|
||||
result = (Expr *) saopexpr;
|
||||
}
|
||||
else
|
||||
{
|
||||
List *elemops = NIL;
|
||||
ListCell *lc;
|
||||
|
||||
foreach (lc, elems)
|
||||
{
|
||||
Expr *elem = lfirst(lc),
|
||||
*elemop;
|
||||
|
||||
elemop = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, elem,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
elemops = lappend(elemops, elemop);
|
||||
}
|
||||
|
||||
result = nelems > 1 ? makeBoolExpr(OR_EXPR, elemops, -1) : linitial(elemops);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case PARTITION_STRATEGY_RANGE:
|
||||
result = make_opclause(operoid,
|
||||
BOOLOID,
|
||||
false,
|
||||
arg1, arg2,
|
||||
InvalidOid,
|
||||
key->partcollation[keynum]);
|
||||
break;
|
||||
|
||||
default:
|
||||
elog(ERROR, "invalid partitioning strategy");
|
||||
break;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -1379,84 +1322,84 @@ get_range_key_properties(PartitionKey key, int keynum,
|
|||
Expr **keyCol,
|
||||
Const **lower_val, Const **upper_val)
|
||||
{
|
||||
/* Get partition key expression for this column */
|
||||
if (key->partattrs[keynum] != 0)
|
||||
{
|
||||
*keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[keynum],
|
||||
key->parttypid[keynum],
|
||||
key->parttypmod[keynum],
|
||||
key->parttypcoll[keynum],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
*keyCol = copyObject(lfirst(*partexprs_item));
|
||||
*partexprs_item = lnext(*partexprs_item);
|
||||
}
|
||||
/* Get partition key expression for this column */
|
||||
if (key->partattrs[keynum] != 0)
|
||||
{
|
||||
*keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[keynum],
|
||||
key->parttypid[keynum],
|
||||
key->parttypmod[keynum],
|
||||
key->parttypcoll[keynum],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (*partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
*keyCol = copyObject(lfirst(*partexprs_item));
|
||||
*partexprs_item = lnext(*partexprs_item);
|
||||
}
|
||||
|
||||
/* Get appropriate Const nodes for the bounds */
|
||||
if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*lower_val = castNode(Const, copyObject(ldatum->value));
|
||||
else
|
||||
*lower_val = NULL;
|
||||
/* Get appropriate Const nodes for the bounds */
|
||||
if (ldatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*lower_val = castNode(Const, copyObject(ldatum->value));
|
||||
else
|
||||
*lower_val = NULL;
|
||||
|
||||
if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*upper_val = castNode(Const, copyObject(udatum->value));
|
||||
else
|
||||
*upper_val = NULL;
|
||||
if (udatum->kind == PARTITION_RANGE_DATUM_VALUE)
|
||||
*upper_val = castNode(Const, copyObject(udatum->value));
|
||||
else
|
||||
*upper_val = NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* get_range_nulltest
|
||||
*
|
||||
* A non-default range partition table does not currently allow partition
|
||||
* keys to be null, so emit an IS NOT NULL expression for each key column.
|
||||
*/
|
||||
/*
|
||||
* Copied from src/backend/catalog/partition.c, not exported
|
||||
*
|
||||
* get_range_nulltest
|
||||
*
|
||||
* A non-default range partition table does not currently allow partition
|
||||
* keys to be null, so emit an IS NOT NULL expression for each key column.
|
||||
*/
|
||||
List *
|
||||
get_range_nulltest(PartitionKey key)
|
||||
{
|
||||
List *result = NIL;
|
||||
NullTest *nulltest;
|
||||
ListCell *partexprs_item;
|
||||
int i;
|
||||
|
||||
partexprs_item = list_head(key->partexprs);
|
||||
for (i = 0; i < key->partnatts; i++)
|
||||
{
|
||||
Expr *keyCol;
|
||||
|
||||
if (key->partattrs[i] != 0)
|
||||
List *result = NIL;
|
||||
NullTest *nulltest;
|
||||
ListCell *partexprs_item;
|
||||
int i;
|
||||
|
||||
partexprs_item = list_head(key->partexprs);
|
||||
for (i = 0; i < key->partnatts; i++)
|
||||
{
|
||||
keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[i],
|
||||
key->parttypid[i],
|
||||
key->parttypmod[i],
|
||||
key->parttypcoll[i],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
keyCol = copyObject(lfirst(partexprs_item));
|
||||
partexprs_item = lnext(partexprs_item);
|
||||
Expr *keyCol;
|
||||
|
||||
if (key->partattrs[i] != 0)
|
||||
{
|
||||
keyCol = (Expr *) makeVar(1,
|
||||
key->partattrs[i],
|
||||
key->parttypid[i],
|
||||
key->parttypmod[i],
|
||||
key->parttypcoll[i],
|
||||
0);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (partexprs_item == NULL)
|
||||
elog(ERROR, "wrong number of partition key expressions");
|
||||
keyCol = copyObject(lfirst(partexprs_item));
|
||||
partexprs_item = lnext(partexprs_item);
|
||||
}
|
||||
|
||||
nulltest = makeNode(NullTest);
|
||||
nulltest->arg = keyCol;
|
||||
nulltest->nulltesttype = IS_NOT_NULL;
|
||||
nulltest->argisrow = false;
|
||||
nulltest->location = -1;
|
||||
result = lappend(result, nulltest);
|
||||
}
|
||||
|
||||
nulltest = makeNode(NullTest);
|
||||
nulltest->arg = keyCol;
|
||||
nulltest->nulltesttype = IS_NOT_NULL;
|
||||
nulltest->argisrow = false;
|
||||
nulltest->location = -1;
|
||||
result = lappend(result, nulltest);
|
||||
}
|
||||
|
||||
return result;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -1565,4 +1508,60 @@ make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
|||
*translated_vars = vars;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Copied from src/backend/optimizer/path/allpaths.c, not exported
|
||||
*
|
||||
* set_plain_rel_pathlist
|
||||
* Build access paths for a plain relation (no subquery, no inheritance)
|
||||
*/
|
||||
void
|
||||
set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
|
||||
{
|
||||
Relids required_outer;
|
||||
|
||||
/*
|
||||
* We don't support pushing join clauses into the quals of a seqscan, but
|
||||
* it could still have required parameterization due to LATERAL refs in
|
||||
* its tlist.
|
||||
*/
|
||||
required_outer = rel->lateral_relids;
|
||||
|
||||
/* Consider sequential scan */
|
||||
add_path(rel, create_seqscan_path(root, rel, required_outer, 0));
|
||||
|
||||
/* If appropriate, consider parallel sequential scan */
|
||||
if (rel->consider_parallel && required_outer == NULL)
|
||||
create_plain_partial_paths(root, rel);
|
||||
|
||||
/* Consider index scans */
|
||||
create_index_paths(root, rel);
|
||||
|
||||
/* Consider TID scans */
|
||||
create_tidscan_paths(root, rel);
|
||||
}
|
||||
|
||||
/*
|
||||
* Copied from src/backend/optimizer/path/allpaths.c, not exported
|
||||
*
|
||||
* create_plain_partial_paths
|
||||
* Build partial access paths for parallel scan of a plain relation
|
||||
*/
|
||||
void
|
||||
create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel)
|
||||
{
|
||||
int parallel_workers;
|
||||
|
||||
parallel_workers = compute_parallel_worker(rel, rel->pages, -1,
|
||||
max_parallel_workers_per_gather);
|
||||
|
||||
/* If any limit was set to zero, the user doesn't want a parallel scan. */
|
||||
if (parallel_workers <= 0)
|
||||
return;
|
||||
|
||||
/* Add an unordered partial path based on a parallel sequential scan. */
|
||||
add_partial_path(rel, create_seqscan_path(root, rel, NULL, parallel_workers));
|
||||
}
|
||||
|
||||
|
||||
#endif
|
||||
|
|
|
|||
487
hypopg_table.c
487
hypopg_table.c
|
|
@ -26,8 +26,9 @@
|
|||
#include "access/htup_details.h"
|
||||
#include "access/nbtree.h"
|
||||
#include "catalog/namespace.h"
|
||||
#include "catalog/partition.h"
|
||||
#include "catalog/pg_class.h"
|
||||
#include "catalog/pg_inherits_fn.h"
|
||||
#include "catalog/pg_inherits.h"
|
||||
#include "catalog/pg_opclass.h"
|
||||
#include "catalog/pg_type.h"
|
||||
#include "nodes/makefuncs.h"
|
||||
|
|
@ -35,8 +36,11 @@
|
|||
#include "nodes/nodes.h"
|
||||
#include "optimizer/clauses.h"
|
||||
#include "optimizer/cost.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "optimizer/predtest.h"
|
||||
#include "optimizer/prep.h"
|
||||
#include "optimizer/restrictinfo.h"
|
||||
#include "optimizer/var.h"
|
||||
#include "parser/parsetree.h"
|
||||
#include "parser/parse_utilcmd.h"
|
||||
#include "rewrite/rewriteManip.h"
|
||||
|
|
@ -45,8 +49,10 @@
|
|||
#include "utils/datum.h"
|
||||
#include "utils/fmgroids.h"
|
||||
#include "utils/lsyscache.h"
|
||||
#include "utils/partcache.h"
|
||||
#include "utils/ruleutils.h"
|
||||
#include "utils/syscache.h"
|
||||
#include "partitioning/partbounds.h"
|
||||
#endif
|
||||
|
||||
#include "include/hypopg.h"
|
||||
|
|
@ -91,14 +97,14 @@ static const hypoTable *hypo_table_store_parsetree(CreateStmt *node,
|
|||
const char *queryString, Oid parentid);
|
||||
static PartitionBoundSpec *hypo_transformPartitionBound(ParseState *pstate,
|
||||
hypoTable *parent, PartitionBoundSpec *spec);
|
||||
static void hypo_partition_table(PlannerInfo *root, RelOptInfo *rel,
|
||||
static void hypo_partition_table(PlannerInfo *root, RelOptInfo *rel,
|
||||
hypoTable *entry);
|
||||
static List *hypo_get_partition_constraints(PlannerInfo *root, RelOptInfo *rel,
|
||||
static List *hypo_get_partition_constraints(PlannerInfo *root, RelOptInfo *rel,
|
||||
hypoTable *parent);
|
||||
static List *hypo_get_qual_from_partbound(hypoTable *parent, PartitionBoundSpec *spec);
|
||||
static List *hypo_get_qual_for_hash(hypoTable *parent, PartitionBoundSpec *spec);
|
||||
static List *hypo_get_qual_for_list(hypoTable *parent, PartitionBoundSpec *spec);
|
||||
static List *hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec,
|
||||
static List *hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec,
|
||||
bool for_default);
|
||||
|
||||
#define HYPO_RTI_IS_TAGGED(rti, root) (planner_rt_fetch(rti, root)->security_barrier)
|
||||
|
|
@ -829,7 +835,7 @@ hypo_generate_partkey(CreateStmt *stmt, Oid parentid, hypoTable *entry)
|
|||
key->parttypid[i] = exprType(lfirst(partexprs_item));
|
||||
key->parttypmod[i] = exprTypmod(lfirst(partexprs_item));
|
||||
key->parttypcoll[i] = exprCollation(lfirst(partexprs_item));
|
||||
|
||||
|
||||
partexprs_item = lnext(partexprs_item);
|
||||
}
|
||||
get_typlenbyvalalign(key->parttypid[i],
|
||||
|
|
@ -909,7 +915,7 @@ hypo_generate_part_scheme(CreateStmt *stmt, PartitionKey partkey, Oid
|
|||
//part_scheme->parttypcoll = (Oid *) palloc(sizeof(Oid) * partnatts);
|
||||
//memcpy(part_scheme->parttypcoll, partkey->parttypcoll,
|
||||
// sizeof(Oid) * partnatts);
|
||||
|
||||
|
||||
part_scheme->parttyplen = (int16 *) palloc(sizeof(int16) * partnatts);
|
||||
memcpy(part_scheme->parttyplen, partkey->parttyplen,
|
||||
sizeof(int16) * partnatts);
|
||||
|
|
@ -1732,226 +1738,279 @@ hypo_transformPartitionBound(ParseState *pstate, hypoTable *parent,
|
|||
* the hypothetical partitioning to this rel
|
||||
*/
|
||||
void
|
||||
hypo_injectHypotheticalPartitioning(PlannerInfo *root,
|
||||
Oid relationObjectId,
|
||||
hypo_injectHypotheticalPartitioning(PlannerInfo *root,
|
||||
Oid relationObjectId,
|
||||
RelOptInfo *rel)
|
||||
{
|
||||
hypoTable *parent;
|
||||
hypoTable *parent;
|
||||
|
||||
Assert(HYPO_ENABLED());
|
||||
Assert(hypo_table_oid_is_hypothetical(relationObjectId));
|
||||
|
||||
parent = hypo_find_table(relationObjectId);
|
||||
Assert(HYPO_ENABLED());
|
||||
Assert(hypo_table_oid_is_hypothetical(relationObjectId));
|
||||
|
||||
/*
|
||||
* if this rel is parent, prepare some structures to inject
|
||||
* hypothetical partitioning
|
||||
*/
|
||||
if(!HYPO_RTI_IS_TAGGED(rel->relid,root))
|
||||
{
|
||||
List *inhoids;
|
||||
int nparts, i;
|
||||
int oldsize = root->simple_rel_array_size;
|
||||
RangeTblEntry *rte;
|
||||
List *partitioned_child_rels = NIL;
|
||||
ListCell *cell;
|
||||
AppendRelInfo *appinfo;
|
||||
PartitionedChildRelInfo *pcinfo;
|
||||
|
||||
/* get all of the partition oids */
|
||||
inhoids = hypo_find_inheritance_children(parent);
|
||||
nparts = list_length(inhoids);
|
||||
|
||||
/* resize and clean rte and rel arrays */
|
||||
root->simple_rel_array_size = oldsize + nparts + 1;
|
||||
root->simple_rel_array = (RelOptInfo **)
|
||||
repalloc(root->simple_rel_array,
|
||||
root->simple_rel_array_size *
|
||||
sizeof(RelOptInfo *));
|
||||
root->simple_rte_array = (RangeTblEntry **)
|
||||
repalloc(root->simple_rte_array,
|
||||
root->simple_rel_array_size *
|
||||
sizeof(RangeTblEntry *));
|
||||
|
||||
for (i=oldsize; i<root->simple_rel_array_size; i++)
|
||||
parent = hypo_find_table(relationObjectId);
|
||||
|
||||
/*
|
||||
* if this rel is parent, prepare some structures to inject
|
||||
* hypothetical partitioning
|
||||
*/
|
||||
if(!HYPO_RTI_IS_TAGGED(rel->relid,root))
|
||||
{
|
||||
root->simple_rel_array[i] = NULL;
|
||||
root->simple_rte_array[i] = NULL;
|
||||
}
|
||||
|
||||
/* rewrite and restore this rel's rte */
|
||||
rte = root->simple_rte_array[rel->relid];
|
||||
rte->relkind = RELKIND_PARTITIONED_TABLE;
|
||||
rte->inh = true;
|
||||
|
||||
root->simple_rte_array[rel->relid] = rte;
|
||||
root->simple_rte_array[oldsize] = rte;
|
||||
|
||||
partitioned_child_rels = lappend_int(partitioned_child_rels,
|
||||
oldsize);
|
||||
root->parse->rtable = lappend(root->parse->rtable,
|
||||
root->simple_rte_array[oldsize]);
|
||||
|
||||
HYPO_TAG_RTI(rel->relid, root);
|
||||
HYPO_TAG_RTI(oldsize, root);
|
||||
|
||||
List *inhoids;
|
||||
int nparts, i;
|
||||
int oldsize = root->simple_rel_array_size;
|
||||
RangeTblEntry *rte;
|
||||
List *partitioned_child_rels = NIL;
|
||||
ListCell *cell;
|
||||
AppendRelInfo *appinfo;
|
||||
PartitionedChildRelInfo *pcinfo;
|
||||
|
||||
/*
|
||||
* create RangeTblEntries and AppendRelInfos hypothetically
|
||||
* for all hypothetical partitions
|
||||
*/
|
||||
i = 1;
|
||||
foreach(cell, inhoids)
|
||||
{
|
||||
int newrelid;
|
||||
Oid childOid = lfirst_oid(cell);
|
||||
hypoTable *child;
|
||||
RangeTblEntry *childrte;
|
||||
Relation parentrel;
|
||||
|
||||
child = hypo_find_table(childOid);
|
||||
newrelid = oldsize + i;
|
||||
|
||||
childrte = copyObject(rte);
|
||||
childrte->rtekind = RTE_RELATION;
|
||||
childrte->relid = relationObjectId; //originalOID;
|
||||
childrte->relkind = RELKIND_RELATION;
|
||||
childrte->inh = false;
|
||||
if(!childrte->alias)
|
||||
childrte->alias = makeNode(Alias);
|
||||
childrte->alias->aliasname = child->tablename;
|
||||
/* FIXME maybe use a mapping array here instead of rte->values_lists*/
|
||||
childrte->values_lists = list_make1_oid(child->oid); //partitionOID
|
||||
root->simple_rte_array[newrelid] = childrte;
|
||||
HYPO_TAG_RTI(newrelid, root);
|
||||
|
||||
appinfo = makeNode(AppendRelInfo);
|
||||
appinfo->parent_relid = rel->relid;
|
||||
appinfo->child_relid = newrelid;
|
||||
parentrel = heap_open(relationObjectId, NoLock);
|
||||
appinfo->parent_reltype = parentrel->rd_rel->reltype;
|
||||
appinfo->child_reltype = parentrel->rd_rel->reltype;
|
||||
make_inh_translation_list(parentrel, parentrel, newrelid,
|
||||
&appinfo->translated_vars);
|
||||
heap_close(parentrel, NoLock);
|
||||
appinfo->parent_reloid = relationObjectId;
|
||||
root->append_rel_list = lappend(root->append_rel_list,
|
||||
appinfo);
|
||||
root->parse->rtable = lappend(root->parse->rtable,
|
||||
/* get all of the partition oids */
|
||||
inhoids = hypo_find_inheritance_children(parent);
|
||||
nparts = list_length(inhoids);
|
||||
|
||||
/* resize and clean rte and rel arrays */
|
||||
root->simple_rel_array_size = oldsize + nparts + 1;
|
||||
root->simple_rel_array = (RelOptInfo **)
|
||||
repalloc(root->simple_rel_array,
|
||||
root->simple_rel_array_size *
|
||||
sizeof(RelOptInfo *));
|
||||
root->simple_rte_array = (RangeTblEntry **)
|
||||
repalloc(root->simple_rte_array,
|
||||
root->simple_rel_array_size *
|
||||
sizeof(RangeTblEntry *));
|
||||
|
||||
for (i=oldsize; i<root->simple_rel_array_size; i++)
|
||||
{
|
||||
root->simple_rel_array[i] = NULL;
|
||||
root->simple_rte_array[i] = NULL;
|
||||
}
|
||||
|
||||
/* rewrite and restore this rel's rte */
|
||||
rte = root->simple_rte_array[rel->relid];
|
||||
rte->relkind = RELKIND_PARTITIONED_TABLE;
|
||||
rte->inh = true;
|
||||
|
||||
root->simple_rte_array[rel->relid] = rte;
|
||||
root->simple_rte_array[oldsize] = rte;
|
||||
|
||||
partitioned_child_rels = lappend_int(partitioned_child_rels,
|
||||
oldsize);
|
||||
root->parse->rtable = lappend(root->parse->rtable,
|
||||
root->simple_rte_array[oldsize]);
|
||||
|
||||
HYPO_TAG_RTI(rel->relid, root);
|
||||
HYPO_TAG_RTI(oldsize, root);
|
||||
|
||||
|
||||
/*
|
||||
* create RangeTblEntries and AppendRelInfos hypothetically
|
||||
* for all hypothetical partitions
|
||||
*/
|
||||
i = 1;
|
||||
foreach(cell, inhoids)
|
||||
{
|
||||
int newrelid;
|
||||
Oid childOid = lfirst_oid(cell);
|
||||
hypoTable *child;
|
||||
RangeTblEntry *childrte;
|
||||
Relation parentrel;
|
||||
|
||||
child = hypo_find_table(childOid);
|
||||
newrelid = oldsize + i;
|
||||
|
||||
childrte = copyObject(rte);
|
||||
childrte->rtekind = RTE_RELATION;
|
||||
childrte->relid = relationObjectId; //originalOID;
|
||||
childrte->relkind = RELKIND_RELATION;
|
||||
childrte->inh = false;
|
||||
if(!childrte->alias)
|
||||
childrte->alias = makeNode(Alias);
|
||||
childrte->alias->aliasname = child->tablename;
|
||||
/* FIXME maybe use a mapping array here instead of rte->values_lists*/
|
||||
childrte->values_lists = list_make1_oid(child->oid); //partitionOID
|
||||
root->simple_rte_array[newrelid] = childrte;
|
||||
HYPO_TAG_RTI(newrelid, root);
|
||||
|
||||
appinfo = makeNode(AppendRelInfo);
|
||||
appinfo->parent_relid = rel->relid;
|
||||
appinfo->child_relid = newrelid;
|
||||
parentrel = heap_open(relationObjectId, NoLock);
|
||||
appinfo->parent_reltype = parentrel->rd_rel->reltype;
|
||||
appinfo->child_reltype = parentrel->rd_rel->reltype;
|
||||
make_inh_translation_list(parentrel, parentrel, newrelid,
|
||||
&appinfo->translated_vars);
|
||||
heap_close(parentrel, NoLock);
|
||||
appinfo->parent_reloid = relationObjectId;
|
||||
root->append_rel_list = lappend(root->append_rel_list,
|
||||
appinfo);
|
||||
root->parse->rtable = lappend(root->parse->rtable,
|
||||
root->simple_rte_array[newrelid]);
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
/* create pcinfo hypothetically for this rel */
|
||||
pcinfo = makeNode(PartitionedChildRelInfo);
|
||||
pcinfo->parent_relid = oldsize;
|
||||
pcinfo->child_rels = partitioned_child_rels;
|
||||
root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
|
||||
|
||||
/* add partition info to this rel */
|
||||
hypo_partition_table(root, rel, parent);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* if this rel is partition, rewrite tuples and pages using selectivity
|
||||
* which is computed according to its partition constraints
|
||||
*/
|
||||
if (rel->reloptkind != RELOPT_BASEREL
|
||||
&&HYPO_RTI_IS_TAGGED(rel->relid,root))
|
||||
{
|
||||
List *constraints;
|
||||
PlannerInfo *root_dummy;
|
||||
Selectivity selectivity;
|
||||
double pages;
|
||||
|
||||
/* get its partition constraints */
|
||||
constraints = hypo_get_partition_constraints(root, rel, parent);
|
||||
|
||||
/*
|
||||
* to compute selectivity, make dummy PlannerInfo and then rewrite
|
||||
* tuples and pages using this selectivity
|
||||
*/
|
||||
root_dummy = makeNode(PlannerInfo);
|
||||
root_dummy = root;
|
||||
root_dummy->simple_rel_array[rel->relid] = rel;
|
||||
|
||||
selectivity = clauselist_selectivity(root_dummy,
|
||||
constraints,
|
||||
0,
|
||||
JOIN_INNER,
|
||||
NULL);
|
||||
|
||||
pages = ceil(rel->pages * selectivity);
|
||||
rel->pages = (BlockNumber)pages;
|
||||
rel->tuples = clamp_row_est(rel->tuples * selectivity);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
/* create pcinfo hypothetically for this rel */
|
||||
pcinfo = makeNode(PartitionedChildRelInfo);
|
||||
pcinfo->parent_relid = oldsize;
|
||||
pcinfo->child_rels = partitioned_child_rels;
|
||||
root->pcinfo_list = lappend(root->pcinfo_list, pcinfo);
|
||||
|
||||
/* add partition info to this rel */
|
||||
hypo_partition_table(root, rel, parent);
|
||||
}
|
||||
|
||||
/*
|
||||
* If this rel is partition, we add the partition constraints to the
|
||||
* rte->securityQuals so that the relation which is need not be scanned
|
||||
* is marked as Dummy at the set_append_rel_size() and the rel->rows is
|
||||
* computed correctly at the set_baserel_size_estimates(). We shouldn't
|
||||
* rewrite the rel->pages and the rel->tuples here, because they will be
|
||||
* rewritten at the later hook.
|
||||
*
|
||||
* TODO: should comfirm that the tuples will not referred till the
|
||||
* set_baserel_size_esimates() and think about rel->reltarget->width
|
||||
*
|
||||
*/
|
||||
if (rel->reloptkind != RELOPT_BASEREL
|
||||
&&HYPO_RTI_IS_TAGGED(rel->relid,root))
|
||||
{
|
||||
List *constraints;
|
||||
|
||||
/* get its partition constraints */
|
||||
constraints = hypo_get_partition_constraints(root, rel, parent);
|
||||
|
||||
/*
|
||||
* to compute rel->rows at set_baserel_size_estimates using parent's
|
||||
* statistics, parent's tuples and baserestrictinfo, we add the partition
|
||||
* constraints to its rte->securityQuals
|
||||
*/
|
||||
planner_rt_fetch(rel->relid, root)->securityQuals = list_make1(constraints);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* If this rel is need not be scanned, we have to mark it as dummy to omit it
|
||||
* from the appendrel
|
||||
*
|
||||
* It is inspired on relation_excluded_by_constraints
|
||||
* If this rel is partition, we remove the partition constraints from the
|
||||
* its rel->baserestrictinfo and rewrite some items of its RelOptInfo:
|
||||
* the rel->pages, the rel->tuples rel->baserestrictcost. After that
|
||||
* we call the set_plain_rel_pathlist() to re-create its pathlist using
|
||||
* the new RelOptInfo.
|
||||
*
|
||||
*/
|
||||
void hypo_markDummyIfExcluded(PlannerInfo *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte)
|
||||
void hypo_setPartitionPathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte)
|
||||
{
|
||||
hypoTable *parent;
|
||||
List *constraints;
|
||||
List *safe_constraints = NIL;
|
||||
ListCell *lc;
|
||||
ListCell *l;
|
||||
Index parentRTindex;
|
||||
RelOptInfo *parentrel;
|
||||
hypoTable *parent = hypo_find_table(rte->relid);
|
||||
List *constraints = hypo_get_partition_constraints(root, rel, parent);
|
||||
PlannerInfo *root_dummy;
|
||||
Selectivity selectivity;
|
||||
double pages;
|
||||
|
||||
Assert(HYPO_ENABLED());
|
||||
Assert(hypo_table_oid_is_hypothetical(rte->relid));
|
||||
Assert(rte->relkind == 'r');
|
||||
/*
|
||||
* get the parent's rel and copy its rel->baserestrictinfo to
|
||||
* the own rel->baserestrictinfo.
|
||||
* this part is inspired on set_append_rel_size().
|
||||
*/
|
||||
foreach(l, root->append_rel_list)
|
||||
{
|
||||
AppendRelInfo *appinfo = (AppendRelInfo *)lfirst(l);
|
||||
List *childquals = NIL;
|
||||
Index cq_min_security = UINT_MAX;
|
||||
ListCell *lc;
|
||||
|
||||
parent = hypo_find_table(rte->relid);
|
||||
|
||||
/* get its partition constraints */
|
||||
constraints = hypo_get_partition_constraints(root, rel, parent);
|
||||
|
||||
/*
|
||||
* We do not currently enforce that CHECK constraints contain only
|
||||
* immutable functions, so it's necessary to check here. We daren't draw
|
||||
* conclusions from plan-time evaluation of non-immutable functions. Since
|
||||
* they're ANDed, we can just ignore any mutable constraints in the list,
|
||||
* and reason about the rest.
|
||||
*/
|
||||
foreach(lc, constraints)
|
||||
{
|
||||
Node *pred = (Node *) lfirst(lc);
|
||||
|
||||
if (!contain_mutable_functions(pred))
|
||||
safe_constraints = lappend(safe_constraints, pred);
|
||||
}
|
||||
|
||||
/* if this partition need not be scanned, we call the set_dummy_rel_pathlist()
|
||||
* to mark it as dummy */
|
||||
if (predicate_refuted_by(safe_constraints, rel->baserestrictinfo, false))
|
||||
set_dummy_rel_pathlist(rel);
|
||||
|
||||
if(appinfo->child_relid == rti)
|
||||
{
|
||||
parentRTindex = appinfo->parent_relid;
|
||||
parentrel = root->simple_rel_array[parentRTindex];
|
||||
|
||||
/*
|
||||
TODO: re-estimate parent size just like set_append_rel_size()
|
||||
*/
|
||||
|
||||
|
||||
foreach(lc, parentrel->baserestrictinfo)
|
||||
{
|
||||
RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
|
||||
Node *childqual;
|
||||
ListCell *lc2;
|
||||
|
||||
Assert(IsA(rinfo, RestrictInfo));
|
||||
childqual = adjust_appendrel_attrs(root,
|
||||
(Node *) rinfo->clause,
|
||||
1, &appinfo);
|
||||
childqual = eval_const_expressions(root, childqual);
|
||||
|
||||
/* might have gotten an AND clause, if so flatten it */
|
||||
foreach(lc2, make_ands_implicit((Expr *) childqual))
|
||||
{
|
||||
Node *onecq = (Node *) lfirst(lc2);
|
||||
bool pseudoconstant;
|
||||
|
||||
/* check for pseudoconstant (no Vars or volatile functions) */
|
||||
pseudoconstant =
|
||||
!contain_vars_of_level(onecq, 0) &&
|
||||
!contain_volatile_functions(onecq);
|
||||
if (pseudoconstant)
|
||||
{
|
||||
/* tell createplan.c to check for gating quals */
|
||||
root->hasPseudoConstantQuals = true;
|
||||
}
|
||||
/* reconstitute RestrictInfo with appropriate properties */
|
||||
childquals = lappend(childquals,
|
||||
make_restrictinfo((Expr *) onecq,
|
||||
rinfo->is_pushed_down,
|
||||
rinfo->outerjoin_delayed,
|
||||
pseudoconstant,
|
||||
rinfo->security_level,
|
||||
NULL, NULL, NULL));
|
||||
/* track minimum security level among child quals */
|
||||
cq_min_security = Min(cq_min_security, rinfo->security_level);
|
||||
}
|
||||
}
|
||||
rel->baserestrictinfo = childquals;
|
||||
rel->baserestrict_min_security = cq_min_security;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* make dummy PlannerInfo to compute the selectivity, and then rewrite
|
||||
* tuples and pages using this selectivity
|
||||
*/
|
||||
root_dummy = makeNode(PlannerInfo);
|
||||
root_dummy = root;
|
||||
root_dummy->simple_rel_array[rti] = rel;
|
||||
|
||||
selectivity = clauselist_selectivity(root_dummy,
|
||||
constraints,
|
||||
0,
|
||||
JOIN_INNER,
|
||||
NULL);
|
||||
|
||||
pages = ceil(rel->pages * selectivity);
|
||||
rel->pages = (BlockNumber)pages;
|
||||
rel->tuples = clamp_row_est(rel->tuples * selectivity);
|
||||
|
||||
/* recompute the rel->baserestrictcost*/
|
||||
cost_qual_eval(&rel->baserestrictcost, rel->baserestrictinfo, root);
|
||||
|
||||
/*
|
||||
* call the set_plain_rel_pathlist() to re-create its pathlist using
|
||||
* the new RelOptInfo
|
||||
*/
|
||||
set_plain_rel_pathlist(root, rel, rte);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* If this is the table we want to hypothetically partition, modifies its
|
||||
* metadata to add partitioning information
|
||||
*/
|
||||
static void
|
||||
hypo_partition_table(PlannerInfo *root, RelOptInfo *rel, hypoTable *entry)
|
||||
{
|
||||
{
|
||||
PartitionDesc partdesc;
|
||||
PartitionKey partkey;
|
||||
|
||||
|
||||
partdesc = hypo_generate_partitiondesc(entry);
|
||||
partkey = entry->partkey;
|
||||
rel->part_scheme = entry->part_scheme;
|
||||
|
|
@ -1968,8 +2027,8 @@ hypo_partition_table(PlannerInfo *root, RelOptInfo *rel, hypoTable *entry)
|
|||
*/
|
||||
static List *
|
||||
hypo_get_partition_constraints(PlannerInfo *root, RelOptInfo *rel, hypoTable *parent)
|
||||
{
|
||||
ListCell *lc;
|
||||
{
|
||||
ListCell *lc;
|
||||
Oid childOid;
|
||||
hypoTable *child;
|
||||
PartitionBoundSpec *spec;
|
||||
|
|
@ -1980,10 +2039,10 @@ hypo_get_partition_constraints(PlannerInfo *root, RelOptInfo *rel, hypoTable *pa
|
|||
childOid = lfirst_oid(lc);
|
||||
child = hypo_find_table(childOid);
|
||||
spec = child->boundspec;
|
||||
|
||||
|
||||
/* get its partition constraints */
|
||||
constraints = hypo_get_qual_from_partbound(parent,spec);
|
||||
|
||||
|
||||
if (constraints)
|
||||
{
|
||||
/*
|
||||
|
|
@ -1992,20 +2051,20 @@ hypo_get_partition_constraints(PlannerInfo *root, RelOptInfo *rel, hypoTable *pa
|
|||
*/
|
||||
constraints = (List *) eval_const_expressions(root, (Node *) constraints);
|
||||
/* FIXME this func will be modified at pg11 */
|
||||
constraints = (List *) canonicalize_qual((Expr *) constraints);
|
||||
|
||||
constraints = (List *) canonicalize_qual((Expr *) constraints, true);
|
||||
|
||||
/* Fix Vars to have the desired varno */
|
||||
if (rel->relid != 1)
|
||||
ChangeVarNodes((Node *) constraints, 1, rel->relid, 0);
|
||||
|
||||
}
|
||||
}
|
||||
return constraints;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* Return the list of executable expressions as partition constraint
|
||||
* Return the list of executable expressions as partition constraint
|
||||
*
|
||||
* Heavily inspired on get_qual_from_partbound
|
||||
*/
|
||||
|
|
@ -2016,15 +2075,15 @@ hypo_get_qual_from_partbound(hypoTable *parent, PartitionBoundSpec *spec)
|
|||
List *my_qual = NIL;
|
||||
|
||||
Assert(key != NULL);
|
||||
|
||||
|
||||
switch (key->strategy)
|
||||
{
|
||||
|
||||
|
||||
case PARTITION_STRATEGY_HASH:
|
||||
Assert(spec->strategy == PARTITION_STRATEGY_HASH);
|
||||
my_qual = hypo_get_qual_for_hash(parent, spec);
|
||||
break;
|
||||
|
||||
|
||||
case PARTITION_STRATEGY_LIST:
|
||||
Assert(spec->strategy == PARTITION_STRATEGY_LIST);
|
||||
my_qual = hypo_get_qual_for_list(parent, spec);
|
||||
|
|
@ -2039,7 +2098,7 @@ hypo_get_qual_from_partbound(hypoTable *parent, PartitionBoundSpec *spec)
|
|||
elog(ERROR, "unexpected partition strategy: %d",
|
||||
(int) key->strategy);
|
||||
}
|
||||
|
||||
|
||||
return my_qual;
|
||||
}
|
||||
|
||||
|
|
@ -2329,9 +2388,9 @@ hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec, bool for_de
|
|||
*upper_or_start_datum;
|
||||
bool need_next_lower_arm,
|
||||
need_next_upper_arm;
|
||||
|
||||
|
||||
if (spec->is_default)
|
||||
{
|
||||
{
|
||||
List *or_expr_args = NIL;
|
||||
PartitionDesc pdesc = hypo_generate_partitiondesc(parent);
|
||||
Oid *inhoids = pdesc->oids;
|
||||
|
|
@ -2340,7 +2399,7 @@ hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec, bool for_de
|
|||
|
||||
for (i = 0; i < nparts; i++)
|
||||
{
|
||||
Oid inhrelid = inhoids[i]; //is this a parent oid or dummy child oid?
|
||||
Oid inhrelid = inhoids[i]; //is this a parent oid or dummy child oid?
|
||||
HeapTuple tuple;
|
||||
Datum datum;
|
||||
bool isnull;
|
||||
|
|
@ -2409,7 +2468,7 @@ hypo_get_qual_for_range(hypoTable *parent, PartitionBoundSpec *spec, bool for_de
|
|||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
lower_or_start_datum = list_head(spec->lowerdatums);
|
||||
upper_or_start_datum = list_head(spec->upperdatums);
|
||||
num_or_arms = key->partnatts;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,8 @@
|
|||
|
||||
#include "nodes/pg_list.h"
|
||||
#include "optimizer/planner.h"
|
||||
#include "optimizer/pathnode.h"
|
||||
#include "partitioning/partbounds.h"
|
||||
#include "utils/rel.h"
|
||||
|
||||
|
||||
|
|
@ -36,6 +38,7 @@ extern char *get_am_name(Oid amOid);
|
|||
extern void get_opclass_name(Oid opclass, Oid actual_datatype, StringInfo buf);
|
||||
|
||||
#if PG_VERSION_NUM >= 100000
|
||||
#if PG_VERSION_NUM < 110000
|
||||
/*
|
||||
* Imported from src/backend/catalog/partition.c, not exported
|
||||
*/
|
||||
|
|
@ -77,6 +80,7 @@ typedef struct PartitionRangeBound
|
|||
PartitionRangeDatumKind *kind; /* the kind of each datum */
|
||||
bool lower; /* this is the lower (vs upper) bound */
|
||||
} PartitionRangeBound;
|
||||
#endif
|
||||
|
||||
/* Context info needed for invoking a recursive querytree display routine */
|
||||
typedef struct
|
||||
|
|
@ -108,9 +112,6 @@ int32 qsort_partition_list_value_cmp(const void *a, const void *b, void *arg);
|
|||
PartitionRangeBound *make_one_range_bound(PartitionKey key, int index, List
|
||||
*datums, bool lower);
|
||||
int32 qsort_partition_rbound_cmp(const void *a, const void *b, void *arg);
|
||||
int32 partition_rbound_cmp(PartitionKey key,
|
||||
Datum *datums1, PartitionRangeDatumKind *kind1,
|
||||
bool lower1, PartitionRangeBound *b2);
|
||||
void get_const_expr(Const *constval, deparse_context *context, int
|
||||
showtype);
|
||||
void get_const_collation(Const *constval, deparse_context *context);
|
||||
|
|
@ -132,7 +133,8 @@ List *get_range_nulltest(PartitionKey key);
|
|||
void make_inh_translation_list(Relation oldrelation, Relation newrelation,
|
||||
Index newvarno,
|
||||
List **translated_vars);
|
||||
|
||||
void set_plain_rel_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte);
|
||||
void create_plain_partial_paths(PlannerInfo *root, RelOptInfo *rel);
|
||||
/* Copied from src/backend/catalog/partition.c, not exported */
|
||||
#define partition_bound_accepts_nulls(bi) ((bi)->null_index != -1)
|
||||
|
||||
|
|
|
|||
|
|
@ -73,5 +73,7 @@ void hypo_injectHypotheticalPartitioning(PlannerInfo *root,
|
|||
RelOptInfo *rel);
|
||||
void hypo_markDummyIfExcluded(PlannerInfo *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte);
|
||||
void hypo_setPartitionPathlist(PlannerInfo *root, RelOptInfo *rel,
|
||||
Index rti, RangeTblEntry *rte);
|
||||
|
||||
#endif
|
||||
|
|
|
|||
Loading…
Reference in a new issue