summaryrefslogtreecommitdiff
path: root/src/backend/optimizer/util/plancat.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2008-01-12 00:11:45 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2008-01-12 00:11:45 +0000
commit691189c9d659b641c20c26ab21ad3fa706310db3 (patch)
treed8fce74d8cba6acd5ea0fcd64fb4b2983c43e66c /src/backend/optimizer/util/plancat.c
parentbcabf2195b8903c95cca187e44bd073de0e2f288 (diff)
Fix logical errors in constraint exclusion: we cannot assume that a CHECK
constraint yields TRUE for every row of its table, only that it does not yield FALSE (a NULL result isn't disallowed). This breaks a couple of implications that would be true in two-valued logic. I had put in one such mistake in an 8.2.5 patch: foo IS NULL doesn't refute a strict operator on foo. But there was another in the original 8.2 release: NOT foo doesn't refute an expression whose truth would imply the truth of foo. Per report from Rajesh Kumar Mallah. To preserve the ability to do constraint exclusion with one partition holding NULL values, extend relation_excluded_by_constraints() to check for attnotnull flags, and add col IS NOT NULL expressions to the set of constraints we hope to refute.
Diffstat (limited to 'src/backend/optimizer/util/plancat.c')
-rw-r--r--src/backend/optimizer/util/plancat.c42
1 files changed, 37 insertions, 5 deletions
diff --git a/src/backend/optimizer/util/plancat.c b/src/backend/optimizer/util/plancat.c
index de14ddd2dc0..55bdfd17fd4 100644
--- a/src/backend/optimizer/util/plancat.c
+++ b/src/backend/optimizer/util/plancat.c
@@ -9,7 +9,7 @@
*
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.127 2006/10/04 00:29:55 momjian Exp $
+ * $PostgreSQL: pgsql/src/backend/optimizer/util/plancat.c,v 1.127.2.1 2008/01/12 00:11:45 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -43,7 +43,8 @@ bool constraint_exclusion = false;
static void estimate_rel_size(Relation rel, int32 *attr_widths,
BlockNumber *pages, double *tuples);
-static List *get_relation_constraints(Oid relationObjectId, RelOptInfo *rel);
+static List *get_relation_constraints(Oid relationObjectId, RelOptInfo *rel,
+ bool include_notnull);
/*
@@ -391,12 +392,16 @@ estimate_rel_size(Relation rel, int32 *attr_widths,
* indicated by rel->relid. This allows the expressions to be easily
* compared to expressions taken from WHERE.
*
+ * If include_notnull is true, "col IS NOT NULL" expressions are generated
+ * and added to the result for each column that's marked attnotnull.
+ *
* Note: at present this is invoked at most once per relation per planner
* run, and in many cases it won't be invoked at all, so there seems no
* point in caching the data in RelOptInfo.
*/
static List *
-get_relation_constraints(Oid relationObjectId, RelOptInfo *rel)
+get_relation_constraints(Oid relationObjectId, RelOptInfo *rel,
+ bool include_notnull)
{
List *result = NIL;
Index varno = rel->relid;
@@ -451,6 +456,30 @@ get_relation_constraints(Oid relationObjectId, RelOptInfo *rel)
result = list_concat(result,
make_ands_implicit((Expr *) cexpr));
}
+
+ /* Add NOT NULL constraints in expression form, if requested */
+ if (include_notnull && constr->has_not_null)
+ {
+ int natts = relation->rd_att->natts;
+
+ for (i = 1; i <= natts; i++)
+ {
+ Form_pg_attribute att = relation->rd_att->attrs[i - 1];
+
+ if (att->attnotnull && !att->attisdropped)
+ {
+ NullTest *ntest = makeNode(NullTest);
+
+ ntest->arg = (Expr *) makeVar(varno,
+ i,
+ att->atttypid,
+ att->atttypmod,
+ 0);
+ ntest->nulltesttype = IS_NOT_NULL;
+ result = lappend(result, ntest);
+ }
+ }
+ }
}
heap_close(relation, NoLock);
@@ -502,8 +531,11 @@ relation_excluded_by_constraints(RelOptInfo *rel, RangeTblEntry *rte)
if (rte->rtekind != RTE_RELATION || rte->inh)
return false;
- /* OK to fetch the constraint expressions */
- constraint_pred = get_relation_constraints(rte->relid, rel);
+ /*
+ * OK to fetch the constraint expressions. Include "col IS NOT NULL"
+ * expressions for attnotnull columns, in case we can refute those.
+ */
+ constraint_pred = get_relation_constraints(rte->relid, rel, true);
/*
* We do not currently enforce that CHECK constraints contain only