Add the partition estimation feature

This commit is contained in:
yuzupy 2018-04-02 09:50:30 +00:00 committed by Julien Rouhaud
parent ef5668408a
commit 7aae71d138
5 changed files with 527 additions and 464 deletions

View file

@ -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);
}

View file

@ -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

View file

@ -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;

View file

@ -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)

View file

@ -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