aboutsummaryrefslogtreecommitdiff
path: root/src/backend/commands/constraint.c
diff options
context:
space:
mode:
authorTom Lane <tgl@sss.pgh.pa.us>2009-12-07 05:22:23 +0000
committerTom Lane <tgl@sss.pgh.pa.us>2009-12-07 05:22:23 +0000
commit0cb65564e5f855b1e9aa145fd645352130f74646 (patch)
treebadcc3ee73a16d472f9e637246589d6b803e620f /src/backend/commands/constraint.c
parent8de7472b45859108761223fb19b396efaa8f0a4d (diff)
downloadpostgresql-0cb65564e5f855b1e9aa145fd645352130f74646.tar.gz
postgresql-0cb65564e5f855b1e9aa145fd645352130f74646.zip
Add exclusion constraints, which generalize the concept of uniqueness to
support any indexable commutative operator, not just equality. Two rows violate the exclusion constraint if "row1.col OP row2.col" is TRUE for each of the columns in the constraint. Jeff Davis, reviewed by Robert Haas
Diffstat (limited to 'src/backend/commands/constraint.c')
-rw-r--r--src/backend/commands/constraint.c45
1 files changed, 34 insertions, 11 deletions
diff --git a/src/backend/commands/constraint.c b/src/backend/commands/constraint.c
index 42d4d4e1f9c..41adf871471 100644
--- a/src/backend/commands/constraint.c
+++ b/src/backend/commands/constraint.c
@@ -7,7 +7,7 @@
* Portions Copyright (c) 1994, Regents of the University of California
*
* IDENTIFICATION
- * $PostgreSQL: pgsql/src/backend/commands/constraint.c,v 1.1 2009/07/29 20:56:18 tgl Exp $
+ * $PostgreSQL: pgsql/src/backend/commands/constraint.c,v 1.2 2009/12/07 05:22:21 tgl Exp $
*
*-------------------------------------------------------------------------
*/
@@ -23,9 +23,12 @@
/*
* unique_key_recheck - trigger function to do a deferred uniqueness check.
*
+ * This now also does deferred exclusion-constraint checks, so the name is
+ * somewhat historical.
+ *
* This is invoked as an AFTER ROW trigger for both INSERT and UPDATE,
* for any rows recorded as potentially violating a deferrable unique
- * constraint.
+ * or exclusion constraint.
*
* This may be an end-of-statement check, a commit-time check, or a
* check triggered by a SET CONSTRAINTS command.
@@ -85,7 +88,7 @@ unique_key_recheck(PG_FUNCTION_ARGS)
* because this trigger gets queued only in response to index insertions;
* which means it does not get queued for HOT updates. The row we are
* called for might now be dead, but have a live HOT child, in which case
- * we still need to make the uniqueness check. Therefore we have to use
+ * we still need to make the check. Therefore we have to use
* heap_hot_search, not just HeapTupleSatisfiesVisibility as is done in
* the comparable test in RI_FKey_check.
*
@@ -123,9 +126,11 @@ unique_key_recheck(PG_FUNCTION_ARGS)
/*
* Typically the index won't have expressions, but if it does we need
- * an EState to evaluate them.
+ * an EState to evaluate them. We need it for exclusion constraints
+ * too, even if they are just on simple columns.
*/
- if (indexInfo->ii_Expressions != NIL)
+ if (indexInfo->ii_Expressions != NIL ||
+ indexInfo->ii_ExclusionOps != NULL)
{
estate = CreateExecutorState();
econtext = GetPerTupleExprContext(estate);
@@ -141,19 +146,37 @@ unique_key_recheck(PG_FUNCTION_ARGS)
* Note: if the index uses functions that are not as immutable as they
* are supposed to be, this could produce an index tuple different from
* the original. The index AM can catch such errors by verifying that
- * it finds a matching index entry with the tuple's TID.
+ * it finds a matching index entry with the tuple's TID. For exclusion
+ * constraints we check this in check_exclusion_constraint().
*/
FormIndexDatum(indexInfo, slot, estate, values, isnull);
/*
- * Now do the uniqueness check. This is not a real insert; it is a
- * check that the index entry that has already been inserted is unique.
+ * Now do the appropriate check.
*/
- index_insert(indexRel, values, isnull, &(new_row->t_self),
- trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
+ if (indexInfo->ii_ExclusionOps == NULL)
+ {
+ /*
+ * Note: this is not a real insert; it is a check that the index entry
+ * that has already been inserted is unique.
+ */
+ index_insert(indexRel, values, isnull, &(new_row->t_self),
+ trigdata->tg_relation, UNIQUE_CHECK_EXISTING);
+ }
+ else
+ {
+ /*
+ * For exclusion constraints we just do the normal check, but now
+ * it's okay to throw error.
+ */
+ check_exclusion_constraint(trigdata->tg_relation, indexRel, indexInfo,
+ &(new_row->t_self), values, isnull,
+ estate, false, false);
+ }
/*
- * If that worked, then this index entry is unique, and we are done.
+ * If that worked, then this index entry is unique or non-excluded,
+ * and we are done.
*/
if (estate != NULL)
FreeExecutorState(estate);