0001-Implement-runtime-partiton-pruning_v6.patch
application/octet-stream
Filename: 0001-Implement-runtime-partiton-pruning_v6.patch
Type: application/octet-stream
Part: 0
Patch
Format: unified
Series: patch v6-0001
| File | + | − |
|---|---|---|
| src/backend/catalog/partition.c | 111 | 17 |
| src/backend/commands/explain.c | 15 | 0 |
| src/backend/executor/execPartition.c | 1 | 3 |
| src/backend/executor/nodeAppend.c | 159 | 10 |
| src/backend/nodes/copyfuncs.c | 5 | 0 |
| src/backend/optimizer/path/allpaths.c | 134 | 10 |
| src/backend/optimizer/path/joinrels.c | 1 | 1 |
| src/backend/optimizer/plan/createplan.c | 24 | 0 |
| src/backend/optimizer/plan/planner.c | 1 | 1 |
| src/backend/optimizer/prep/prepunion.c | 2 | 2 |
| src/backend/optimizer/util/clauses.c | 19 | 0 |
| src/backend/optimizer/util/pathnode.c | 51 | 1 |
| src/backend/optimizer/util/relnode.c | 20 | 1 |
| src/include/catalog/partition.h | 4 | 1 |
| src/include/executor/execPartition.h | 3 | 0 |
| src/include/nodes/execnodes.h | 12 | 0 |
| src/include/nodes/plannodes.h | 8 | 0 |
| src/include/nodes/relation.h | 18 | 0 |
| src/include/optimizer/clauses.h | 1 | 0 |
| src/include/optimizer/pathnode.h | 2 | 2 |
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index f07ac15..b4a4965 100644
--- a/src/backend/catalog/partition.c
+++ b/src/backend/catalog/partition.c
@@ -34,6 +34,7 @@
#include "catalog/pg_type.h"
#include "commands/tablecmds.h"
#include "executor/executor.h"
+#include "executor/nodeSubplan.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
#include "nodes/nodeFuncs.h"
@@ -272,11 +273,14 @@ static uint64 compute_hash_value(PartitionKey key, Datum *values, bool *isnull);
PG_FUNCTION_INFO_V1(satisfies_hash_partition);
static Bitmapset *get_partitions_from_clauses_recurse(Relation relation,
- int rt_index, List *clauses);
+ int rt_index, List *clauses,
+ ParamListInfo base_prmlist,
+ ExprContext *exontext);
static int classify_partition_bounding_keys(Relation relation, List *clauses,
int rt_index,
PartScanKeyInfo *keys, bool *constfalse,
- List **or_clauses);
+ List **or_clauses, ParamListInfo base_prmlist,
+ ExprContext *econtext);
static void remove_redundant_clauses(PartitionKey partkey,
int partattoff, List *all_clauses,
List **result, bool *constfalse);
@@ -286,7 +290,8 @@ static bool partition_cmp_args(PartitionKey key, int partattoff,
static int32 partition_op_strategy(PartitionKey key, PartClause *op,
bool *incl);
static bool partkey_datum_from_expr(PartitionKey key, int partattoff,
- Expr *expr, Datum *value);
+ Expr *expr, Datum *value, ParamListInfo base_prmlist,
+ ExprContext *econtext);
static Bitmapset *get_partitions_for_keys(Relation rel,
PartScanKeyInfo *keys);
@@ -1659,6 +1664,37 @@ get_partition_qual_relid(Oid relid)
return result;
}
+/* get_leaf_part_recurse
+ * Get the leaf oids for the given rel.
+ */
+void
+get_leaf_part_recurse(Relation rel, List **leaf_part_oids)
+{
+ PartitionDesc partdesc = RelationGetPartitionDesc(rel);
+ int i;
+
+ check_stack_depth();
+
+ for (i = 0; i < partdesc->nparts; i++)
+ {
+ Oid partrelid = partdesc->oids[i];
+
+ if (get_rel_relkind(partrelid) != RELKIND_PARTITIONED_TABLE)
+ *leaf_part_oids = lappend_oid(*leaf_part_oids, partrelid);
+ else
+ {
+ /*
+ * We assume all tables in the partition tree were already locked
+ * by the caller.
+ */
+ Relation partrel = heap_open(partrelid, NoLock);
+
+ get_leaf_part_recurse(partrel, leaf_part_oids);
+ heap_close(partrel, NoLock);
+ }
+ }
+}
+
/*
* get_partitions_from_clauses
* Determine the set of partitions of relation that will satisfy all
@@ -1669,7 +1705,8 @@ get_partition_qual_relid(Oid relid)
*/
Bitmapset *
get_partitions_from_clauses(Relation relation, int rt_index,
- List *partclauses)
+ List *partclauses, ParamListInfo base_prmlist,
+ ExprContext *econtext)
{
Bitmapset *result;
List *partconstr = RelationGetPartitionQual(relation);
@@ -1703,7 +1740,8 @@ get_partitions_from_clauses(Relation relation, int rt_index,
}
result = get_partitions_from_clauses_recurse(relation, rt_index,
- partclauses);
+ partclauses, base_prmlist,
+ econtext);
return result;
}
@@ -1719,7 +1757,8 @@ get_partitions_from_clauses(Relation relation, int rt_index,
*/
static Bitmapset *
get_partitions_from_clauses_recurse(Relation relation, int rt_index,
- List *clauses)
+ List *clauses, ParamListInfo base_prmlist,
+ ExprContext *econtext)
{
PartitionDesc partdesc = RelationGetPartitionDesc(relation);
Bitmapset *result = NULL;
@@ -1735,7 +1774,8 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
*/
nkeys = classify_partition_bounding_keys(relation, clauses, rt_index,
&keys, &constfalse,
- &or_clauses);
+ &or_clauses, base_prmlist,
+ econtext);
/*
* The analysis of the matched clauses done by
@@ -1797,7 +1837,9 @@ get_partitions_from_clauses_recurse(Relation relation, int rt_index,
arg_partset = get_partitions_from_clauses_recurse(relation,
rt_index,
- arg_clauses);
+ arg_clauses,
+ base_prmlist,
+ econtext);
/*
* Partition sets obtained from mutually-disjunctive clauses are
@@ -1853,7 +1895,8 @@ static int
classify_partition_bounding_keys(Relation relation, List *clauses,
int rt_index,
PartScanKeyInfo *keys, bool *constfalse,
- List **or_clauses)
+ List **or_clauses, ParamListInfo base_prmlist,
+ ExprContext *econtext)
{
PartitionKey partkey = RelationGetPartitionKey(relation);
int i;
@@ -1893,6 +1936,9 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
continue;
}
}
+ /* when called from ExecReScanAppend */
+ else if (IsA(lfirst(lc), ExprState))
+ clause = ((ExprState *) lfirst(lc))->expr;
else
clause = (Expr *) lfirst(lc);
@@ -2305,7 +2351,8 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
if (op_strategy < 0 &&
need_next_max &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->maxkeys[i]))
+ &keys->maxkeys[i], base_prmlist,
+ econtext))
{
keys->n_maxkeys++;
keys->max_incl = incl;
@@ -2317,12 +2364,14 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
Assert(incl);
if (need_next_eq &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->eqkeys[i]))
+ &keys->eqkeys[i], base_prmlist,
+ econtext))
keys->n_eqkeys++;
if (need_next_max &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->maxkeys[i]))
+ &keys->maxkeys[i], base_prmlist,
+ econtext))
{
keys->n_maxkeys++;
keys->max_incl = true;
@@ -2330,7 +2379,8 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
if (need_next_min &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->minkeys[i]))
+ &keys->minkeys[i], base_prmlist,
+ econtext))
{
keys->n_minkeys++;
keys->min_incl = true;
@@ -2338,7 +2388,8 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
}
else if (need_next_min &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->minkeys[i]))
+ &keys->minkeys[i], base_prmlist,
+ econtext))
{
keys->n_minkeys++;
keys->min_incl = incl;
@@ -2426,7 +2477,8 @@ partition_op_strategy(PartitionKey key, PartClause *op, bool *incl)
*/
static bool
partkey_datum_from_expr(PartitionKey key, int partattoff,
- Expr *expr, Datum *value)
+ Expr *expr, Datum *value, ParamListInfo base_prmlist,
+ ExprContext *econtext)
{
Oid exprtype = exprType((Node *) expr);
@@ -2467,6 +2519,46 @@ partkey_datum_from_expr(PartitionKey key, int partattoff,
*value = ((Const *) expr)->constvalue;
return true;
+ case T_Param:
+ switch (((Param *) expr)->paramkind)
+ {
+ case PARAM_EXTERN:
+ if (base_prmlist)
+ {
+ Node *n;
+
+ n = eval_const_expressions_from_list(base_prmlist,
+ (Node *) expr);
+
+ if (IsA(n, Const))
+ {
+ *value = ((Const *) n)->constvalue;
+ return true;
+ }
+ }
+ return false;
+
+ case PARAM_EXEC:
+ if (econtext)
+ {
+ Param *param = (Param *) expr;
+ ParamExecData *prm;
+
+ prm = &(econtext->ecxt_param_exec_vals[param->paramid]);
+ if (unlikely(prm->execPlan != NULL))
+ {
+ ExecSetParamPlan(prm->execPlan, econtext);
+ Assert(prm->execPlan == NULL);
+ }
+ *value = prm->value;
+ return true;
+ }
+
+ default:
+ return false;
+ }
+ return false;
+
default:
return false;
}
@@ -2728,10 +2820,12 @@ partition_cmp_args(PartitionKey key, int partattoff,
Assert(op->valid_cache && leftarg->valid_cache && rightarg->valid_cache);
/* Get the constant values from the operands */
if (!partkey_datum_from_expr(key, partattoff,
- leftarg->constarg, &leftarg_const))
+ leftarg->constarg, &leftarg_const,
+ NULL, NULL))
return false;
if (!partkey_datum_from_expr(key, partattoff,
- rightarg->constarg, &rightarg_const))
+ rightarg->constarg, &rightarg_const,
+ NULL, NULL))
return false;
/*
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
index 447f69d..06c62cb 100644
--- a/src/backend/commands/explain.c
+++ b/src/backend/commands/explain.c
@@ -1347,6 +1347,21 @@ ExplainNode(PlanState *planstate, List *ancestors,
if (es->format == EXPLAIN_FORMAT_TEXT)
appendStringInfoChar(es->str, '\n');
+ /* run-time pruning information for Append node */
+ if (es->analyze && IsA(plan, Append))
+ {
+ Append *append = (Append *) plan;
+
+ if (append->base_params)
+ show_scan_qual(append->base_params, "Runtime Partition Pruning",
+ planstate, ancestors, es);
+
+ if (append->join_clauses)
+ show_scan_qual(append->join_clauses,
+ "Runtime Partition Pruning Join Filter",
+ planstate, ancestors, es);
+ }
+
/* target list */
if (es->verbose)
show_plan_tlist(planstate, ancestors, es);
diff --git a/src/backend/executor/execPartition.c b/src/backend/executor/execPartition.c
index d275cef..187d30f 100644
--- a/src/backend/executor/execPartition.c
+++ b/src/backend/executor/execPartition.c
@@ -23,8 +23,6 @@
#include "utils/rls.h"
#include "utils/ruleutils.h"
-static PartitionDispatch *RelationGetPartitionDispatchInfo(Relation rel,
- int *num_parted, List **leaf_part_oids);
static void get_partition_dispatch_recurse(Relation rel, Relation parent,
List **pds, List **leaf_part_oids);
static void FormPartitionKeyDatum(PartitionDispatch pd,
@@ -275,7 +273,7 @@ ExecFindPartition(ResultRelInfo *resultRelInfo, PartitionDispatch *pd,
* All the relations in the partition tree (including 'rel') must have been
* locked (using at least the AccessShareLock) by the caller.
*/
-static PartitionDispatch *
+PartitionDispatch *
RelationGetPartitionDispatchInfo(Relation rel,
int *num_parted, List **leaf_part_oids)
{
diff --git a/src/backend/executor/nodeAppend.c b/src/backend/executor/nodeAppend.c
index 1d2fb35..9d36657 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -57,7 +57,9 @@
#include "postgres.h"
+#include "catalog/pg_inherits_fn.h"
#include "executor/execdebug.h"
+#include "executor/execPartition.h"
#include "executor/nodeAppend.h"
#include "miscadmin.h"
@@ -108,6 +110,65 @@ exec_append_initialize_next(AppendState *appendstate)
}
/* ----------------------------------------------------------------
+ * set_append_subplan_indexes
+ *
+ * Determine the subplans to scan based on the clauses.
+ * ----------------------------------------------------------------
+ */
+static void
+set_append_subplan_indexes(AppendState *node, List *clauses)
+{
+ Bitmapset *partset = NULL,
+ *subplans = NULL;
+ PartitionDispatch *pd = (PartitionDispatch *) node->pd,
+ parent,
+ *p1;
+ List *parents = NIL;
+ int cur_index,
+ i;
+
+ parents = lappend(parents, &pd[0]);
+ node->subplan_indexes = NIL;
+ do
+ {
+ p1 = linitial(parents);
+ parent = *p1;
+
+ partset = get_partitions_from_clauses(parent->reldesc,
+ 1,
+ list_copy(clauses),
+ node->es_param_list_info,
+ node->ps.ps_ExprContext);
+
+ if (!bms_is_empty(partset))
+ {
+ while ((cur_index = bms_first_member(partset)) >= 0)
+ {
+ if (parent->indexes[cur_index] >= 0)
+ subplans =
+ bms_add_member(subplans, parent->indexes[cur_index]);
+ else
+ parents =
+ lappend(parents, &pd[-parent->indexes[cur_index]]);
+ }
+ }
+ parents = list_delete_first(parents);
+ } while (parents);
+
+ if (!bms_is_empty(subplans))
+ {
+ while ((i = bms_first_member(subplans)) >= 0)
+ {
+ int index = node->append_paths_array[i];
+
+ if (index >= 0)
+ node->subplan_indexes = lappend_int(node->subplan_indexes,
+ index);
+ }
+ }
+}
+
+/* ----------------------------------------------------------------
* ExecInitAppend
*
* Begin all of the subscans of the append node.
@@ -151,17 +212,22 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
+ appendstate->subplan_indexes = NIL;
+ appendstate->as_whichpartition = -1;
+ appendstate->append_paths_size = node->append_paths_size;
+ appendstate->append_paths_array = node->append_paths_array;
+ appendstate->parentoid = node->parentoid;
/*
* Miscellaneous initialization
- *
- * Append plans don't have expression contexts because they never call
- * ExecQual or ExecProject.
*/
+ /* create expression context for node */
+ ExecAssignExprContext(estate, &appendstate->ps);
+
/*
- * append nodes still have Result slots, which hold pointers to tuples, so
- * we have to initialize them.
+ * append nodes have Result slots, which hold pointers to tuples, so we
+ * have to initialize them.
*/
ExecInitResultTupleSlot(estate, &appendstate->ps);
@@ -178,9 +244,39 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
i++;
}
- /*
- * initialize output tuple type
- */
+ if (node->base_params)
+ {
+ appendstate->base_params = node->base_params;
+ appendstate->es_param_list_info = estate->es_param_list_info;
+ }
+
+ if (node->join_clauses)
+ appendstate->join_clauses = ExecInitExprList(node->join_clauses,
+ (PlanState *) appendstate);
+
+ if(node->base_params || node->join_clauses)
+ {
+ Relation rel;
+ PartitionDispatch *pd;
+ List *leaf_part_oids = NIL;
+ int num_parted;
+ /*
+ * Get the information about the partition tree after locking all the
+ * partitions.
+ */
+ rel = relation_open(node->parentoid, NoLock);
+ pd = RelationGetPartitionDispatchInfo(rel, &num_parted, &leaf_part_oids);
+ relation_close(rel, NoLock);
+ appendstate->pd = pd;
+ for (i = 1; i < num_parted; i++)
+ {
+ PartitionDispatch partdispatch = pd[i];
+
+ heap_close(partdispatch->reldesc, NoLock);
+ ExecDropSingleTupleTableSlot(partdispatch->tupslot);
+ }
+ }
+
ExecAssignResultTypeFromTL(&appendstate->ps);
appendstate->ps.ps_ProjInfo = NULL;
@@ -204,6 +300,19 @@ ExecAppend(PlanState *pstate)
{
AppendState *node = castNode(AppendState, pstate);
+ /* Determine the subplans to scan depending on the base_params */
+ if (node->base_params && node->as_whichpartition == -1)
+ {
+ set_append_subplan_indexes(node, node->base_params);
+ if (node->subplan_indexes)
+ {
+ node->as_whichplan = linitial_int(node->subplan_indexes);
+ node->as_whichpartition = 0;
+ }
+ else
+ node->as_whichplan = 0;
+ }
+
for (;;)
{
PlanState *subnode;
@@ -212,8 +321,19 @@ ExecAppend(PlanState *pstate)
CHECK_FOR_INTERRUPTS();
/*
+ * end scan if no subplan is selected for the current join_clauses
+ * and/or base_params
+ */
+ if ((node->join_clauses || node->base_params)
+ && node->as_whichpartition == -1)
+ return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+
+ /*
* figure out which subplan we are currently processing
*/
+ if (node->as_whichpartition != -1)
+ node->as_whichplan = list_nth_int(node->subplan_indexes,
+ node->as_whichpartition);
subnode = node->appendplans[node->as_whichplan];
/*
@@ -237,7 +357,22 @@ ExecAppend(PlanState *pstate)
* ExecInitAppend.
*/
if (ScanDirectionIsForward(node->ps.state->es_direction))
- node->as_whichplan++;
+ {
+ /*
+ * For runtime partition pruning, goto the next valid partition
+ * index
+ */
+ if (node->subplan_indexes)
+ {
+ if (++node->as_whichpartition < list_length(node->subplan_indexes))
+ node->as_whichplan = list_nth_int(node->subplan_indexes,
+ node->as_whichpartition);
+ else
+ return ExecClearTuple(node->ps.ps_ResultTupleSlot);
+ }
+ else
+ node->as_whichplan++;
+ }
else
node->as_whichplan--;
if (!exec_append_initialize_next(node))
@@ -280,6 +415,10 @@ ExecReScanAppend(AppendState *node)
{
int i;
+ /* Determine subplans to scan based on the new Params */
+ if (node->ps.chgParam != NULL && node->join_clauses)
+ set_append_subplan_indexes(node, node->join_clauses);
+
for (i = 0; i < node->as_nplans; i++)
{
PlanState *subnode = node->appendplans[i];
@@ -298,6 +437,16 @@ ExecReScanAppend(AppendState *node)
if (subnode->chgParam == NULL)
ExecReScan(subnode);
}
- node->as_whichplan = 0;
+
+ if (node->subplan_indexes)
+ {
+ node->as_whichplan = linitial_int(node->subplan_indexes);
+ node->as_whichpartition = 0;
+ }
+ else
+ {
+ node->as_whichplan = 0;
+ node->as_whichpartition = -1;
+ }
exec_append_initialize_next(node);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d9ff8a7..4af11e8 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -242,6 +242,11 @@ _copyAppend(const Append *from)
*/
COPY_NODE_FIELD(partitioned_rels);
COPY_NODE_FIELD(appendplans);
+ COPY_NODE_FIELD(base_params);
+ COPY_NODE_FIELD(join_clauses);
+ COPY_SCALAR_FIELD(parentoid);
+ COPY_POINTER_FIELD(append_paths_array, from->append_paths_size * sizeof(int));
+ COPY_SCALAR_FIELD(append_paths_size);
return newnode;
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6b087ec..78d064a 100644
--- a/src/backend/optimizer/path/allpaths.c
+++ b/src/backend/optimizer/path/allpaths.c
@@ -26,6 +26,7 @@
#include "catalog/pg_opfamily.h"
#include "catalog/pg_proc.h"
#include "catalog/pg_type.h"
+#include "catalog/pg_inherits_fn.h"
#include "foreign/fdwapi.h"
#include "miscadmin.h"
#include "nodes/makefuncs.h"
@@ -144,9 +145,10 @@ static List *get_append_rel_partitions(PlannerInfo *root,
static List *match_clauses_to_partkey(PlannerInfo *root,
RelOptInfo *rel,
List *clauses,
+ bool *contains_param,
bool *contains_const,
bool *constfalse);
-
+static int list_member_oid_index(List *list, Oid datum);
/*
* make_one_rel
@@ -289,6 +291,27 @@ set_base_rel_sizes(PlannerInfo *root)
if (root->glob->parallelModeOK)
set_rel_consider_parallel(root, rel, rte);
+ if (rte->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ List *leaf_parts = NIL;
+ Relation parent = relation_open(rte->relid, NoLock);
+ int i;
+
+ /* fetch the leaf oids of the parent rel */
+ (void) find_all_inheritors(RelationGetRelid(parent), AccessShareLock, NULL);
+ get_leaf_part_recurse(parent, &leaf_parts);
+ relation_close(parent, NoLock);
+
+ /* initialize necessary root variables */
+ root->append_paths_size = list_length(leaf_parts);
+ root->leaf_node_oids = leaf_parts;
+ root->append_paths_array = palloc0(root->append_paths_size * sizeof(int));
+ root->baserestrictinfo_param_indexes = NIL;
+ root->append_paths_count = 0;
+
+ for (i = 0; i < root->append_paths_size; i++)
+ root->append_paths_array[i] = -1;
+ }
set_rel_size(root, rel, rti, rte);
}
}
@@ -350,6 +373,40 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
{
/* It's an "append relation", process accordingly */
set_append_rel_size(root, rel, rti, rte);
+
+ /*
+ * If this rel is part of a join then collect the necessary join
+ * clauses required for runtime partition pruning.
+ */
+ if (rel->joininfo && rel->part_scheme)
+ {
+ List *partclauses;
+ bool contains_param,
+ contains_const,
+ constfalse;
+
+ /*
+ * Get the clauses that match the partition key
+ */
+ partclauses = match_clauses_to_partkey(root, rel,
+ list_copy(rel->joininfo),
+ &contains_param,
+ &contains_const,
+ &constfalse);
+
+ if (partclauses != NIL)
+ {
+ ListCell *lc;
+
+ foreach(lc, partclauses)
+ {
+ Node *n = lfirst(lc);
+
+ if (!list_member(root->join_clauses, n))
+ root->join_clauses = lappend(root->join_clauses, n);
+ }
+ }
+ }
}
else
{
@@ -871,7 +928,8 @@ get_append_rel_partitions(PlannerInfo *root,
{
List *partclauses;
bool contains_const,
- constfalse;
+ constfalse,
+ contains_param;
/*
* Get the clauses that match the partition key, including information
@@ -880,6 +938,7 @@ get_append_rel_partitions(PlannerInfo *root,
*/
partclauses = match_clauses_to_partkey(root, rel,
list_copy(rel->baserestrictinfo),
+ &contains_param,
&contains_const,
&constfalse);
@@ -897,7 +956,7 @@ get_append_rel_partitions(PlannerInfo *root,
*/
if (partclauses != NIL && contains_const)
partindexes = get_partitions_from_clauses(parent, rel->relid,
- partclauses);
+ partclauses, NULL, NULL);
/*
* Else there are no clauses that are useful to prune any paritions,
@@ -964,17 +1023,21 @@ get_append_rel_partitions(PlannerInfo *root,
*
* If the list contains a pseudo-constant RestrictInfo with constant false
* value, *constfalse is set.
+ *
+ * If the list has a param, *contains_param is set
*/
static List *
match_clauses_to_partkey(PlannerInfo *root,
RelOptInfo *rel,
List *clauses,
+ bool *contains_param,
bool *contains_const,
bool *constfalse)
{
PartitionScheme partscheme = rel->part_scheme;
List *result = NIL;
ListCell *lc;
+ int clause_index = -1;
*contains_const = false;
*constfalse = false;
@@ -987,6 +1050,8 @@ match_clauses_to_partkey(PlannerInfo *root,
Expr *clause;
int i;
+ clause_index++;
+
if (IsA(member, RestrictInfo))
{
RestrictInfo *rinfo = (RestrictInfo *) member;
@@ -1024,14 +1089,24 @@ match_clauses_to_partkey(PlannerInfo *root,
bool arg_matches_key = false,
matched_arg_contains_const = false,
all_args_constfalse = true;
+ List *base_param_indexes;
+
+ /*
+ * Make a copy of root's baserestrictinfo_param_indexes before
+ * the recursive call
+ */
+ base_param_indexes =
+ list_copy(root->baserestrictinfo_param_indexes);
foreach (lc1, orclause->args)
{
Node *arg = lfirst(lc1);
- bool contains_const1,
- constfalse1;
+ bool contains_const1;
+ bool constfalse1;
+ bool contains_param1;
if (match_clauses_to_partkey(root, rel, list_make1(arg),
+ &contains_param1,
&contains_const1,
&constfalse1) != NIL)
{
@@ -1042,8 +1117,22 @@ match_clauses_to_partkey(PlannerInfo *root,
/* We got at least one arg that is not constant false. */
if (!constfalse1)
all_args_constfalse = false;
+
+ /*
+ * We got at least one arg which is Param, so add the
+ * current clause_index to the base_param_indexes list.
+ */
+ if (contains_param1)
+ {
+ *contains_param = true;
+ base_param_indexes =
+ list_append_unique_int(base_param_indexes,
+ clause_index);
+ }
}
+ root->baserestrictinfo_param_indexes = base_param_indexes;
+
if (arg_matches_key)
{
result = lappend(result, clause);
@@ -1150,6 +1239,15 @@ match_clauses_to_partkey(PlannerInfo *root,
if (contain_volatile_functions((Node *) constexpr))
continue;
+ if (IsA(constexpr, Param))
+ {
+ *contains_param = true;
+
+ root->baserestrictinfo_param_indexes =
+ list_append_unique_int(root->baserestrictinfo_param_indexes,
+ clause_index);
+ }
+
/*
* Everything seems to be fine, so add it to the list of
* clauses we will use for pruning.
@@ -1249,6 +1347,26 @@ match_clauses_to_partkey(PlannerInfo *root,
return result;
}
+/* list_member_oid_index
+ * Returns the index of the given datum in the oid list.
+ *
+ * It returns -1 if the datum is not found.
+ */
+static int
+list_member_oid_index(List *list, Oid datum)
+{
+ int i = 0;
+ const ListCell *cell;
+
+ foreach(cell, list)
+ {
+ if (lfirst_oid(cell) == datum)
+ return i;
+ i++;
+ }
+ return -1;
+}
+
/*
* set_append_rel_size
* Set size estimates for a simple "append relation"
@@ -1641,7 +1759,8 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
foreach(l, rel_appinfos)
{
AppendRelInfo *appinfo = (AppendRelInfo *) lfirst(l);
- int childRTindex;
+ int childRTindex,
+ index;
RangeTblEntry *childRTE;
RelOptInfo *childrel;
@@ -1674,6 +1793,11 @@ set_append_rel_pathlist(PlannerInfo *root, RelOptInfo *rel,
if (IS_DUMMY_REL(childrel))
continue;
+ /* only consider non dummy children */
+ index = list_member_oid_index(root->leaf_node_oids, childRTE->relid);
+ if (index >= 0)
+ root->append_paths_array[index] = root->append_paths_count++;
+
/*
* Child is live, so add it to the live_childrels list for use below.
*/
@@ -1855,7 +1979,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
* if we have zero or one live subpath due to constraint exclusion.)
*/
if (subpaths_valid)
- add_path(rel, (Path *) create_append_path(rel, subpaths, NULL, 0,
+ add_path(rel, (Path *) create_append_path(root, rel, subpaths, NULL, 0,
partitioned_rels));
/*
@@ -1882,7 +2006,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
Assert(parallel_workers > 0);
/* Generate a partial append path. */
- appendpath = create_append_path(rel, partial_subpaths, NULL,
+ appendpath = create_append_path(root, rel, partial_subpaths, NULL,
parallel_workers, partitioned_rels);
add_partial_path(rel, (Path *) appendpath);
}
@@ -1936,7 +2060,7 @@ add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
if (subpaths_valid)
add_path(rel, (Path *)
- create_append_path(rel, subpaths, required_outer, 0,
+ create_append_path(root, rel, subpaths, required_outer, 0,
partitioned_rels));
}
}
@@ -2173,7 +2297,7 @@ set_dummy_rel_pathlist(RelOptInfo *rel)
rel->pathlist = NIL;
rel->partial_pathlist = NIL;
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
+ add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NULL, 0, NIL));
/*
* We set the cheapest path immediately, to ensure that IS_DUMMY_REL()
diff --git a/src/backend/optimizer/path/joinrels.c b/src/backend/optimizer/path/joinrels.c
index b491fb9..61fe647 100644
--- a/src/backend/optimizer/path/joinrels.c
+++ b/src/backend/optimizer/path/joinrels.c
@@ -1232,7 +1232,7 @@ mark_dummy_rel(RelOptInfo *rel)
rel->partial_pathlist = NIL;
/* Set up the dummy path */
- add_path(rel, (Path *) create_append_path(rel, NIL, NULL, 0, NIL));
+ add_path(rel, (Path *) create_append_path(NULL, rel, NIL, NULL, 0, NIL));
/* Set or update cheapest_total_path and related fields */
set_cheapest(rel);
diff --git a/src/backend/optimizer/plan/createplan.c b/src/backend/optimizer/plan/createplan.c
index d445477..a47373f 100644
--- a/src/backend/optimizer/plan/createplan.c
+++ b/src/backend/optimizer/plan/createplan.c
@@ -1001,6 +1001,24 @@ create_join_plan(PlannerInfo *root, JoinPath *best_path)
return plan;
}
+static List *
+replace_partition_nestloop_params(PlannerInfo *root, List *old_list)
+{
+ List *new_list = NIL;
+ ListCell *lc;
+
+ if (old_list == NULL)
+ return NULL;
+
+ foreach(lc, old_list)
+ {
+ Node *n = lfirst(lc);
+
+ new_list = lappend(new_list, replace_nestloop_params(root, n));
+ }
+ return new_list;
+}
+
/*
* create_append_plan
* Create an Append plan for 'best_path' and (recursively) plans
@@ -1063,6 +1081,12 @@ create_append_plan(PlannerInfo *root, AppendPath *best_path)
copy_generic_path_info(&plan->plan, (Path *) best_path);
+ plan->base_params = best_path->base_params;
+ plan->join_clauses = replace_partition_nestloop_params(root, best_path->join_clauses);
+ plan->parentoid = best_path->parentoid;
+ plan->append_paths_size = best_path->append_paths_size;
+ plan->append_paths_array = best_path->append_paths_array;
+
return (Plan *) plan;
}
diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c
index 28093ac..ffefcd0 100644
--- a/src/backend/optimizer/plan/planner.c
+++ b/src/backend/optimizer/plan/planner.c
@@ -3678,7 +3678,7 @@ create_grouping_paths(PlannerInfo *root,
paths = lappend(paths, path);
}
path = (Path *)
- create_append_path(grouped_rel,
+ create_append_path(root, grouped_rel,
paths,
NULL,
0,
diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c
index f620243..12d0f85 100644
--- a/src/backend/optimizer/prep/prepunion.c
+++ b/src/backend/optimizer/prep/prepunion.c
@@ -590,7 +590,7 @@ generate_union_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
+ path = (Path *) create_append_path(root, result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
@@ -702,7 +702,7 @@ generate_nonunion_path(SetOperationStmt *op, PlannerInfo *root,
/*
* Append the child results together.
*/
- path = (Path *) create_append_path(result_rel, pathlist, NULL, 0, NIL);
+ path = (Path *) create_append_path(root, result_rel, pathlist, NULL, 0, NIL);
/* We have to manually jam the right tlist into the path; ick */
path->pathtarget = create_pathtarget(root, tlist);
diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c
index 72f1fa3..fbbcae8 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -2470,6 +2470,25 @@ eval_const_expressions(PlannerInfo *root, Node *node)
}
/*--------------------
+ * eval_const_expressions_from_list
+ *
+ * This is similar to eval_const_expression except that it takes ParamListInfo
+ * argument instead of PlannerInfo to create the context.
+ */
+Node *
+eval_const_expressions_from_list(ParamListInfo prmlist, Node *node)
+{
+ eval_const_expressions_context context;
+
+ context.boundParams = prmlist; /* bound Params */
+ context.root = NULL;
+ context.active_fns = NIL; /* nothing being recursively simplified */
+ context.case_val = NULL; /* no CASE being examined */
+ context.estimate = false; /* safe transformations only */
+ return eval_const_expressions_mutator(node, &context);
+}
+
+/*--------------------
* estimate_expression_value
*
* This function attempts to estimate the value of an expression for
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 68dee0f..12baead 100644
--- a/src/backend/optimizer/util/pathnode.c
+++ b/src/backend/optimizer/util/pathnode.c
@@ -1208,7 +1208,7 @@ create_tidscan_path(PlannerInfo *root, RelOptInfo *rel, List *tidquals,
* Note that we must handle subpaths = NIL, representing a dummy access path.
*/
AppendPath *
-create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
+create_append_path(PlannerInfo *root, RelOptInfo *rel, List *subpaths, Relids required_outer,
int parallel_workers, List *partitioned_rels)
{
AppendPath *pathnode = makeNode(AppendPath);
@@ -1253,6 +1253,56 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
}
+ /* Do necessary evaluation needed for runtime partition pruning. */
+ if (root && (required_outer || (rel->baserestrictinfo)))
+ {
+ RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
+
+ pathnode->append_paths_array = root->append_paths_array;
+ pathnode->append_paths_size = root->append_paths_size;
+
+ if (rte && rte->rtekind == RTE_RELATION)
+ {
+ Oid poid = rte->relid;
+ Relation prel = relation_open(poid, NoLock);
+
+ if (prel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
+ {
+ if (root->join_clauses)
+ pathnode->join_clauses = root->join_clauses;
+
+ if (root->baserestrictinfo_param_indexes && rel->baserestrictinfo)
+ {
+ ListCell *lc;
+ List *quals = list_copy(rel->baserestrictinfo);
+
+ pathnode->base_params = NIL;
+
+ /*
+ * collect the clauses from baserestrictinfo for partition
+ * pruning
+ */
+ foreach(lc, root->baserestrictinfo_param_indexes)
+ {
+ int index = lfirst_int(lc);
+ Node *member = list_nth(quals, index);
+ Expr *clause;
+
+ if (IsA(member, RestrictInfo))
+ clause = ((RestrictInfo *) member)->clause;
+ else
+ clause = (Expr *) member;
+
+ pathnode->base_params = lappend(pathnode->base_params,
+ clause);
+ }
+ }
+ pathnode->parentoid = poid;
+ }
+ relation_close(prel, NoLock);
+ }
+ }
+
return pathnode;
}
diff --git a/src/backend/optimizer/util/relnode.c b/src/backend/optimizer/util/relnode.c
index a968fa4..545a34b 100644
--- a/src/backend/optimizer/util/relnode.c
+++ b/src/backend/optimizer/util/relnode.c
@@ -1555,6 +1555,9 @@ ParamPathInfo *
get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
{
ParamPathInfo *ppi;
+ Relids joinrelids;
+ List *pclauses;
+ ListCell *lc;
/* Unparameterized paths have no ParamPathInfo */
if (bms_is_empty(required_outer))
@@ -1566,11 +1569,27 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
if ((ppi = find_param_path_info(appendrel, required_outer)))
return ppi;
+ /*
+ * To determine whether the appendrel is applicable for runtime pruning or
+ * not, we fetch the clause from the join clause.
+ */
+ joinrelids = bms_union(appendrel->relids, required_outer);
+ pclauses = NIL;
+ foreach(lc, appendrel->joininfo)
+ {
+ RestrictInfo *rinfo = (RestrictInfo *) lfirst(lc);
+
+ if (join_clause_is_movable_into(rinfo,
+ appendrel->relids,
+ joinrelids))
+ pclauses = lappend(pclauses, rinfo);
+ }
+
/* Else build the ParamPathInfo */
ppi = makeNode(ParamPathInfo);
ppi->ppi_req_outer = required_outer;
ppi->ppi_rows = 0;
- ppi->ppi_clauses = NIL;
+ ppi->ppi_clauses = pclauses;
appendrel->ppilist = lappend(appendrel->ppilist, ppi);
return ppi;
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 2041de5..5a8acd9 100644
--- a/src/include/catalog/partition.h
+++ b/src/include/catalog/partition.h
@@ -16,6 +16,7 @@
#include "fmgr.h"
#include "executor/tuptable.h"
#include "nodes/execnodes.h"
+#include "nodes/relation.h"
#include "parser/parse_node.h"
#include "utils/rel.h"
@@ -73,5 +74,7 @@ extern int get_partition_for_tuple(Relation relation, Datum *values,
/* For partition-pruning */
extern Bitmapset *get_partitions_from_clauses(Relation relation, int rt_index,
- List *partclauses);
+ List *partclauses, ParamListInfo base_prmlist,
+ ExprContext *econtext);
+extern void get_leaf_part_recurse(Relation rel, List **leaf_part_oids);
#endif /* PARTITION_H */
diff --git a/src/include/executor/execPartition.h b/src/include/executor/execPartition.h
index 64e5aab..6e7a841 100644
--- a/src/include/executor/execPartition.h
+++ b/src/include/executor/execPartition.h
@@ -49,6 +49,9 @@ typedef struct PartitionDispatchData
typedef struct PartitionDispatchData *PartitionDispatch;
+extern PartitionDispatch *RelationGetPartitionDispatchInfo(Relation rel,
+ int *num_parted, List **leaf_part_oids);
+
extern void ExecSetupPartitionTupleRouting(Relation rel,
Index resultRTindex,
EState *estate,
diff --git a/src/include/nodes/execnodes.h b/src/include/nodes/execnodes.h
index e05bc04..0c3be05 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -41,6 +41,7 @@
struct ExprState; /* forward references in this file */
struct ExprContext;
struct ExprEvalStep; /* avoid including execExpr.h everywhere */
+struct PartitionDispatchData;
typedef Datum (*ExprStateEvalFunc) (struct ExprState *expression,
struct ExprContext *econtext,
@@ -1006,6 +1007,17 @@ typedef struct AppendState
PlanState **appendplans; /* array of PlanStates for my inputs */
int as_nplans;
int as_whichplan;
+
+ /* for runtime partition pruning */
+ Oid parentoid; /* oid of the parent */
+ int *append_paths_array;
+ int append_paths_size; /* size of append_paths_array */
+ List *base_params; /* base restrictinfo on partition keys */
+ List *join_clauses; /* join clauses on partiton keys */
+ ParamListInfo es_param_list_info;
+ List *subplan_indexes; /* List of subplan indexes to scan */
+ int as_whichpartition; /* current index to scan in index */
+ struct PartitionDispatchData **pd;
} AppendState;
/* ----------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 9b38d44..698322d 100644
--- a/src/include/nodes/plannodes.h
+++ b/src/include/nodes/plannodes.h
@@ -19,6 +19,7 @@
#include "nodes/bitmapset.h"
#include "nodes/lockoptions.h"
#include "nodes/primnodes.h"
+#include "nodes/relation.h"
/* ----------------------------------------------------------------
@@ -248,6 +249,13 @@ typedef struct Append
/* RT indexes of non-leaf tables in a partition tree */
List *partitioned_rels;
List *appendplans;
+
+ /* for runtime partition pruning */
+ Oid parentoid;
+ int *append_paths_array;
+ int append_paths_size;
+ List *base_params;
+ List *join_clauses;
} Append;
/* ----------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 94c2e8d..611fb74 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -317,6 +317,17 @@ typedef struct PlannerInfo
/* optional private data for join_search_hook, e.g., GEQO */
void *join_search_private;
+
+ /* These fields accumulate data required for runtime partition pruning. */
+ int *append_paths_array; /* array for append subplans info */
+ int append_paths_size; /* size of append_paths_array */
+ int append_paths_count; /* current count of append_paths_array */
+ List *leaf_node_oids; /* leaf oids of current rel */
+ List *baserestrictinfo_param_indexes; /* index from baserestrictinfo
+ * list with partition related
+ * clauses */
+ List *join_clauses; /* join clause which are required for
+ * partition pruning */
} PlannerInfo;
@@ -1289,6 +1300,13 @@ typedef struct AppendPath
/* RT indexes of non-leaf tables in a partition tree */
List *partitioned_rels;
List *subpaths; /* list of component Paths */
+
+ /* for runtime partition pruning */
+ Oid parentoid;
+ int *append_paths_array;
+ int append_paths_size;
+ List *base_params;
+ List *join_clauses;
} AppendPath;
#define IS_DUMMY_PATH(p) \
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 1ef13a4..f8e7660 100644
--- a/src/include/optimizer/clauses.h
+++ b/src/include/optimizer/clauses.h
@@ -79,6 +79,7 @@ extern void CommuteOpExpr(OpExpr *clause);
extern void CommuteRowCompareExpr(RowCompareExpr *clause);
extern Node *eval_const_expressions(PlannerInfo *root, Node *node);
+extern Node *eval_const_expressions_from_list(ParamListInfo prmlist, Node *node);
extern Node *estimate_expression_value(PlannerInfo *root, Node *node);
diff --git a/src/include/optimizer/pathnode.h b/src/include/optimizer/pathnode.h
index c1f2fc9..7c1fbfd 100644
--- a/src/include/optimizer/pathnode.h
+++ b/src/include/optimizer/pathnode.h
@@ -63,8 +63,8 @@ extern BitmapOrPath *create_bitmap_or_path(PlannerInfo *root,
List *bitmapquals);
extern TidPath *create_tidscan_path(PlannerInfo *root, RelOptInfo *rel,
List *tidquals, Relids required_outer);
-extern AppendPath *create_append_path(RelOptInfo *rel, List *subpaths,
- Relids required_outer, int parallel_workers,
+extern AppendPath *create_append_path(PlannerInfo *root, RelOptInfo *rel,
+ List *subpaths, Relids required_outer, int parallel_workers,
List *partitioned_rels);
extern MergeAppendPath *create_merge_append_path(PlannerInfo *root,
RelOptInfo *rel,