static PartitionScheme find_partition_scheme(PlannerInfo *root, Relation rel);
static void set_baserel_partition_key_exprs(Relation relation,
RelOptInfo *rel);
+static void set_baserel_partition_constraint(Relation relation,
+ RelOptInfo *rel);
+
/*
* get_relation_info -
*/
if (include_partition && relation->rd_rel->relispartition)
{
- List *pcqual = RelationGetPartitionQual(relation);
-
- if (pcqual)
- {
- /*
- * Run the partition quals through const-simplification similar to
- * check constraints. We skip canonicalize_qual, though, because
- * partition quals should be in canonical form already; also,
- * since the qual is in implicit-AND format, we'd have to
- * explicitly convert it to explicit-AND format and back again.
- */
- pcqual = (List *) eval_const_expressions(root, (Node *) pcqual);
-
- /* Fix Vars to have the desired varno */
- if (varno != 1)
- ChangeVarNodes((Node *) pcqual, 1, varno, 0);
-
- result = list_concat(result, pcqual);
- }
+ /* make sure rel->partition_qual is set */
+ set_baserel_partition_constraint(relation, rel);
+ result = list_concat(result, rel->partition_qual);
}
table_close(relation, NoLock);
rel->boundinfo = partdesc->boundinfo;
rel->nparts = partdesc->nparts;
set_baserel_partition_key_exprs(relation, rel);
- rel->partition_qual = RelationGetPartitionQual(relation);
+ set_baserel_partition_constraint(relation, rel);
}
/*
*/
rel->nullable_partexprs = (List **) palloc0(sizeof(List *) * partnatts);
}
+
+/*
+ * set_baserel_partition_constraint
+ *
+ * Builds the partition constraint for the given base relation and sets it
+ * in the given RelOptInfo. All Var nodes are restamped with the relid of the
+ * given relation.
+ */
+static void
+set_baserel_partition_constraint(Relation relation, RelOptInfo *rel)
+{
+ List *partconstr;
+
+ if (rel->partition_qual) /* already done */
+ return;
+
+ /*
+ * Run the partition quals through const-simplification similar to check
+ * constraints. We skip canonicalize_qual, though, because partition
+ * quals should be in canonical form already; also, since the qual is in
+ * implicit-AND format, we'd have to explicitly convert it to explicit-AND
+ * format and back again.
+ */
+ partconstr = RelationGetPartitionQual(relation);
+ if (partconstr)
+ {
+ partconstr = (List *) expression_planner((Expr *) partconstr);
+ if (rel->relid != 1)
+ ChangeVarNodes((Node *) partconstr, 1, rel->relid, 0);
+ rel->partition_qual = partconstr;
+ }
+}
context->target = target;
/*
- * For sub-partitioned tables there's a corner case where if the
- * sub-partitioned table shares any partition keys with its parent, then
- * it's possible that the partitioning hierarchy allows the parent
- * partition to only contain a narrower range of values than the
- * sub-partitioned table does. In this case it is possible that we'd
- * include partitions that could not possibly have any tuples matching
- * 'clauses'. The possibility of such a partition arrangement is perhaps
- * unlikely for non-default partitions, but it may be more likely in the
- * case of default partitions, so we'll add the parent partition table's
- * partition qual to the clause list in this case only. This may result
- * in the default partition being eliminated.
+ * If this partitioned table is in turn a partition, and it shares any
+ * partition keys with its parent, then it's possible that the hierarchy
+ * allows the parent a narrower range of values than some of its
+ * partitions (particularly the default one). This is normally not
+ * useful, but it can be to prune the default partition.
*/
- if (partition_bound_has_default(rel->boundinfo) &&
- rel->partition_qual != NIL)
+ if (partition_bound_has_default(rel->boundinfo) && rel->partition_qual)
{
- List *partqual = rel->partition_qual;
-
- partqual = (List *) expression_planner((Expr *) partqual);
-
- /* Fix Vars to have the desired varno */
- if (rel->relid != 1)
- ChangeVarNodes((Node *) partqual, 1, rel->relid, 0);
-
/* Make a copy to avoid modifying the passed-in List */
- clauses = list_concat_copy(clauses, partqual);
+ clauses = list_concat_copy(clauses, rel->partition_qual);
}
/* Down into the rabbit-hole. */
List *result = NIL;
ListCell *lc;
+ /*
+ * If this partitioned relation has a default partition and is itself
+ * a partition (as evidenced by partition_qual being not NIL), we first
+ * check if the clauses contradict the partition constraint. If they do,
+ * there's no need to generate any steps as it'd already be proven that no
+ * partitions need to be scanned.
+ *
+ * This is a measure of last resort only to be used because the default
+ * partition cannot be pruned using the steps generated from clauses that
+ * contradict the parent's partition constraint; regular pruning, which is
+ * cheaper, is sufficient when no default partition exists.
+ */
+ if (partition_bound_has_default(context->rel->boundinfo) &&
+ predicate_refuted_by(context->rel->partition_qual, clauses, false))
+ {
+ context->contradictory = true;
+ return NIL;
+ }
+
memset(keyclauses, 0, sizeof(keyclauses));
foreach(lc, clauses)
{
*/
}
- /*
- * If the clause contradicts the partition constraint, mark the clause
- * as contradictory and we're done. This is particularly helpful to
- * prune the default partition.
- */
- if (context->rel->partition_qual)
- {
- List *partconstr;
-
- partconstr = (List *)
- expression_planner((Expr *) context->rel->partition_qual);
- if (context->rel->relid != 1)
- ChangeVarNodes((Node *) partconstr, 1,
- context->rel->relid, 0);
- if (predicate_refuted_by(partconstr,
- list_make1(clause),
- false))
- {
- context->contradictory = true;
- return NIL;
- }
- }
-
/*
* See if we can match this clause to any of the partition keys.
*/