0001-Implement-runtime-partiton-pruning_v4.patch
application/octet-stream
Filename: 0001-Implement-runtime-partiton-pruning_v4.patch
Type: application/octet-stream
Part: 0
Patch
Format: format-patch
Series: patch v4-0001
Subject: Implement Runtime Partition Pruning
| File | + | − |
|---|---|---|
| src/backend/catalog/partition.c | 99 | 17 |
| src/backend/executor/execPartition.c | 1 | 3 |
| src/backend/executor/nodeAppend.c | 214 | 5 |
| src/backend/nodes/copyfuncs.c | 5 | 0 |
| src/backend/optimizer/path/allpaths.c | 116 | 15 |
| 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 | 14 | 0 |
| src/backend/optimizer/util/pathnode.c | 29 | 1 |
| src/backend/optimizer/util/relnode.c | 22 | 1 |
| src/backend/utils/cache/plancache.c | 1 | 1 |
| src/include/catalog/partition.h | 3 | 1 |
| src/include/executor/execPartition.h | 3 | 0 |
| src/include/nodes/execnodes.h | 8 | 0 |
| src/include/nodes/plannodes.h | 6 | 0 |
| src/include/nodes/relation.h | 12 | 0 |
| src/include/optimizer/clauses.h | 1 | 0 |
| src/include/optimizer/pathnode.h | 2 | 2 |
From 0a6e1da7fab7b2100ff14d202b8577e0f736f002 Mon Sep 17 00:00:00 2001
From: Beena Emerson <Beena.Emerson@EnterpriseDB.com>
Date: Fri, 1 Dec 2017 16:35:40 +0530
Subject: [PATCH] Implement Runtime Partition Pruning
Patch by: Beena Emerson, Dilip Kumar
Discussion: https://postgr.es/m/CAOG9ApE16ac-_VVZVvv0gePSgkg_BwYEV1NBqZFqDR2bBE0X0A@mail.gmail.com
---
src/backend/catalog/partition.c | 116 ++++++++++++++---
src/backend/executor/execPartition.c | 4 +-
src/backend/executor/nodeAppend.c | 219 +++++++++++++++++++++++++++++++-
src/backend/nodes/copyfuncs.c | 5 +
src/backend/optimizer/path/allpaths.c | 131 ++++++++++++++++---
src/backend/optimizer/path/joinrels.c | 2 +-
src/backend/optimizer/plan/createplan.c | 24 ++++
src/backend/optimizer/plan/planner.c | 2 +-
src/backend/optimizer/prep/prepunion.c | 4 +-
src/backend/optimizer/util/clauses.c | 14 ++
src/backend/optimizer/util/pathnode.c | 30 ++++-
src/backend/optimizer/util/relnode.c | 23 +++-
src/backend/utils/cache/plancache.c | 2 +-
src/include/catalog/partition.h | 4 +-
src/include/executor/execPartition.h | 3 +
src/include/nodes/execnodes.h | 8 ++
src/include/nodes/plannodes.h | 6 +
src/include/nodes/relation.h | 12 ++
src/include/optimizer/clauses.h | 1 +
src/include/optimizer/pathnode.h | 4 +-
20 files changed, 564 insertions(+), 50 deletions(-)
diff --git a/src/backend/catalog/partition.c b/src/backend/catalog/partition.c
index f07ac15..38d57a7 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,13 @@ 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 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 prmList,
+ ExprContext *econtext);
static void remove_redundant_clauses(PartitionKey partkey,
int partattoff, List *all_clauses,
List **result, bool *constfalse);
@@ -286,7 +289,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 prmList,
+ ExprContext *econtext);
static Bitmapset *get_partitions_for_keys(Relation rel,
PartScanKeyInfo *keys);
@@ -1659,6 +1663,34 @@ get_partition_qual_relid(Oid relid)
return result;
}
+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 +1701,8 @@ get_partition_qual_relid(Oid relid)
*/
Bitmapset *
get_partitions_from_clauses(Relation relation, int rt_index,
- List *partclauses)
+ List *partclauses, ParamListInfo prmList,
+ ExprContext *econtext)
{
Bitmapset *result;
List *partconstr = RelationGetPartitionQual(relation);
@@ -1703,7 +1736,7 @@ get_partitions_from_clauses(Relation relation, int rt_index,
}
result = get_partitions_from_clauses_recurse(relation, rt_index,
- partclauses);
+ partclauses, prmList, econtext);
return result;
}
@@ -1719,7 +1752,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 prmList,
+ ExprContext *econtext)
{
PartitionDesc partdesc = RelationGetPartitionDesc(relation);
Bitmapset *result = NULL;
@@ -1735,7 +1769,7 @@ 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, prmList, econtext);
/*
* The analysis of the matched clauses done by
@@ -1797,7 +1831,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,
+ prmList,
+ econtext);
/*
* Partition sets obtained from mutually-disjunctive clauses are
@@ -1853,7 +1889,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 prmList,
+ ExprContext *econtext)
{
PartitionKey partkey = RelationGetPartitionKey(relation);
int i;
@@ -1893,6 +1930,8 @@ classify_partition_bounding_keys(Relation relation, List *clauses,
continue;
}
}
+ else if (IsA(lfirst(lc), ExprState))
+ clause = ((ExprState *) lfirst(lc))->expr;
else
clause = (Expr *) lfirst(lc);
@@ -2305,7 +2344,7 @@ 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], prmList, econtext))
{
keys->n_maxkeys++;
keys->max_incl = incl;
@@ -2317,12 +2356,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], prmList,
+ econtext))
keys->n_eqkeys++;
if (need_next_max &&
partkey_datum_from_expr(partkey, i, constarg,
- &keys->maxkeys[i]))
+ &keys->maxkeys[i], prmList,
+ econtext))
{
keys->n_maxkeys++;
keys->max_incl = true;
@@ -2330,7 +2371,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], prmList,
+ econtext))
{
keys->n_minkeys++;
keys->min_incl = true;
@@ -2338,7 +2380,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], prmList,
+ econtext))
{
keys->n_minkeys++;
keys->min_incl = incl;
@@ -2426,7 +2469,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 prmList,
+ ExprContext *econtext)
{
Oid exprtype = exprType((Node *) expr);
@@ -2467,6 +2511,42 @@ 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 (prmList)
+ {
+ Node *n = eval_const_expressions_from_list(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 +2808,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/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..0254b99 100644
--- a/src/backend/executor/nodeAppend.c
+++ b/src/backend/executor/nodeAppend.c
@@ -57,9 +57,13 @@
#include "postgres.h"
+#include "catalog/pg_inherits_fn.h"
+#include "nodes/relation.h"
#include "executor/execdebug.h"
#include "executor/nodeAppend.h"
+#include "executor/execPartition.h"
#include "miscadmin.h"
+#include "optimizer/clauses.h"
static TupleTableSlot *ExecAppend(PlanState *pstate);
static bool exec_append_initialize_next(AppendState *appendstate);
@@ -107,6 +111,24 @@ exec_append_initialize_next(AppendState *appendstate)
}
}
+static List *
+initClauses(PlanState *parent, List *old_list)
+{
+ List *new_list = NIL;
+ ListCell *lc;
+
+ if (old_list == NULL)
+ return NULL;
+
+ foreach(lc, old_list)
+ {
+ Expr *val = (Expr *) lfirst(lc);
+
+ new_list = lappend(new_list, ExecInitExpr(val, parent));
+ }
+ return new_list;
+}
+
/* ----------------------------------------------------------------
* ExecInitAppend
*
@@ -151,6 +173,11 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
appendstate->ps.ExecProcNode = ExecAppend;
appendstate->appendplans = appendplanstates;
appendstate->as_nplans = nplans;
+ appendstate->index = NIL;
+ appendstate->as_whichpartition = -1;
+ appendstate->array_size = node->array_size;
+ appendstate->append_paths_array = node->append_paths_array;
+ appendstate->parentoid = node->parentoid;
/*
* Miscellaneous initialization
@@ -164,6 +191,7 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
* we have to initialize them.
*/
ExecInitResultTupleSlot(estate, &appendstate->ps);
+ ExecAssignExprContext(estate, &appendstate->ps);
/*
* call ExecInitNode on each of the plans to be executed and save the
@@ -178,9 +206,16 @@ ExecInitAppend(Append *node, EState *estate, int eflags)
i++;
}
- /*
- * initialize output tuple type
- */
+ if (node->extern_quals)
+ {
+ appendstate->extern_quals = node->extern_quals;
+ appendstate->es_param_list_info = estate->es_param_list_info;
+ }
+
+ if (node->join_clauses)
+ appendstate->join_clauses = initClauses((PlanState *) appendstate,
+ node->join_clauses);
+
ExecAssignResultTypeFromTL(&appendstate->ps);
appendstate->ps.ps_ProjInfo = NULL;
@@ -204,6 +239,85 @@ ExecAppend(PlanState *pstate)
{
AppendState *node = castNode(AppendState, pstate);
+ if (node->extern_quals && node->as_whichpartition == -1)
+ {
+ Relation rel;
+ Bitmapset *partset = NULL;
+ Bitmapset *subplan_indexes = NULL;
+ int i,
+ cur_index;
+ PartitionDispatch *pd,
+ *p1,
+ parent;
+ int num_parted;
+ List *leaf_part_oids = NIL;
+ List *parents = NIL;
+
+ rel = relation_open(node->parentoid, NoLock);
+
+ /*
+ * Get the information about the partition tree after locking all the
+ * partitions.
+ */
+ (void) find_all_inheritors(RelationGetRelid(rel), AccessShareLock, NULL);
+ pd = RelationGetPartitionDispatchInfo(rel, &num_parted, &leaf_part_oids);
+ relation_close(rel, NoLock);
+ parents = lappend(parents, &pd[0]);
+ do
+ {
+ p1 = linitial(parents);
+ parent = *p1;
+
+ partset = get_partitions_from_clauses(parent->reldesc, 1,
+ list_copy(node->extern_quals),
+ node->es_param_list_info,
+ node->ps.ps_ExprContext);
+
+ if (!bms_is_empty(partset))
+ {
+ i = 0;
+ while ((cur_index = bms_first_member(partset)) >= 0)
+ {
+ if (parent->indexes[cur_index] >= 0)
+ subplan_indexes =
+ bms_add_member(subplan_indexes, parent->indexes[cur_index]);
+ else
+ parents =
+ lappend(parents, &pd[-parent->indexes[cur_index]]);
+ }
+ }
+
+ parents = list_delete_first(parents);
+ } while (parents);
+
+ for (i = 1; i < num_parted; i++)
+ {
+ PartitionDispatch partdispatch = pd[i];
+
+ heap_close(partdispatch->reldesc, NoLock);
+ ExecDropSingleTupleTableSlot(partdispatch->tupslot);
+ }
+
+ if (!bms_is_empty(subplan_indexes))
+ {
+ int j;
+
+ while ((j = bms_first_member(subplan_indexes)) >= 0)
+ {
+ int index = node->append_paths_array[j];
+
+ if (index >= 0)
+ node->index = lappend_int(node->index, index);
+ }
+ if (node->index)
+ {
+ node->as_whichplan = linitial_int(node->index);
+ node->as_whichpartition = 0;
+ }
+ else
+ node->as_whichplan = 0;
+ }
+ }
for (;;)
{
PlanState *subnode;
@@ -237,7 +351,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->index)
+ {
+ if (++node->as_whichpartition < list_length(node->index))
+ node->as_whichplan = list_nth_int(node->index,
+ 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 +409,79 @@ ExecReScanAppend(AppendState *node)
{
int i;
+ if (node->ps.chgParam != NULL && node->join_clauses)
+ {
+ Bitmapset *partset = NULL,
+ *subplan_indexes = NULL;
+ Relation rel;
+ PartitionDispatch *pd,
+ parent,
+ *p1;
+ List *parents = NIL;
+ List *leaf_part_oids = NIL;
+ int cur_index,
+ num_parted;
+
+ rel = relation_open(node->parentoid, NoLock);
+
+ /*
+ * Get the information about the partition tree after locking all the
+ * partitions.
+ */
+ (void) find_all_inheritors(RelationGetRelid(rel), AccessShareLock, NULL);
+ pd = RelationGetPartitionDispatchInfo(rel, &num_parted, &leaf_part_oids);
+ relation_close(rel, NoLock);
+ parents = lappend(parents, &pd[0]);
+ node->index = NIL;
+ do
+ {
+ p1 = linitial(parents);
+ parent = *p1;
+
+ partset = get_partitions_from_clauses(parent->reldesc,
+ 1,
+ list_copy(node->join_clauses),
+ NULL,
+ node->ps.ps_ExprContext);
+
+ if (!bms_is_empty(partset))
+ {
+ i = 0;
+ while ((cur_index = bms_first_member(partset)) >= 0)
+ {
+ if (parent->indexes[cur_index] >= 0)
+ subplan_indexes =
+ bms_add_member(subplan_indexes, parent->indexes[cur_index]);
+ else
+ parents =
+ lappend(parents, &pd[-parent->indexes[cur_index]]);
+ }
+ }
+ parents = list_delete_first(parents);
+ } while (parents);
+
+ for (i = 1; i < num_parted; i++)
+ {
+ PartitionDispatch partdispatch = pd[i];
+
+ heap_close(partdispatch->reldesc, NoLock);
+ ExecDropSingleTupleTableSlot(partdispatch->tupslot);
+ }
+
+ if (!bms_is_empty(subplan_indexes))
+ {
+ int j;
+
+ while ((j = bms_first_member(subplan_indexes)) >= 0)
+ {
+ int index = node->append_paths_array[j];
+
+ if (index >= 0)
+ node->index = lappend_int(node->index, index);
+ }
+ }
+ }
+
for (i = 0; i < node->as_nplans; i++)
{
PlanState *subnode = node->appendplans[i];
@@ -298,6 +500,13 @@ ExecReScanAppend(AppendState *node)
if (subnode->chgParam == NULL)
ExecReScan(subnode);
}
- node->as_whichplan = 0;
+
+ if (node->index)
+ {
+ node->as_whichplan = linitial_int(node->index);
+ node->as_whichpartition = 0;
+ }
+ else
+ node->as_whichplan = 0;
exec_append_initialize_next(node);
}
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index d9ff8a7..74408ae 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(extern_quals);
+ COPY_NODE_FIELD(join_clauses);
+ COPY_SCALAR_FIELD(parentoid);
+ COPY_POINTER_FIELD(append_paths_array, from->array_size * sizeof(int));
+ COPY_SCALAR_FIELD(array_size);
return newnode;
}
diff --git a/src/backend/optimizer/path/allpaths.c b/src/backend/optimizer/path/allpaths.c
index 6b087ec..98fa866 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"
@@ -140,13 +141,15 @@ static void add_paths_to_append_rel(PlannerInfo *root, RelOptInfo *rel,
List *live_childrels);
static List *get_append_rel_partitions(PlannerInfo *root,
RelOptInfo *rel,
- RangeTblEntry *rte);
+ RangeTblEntry *rte,
+ List *chk_clauses);
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 +292,22 @@ 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;
+
+ (void) find_all_inheritors(RelationGetRelid(parent), AccessShareLock, NULL);
+ get_leaf_part_recurse(parent, &leaf_parts);
+ root->array_size = list_length(leaf_parts);
+ root->leaf_node_oids = leaf_parts;
+ root->append_paths_array = palloc0(root->array_size * sizeof(int));
+ for (i = 0; i < root->array_size; i++)
+ root->append_paths_array[i] = -1;
+ root->append_count = 0;
+ relation_close(parent, NoLock);
+ }
set_rel_size(root, rel, rti, rte);
}
}
@@ -350,6 +369,41 @@ set_rel_size(PlannerInfo *root, RelOptInfo *rel,
{
/* It's an "append relation", process accordingly */
set_append_rel_size(root, rel, rti, rte);
+
+ if (rel->joininfo && rel->part_scheme)
+ {
+ List *partclauses;
+ bool contains_param,
+ contains_const,
+ constfalse;
+
+ /*
+ * Get the clauses that match the partition key, including
+ * information about any nullness tests against partition keys.
+ * Set keynullness to a invalid value of NullTestType, which 0 is
+ * not.
+ */
+ 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_append_clauses, n));
+ root->join_append_clauses = lappend(root->join_append_clauses, n);
+ }
+ }
+
+ }
+
}
else
{
@@ -867,11 +921,13 @@ set_foreign_pathlist(PlannerInfo *root, RelOptInfo *rel, RangeTblEntry *rte)
static List *
get_append_rel_partitions(PlannerInfo *root,
RelOptInfo *rel,
- RangeTblEntry *rte)
+ RangeTblEntry *rte,
+ List *chk_clauses)
{
List *partclauses;
bool contains_const,
- constfalse;
+ constfalse,
+ contains_param;
/*
* Get the clauses that match the partition key, including information
@@ -880,6 +936,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 +954,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,
@@ -906,6 +963,18 @@ get_append_rel_partitions(PlannerInfo *root,
else
partindexes = bms_add_range(NULL, 0, partdesc->nparts - 1);
+ if (partclauses != NIL && contains_param)
+ {
+ ListCell *lc;
+
+ foreach(lc, partclauses)
+ {
+ Node *n = lfirst(lc);
+
+ if (!list_member(root->extern_clauses, n));
+ root->extern_clauses = lappend(root->extern_clauses, n);
+ }
+ }
/* Fetch the partition appinfos. */
i = -1;
while ((i = bms_next_member(partindexes, i)) >= 0)
@@ -964,11 +1033,14 @@ 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)
{
@@ -1028,10 +1100,12 @@ match_clauses_to_partkey(PlannerInfo *root,
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)
{
@@ -1150,6 +1224,9 @@ match_clauses_to_partkey(PlannerInfo *root,
if (contain_volatile_functions((Node *) constexpr))
continue;
+ if (IsA(constexpr, Param))
+ *contains_param = true;
+
/*
* Everything seems to be fine, so add it to the list of
* clauses we will use for pruning.
@@ -1249,6 +1326,23 @@ match_clauses_to_partkey(PlannerInfo *root,
return result;
}
+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"
@@ -1264,7 +1358,8 @@ static void
set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
Index rti, RangeTblEntry *rte)
{
- List *rel_appinfos = NIL;
+ List *rel_appinfos = NIL,
+ *chk_clauses = NIL;
int parentRTindex = rti;
bool has_live_children;
double parent_rows;
@@ -1280,7 +1375,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
if (rte->relkind != RELKIND_PARTITIONED_TABLE)
{
- foreach (l, root->append_rel_list)
+ foreach(l, root->append_rel_list)
{
AppendRelInfo *appinfo = lfirst(l);
@@ -1291,7 +1386,7 @@ set_append_rel_size(PlannerInfo *root, RelOptInfo *rel,
}
else
{
- rel_appinfos = get_append_rel_partitions(root, rel, rte);
+ rel_appinfos = get_append_rel_partitions(root, rel, rte, chk_clauses);
rel->live_partitioned_rels = list_make1_int(rti);
}
@@ -1641,7 +1736,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 +1770,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_count++;
+
/*
* Child is live, so add it to the live_childrels list for use below.
*/
@@ -1855,7 +1956,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 +1983,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 +2037,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 +2274,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..91a2bdb 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->extern_quals = best_path->extern_quals;
+ plan->join_clauses = replace_partition_nestloop_params(root, best_path->join_clauses);
+ plan->parentoid = best_path->parentoid;
+ plan->array_size = best_path->array_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..45e3598 100644
--- a/src/backend/optimizer/util/clauses.c
+++ b/src/backend/optimizer/util/clauses.c
@@ -5217,3 +5217,17 @@ tlist_matches_coltypelist(List *tlist, List *coltypelist)
return true;
}
+
+Node *
+eval_const_expressions_from_list(ParamListInfo prmList, Node *node)
+{
+ eval_const_expressions_context context;
+
+ if (prmList)
+ 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);
+}
diff --git a/src/backend/optimizer/util/pathnode.c b/src/backend/optimizer/util/pathnode.c
index 68dee0f..4a19e76 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,34 @@ create_append_path(RelOptInfo *rel, List *subpaths, Relids required_outer,
Assert(bms_equal(PATH_REQ_OUTER(subpath), required_outer));
}
+ if (root)
+ {
+ pathnode->append_paths_array = root->append_paths_array;
+ pathnode->array_size = root->array_size;
+
+ }
+ if (root && (required_outer || root->extern_clauses))
+ {
+ RangeTblEntry *rte = planner_rt_fetch(rel->relid, root);
+
+ 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_append_clauses)
+ pathnode->join_clauses = root->join_append_clauses;
+
+ if (root->extern_clauses)
+ pathnode->extern_quals = root->extern_clauses;
+ 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..495b64b 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,29 @@ get_appendrel_parampathinfo(RelOptInfo *appendrel, Relids required_outer)
if ((ppi = find_param_path_info(appendrel, required_outer)))
return ppi;
+
+ /*
+ * Generally for appendrel we don't fetch the clause from the join clause
+ * (only we do so for baserel), but for identifying whether the appendrel
+ * is applicable for runtime pruning or not.
+ */
+ 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/backend/utils/cache/plancache.c b/src/backend/utils/cache/plancache.c
index 853c1f6..9656fa4 100644
--- a/src/backend/utils/cache/plancache.c
+++ b/src/backend/utils/cache/plancache.c
@@ -1041,7 +1041,7 @@ choose_custom_plan(CachedPlanSource *plansource, ParamListInfo boundParams)
if (plansource->num_custom_plans < 5)
return true;
- avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans;
+ avg_custom_cost = plansource->total_custom_cost / plansource->num_custom_plans + 90000;
/*
* Prefer generic plan if it's less expensive than the average custom
diff --git a/src/include/catalog/partition.h b/src/include/catalog/partition.h
index 2041de5..3102f39 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,6 @@ 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 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..68b8d35 100644
--- a/src/include/nodes/execnodes.h
+++ b/src/include/nodes/execnodes.h
@@ -1006,6 +1006,14 @@ typedef struct AppendState
PlanState **appendplans; /* array of PlanStates for my inputs */
int as_nplans;
int as_whichplan;
+ Oid parentoid;
+ List *index; /* subplan indexes to scan for runtime pruning */
+ int as_whichpartition; /* current partition scanned from list */
+ List *join_clauses;
+ List *extern_quals;
+ ParamListInfo es_param_list_info;
+ int *append_paths_array;
+ int array_size;
} AppendState;
/* ----------------
diff --git a/src/include/nodes/plannodes.h b/src/include/nodes/plannodes.h
index 9b38d44..1908c89 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,11 @@ typedef struct Append
/* RT indexes of non-leaf tables in a partition tree */
List *partitioned_rels;
List *appendplans;
+ Oid parentoid;
+ List *extern_quals;
+ List *join_clauses;
+ int *append_paths_array;
+ int array_size;
} Append;
/* ----------------
diff --git a/src/include/nodes/relation.h b/src/include/nodes/relation.h
index 94c2e8d..a72e92a 100644
--- a/src/include/nodes/relation.h
+++ b/src/include/nodes/relation.h
@@ -168,6 +168,7 @@ typedef struct PlannerInfo
*/
List *plan_params; /* list of PlannerParamItems, see below */
Bitmapset *outer_params;
+ List *extern_clauses;
/*
* simple_rel_array holds pointers to "base rels" and "other rels" (see
@@ -317,6 +318,12 @@ typedef struct PlannerInfo
/* optional private data for join_search_hook, e.g., GEQO */
void *join_search_private;
+
+ List *leaf_node_oids;
+ List *join_append_clauses;
+ int array_size;
+ int append_count;
+ int *append_paths_array;
} PlannerInfo;
@@ -1289,6 +1296,11 @@ typedef struct AppendPath
/* RT indexes of non-leaf tables in a partition tree */
List *partitioned_rels;
List *subpaths; /* list of component Paths */
+ List *extern_quals;
+ List *join_clauses;
+ int *append_paths_array;
+ int array_size;
+ Oid parentoid;
} AppendPath;
#define IS_DUMMY_PATH(p) \
diff --git a/src/include/optimizer/clauses.h b/src/include/optimizer/clauses.h
index 1ef13a4..c09044e 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 prm_list, 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,
--
1.8.3.1