Updated patch attached.

Changes:
 * Added syntax support:
     CREATE INDEX foo_idx ON foo ... (a CONSTRAINT =, b CONSTRAINT &&);
 * More aggressively clear the shared memory entries to avoid 
   unnecessary checks
 * Code cleanup

TODO:
 * When adding constraint to table with data already in it, verify that 
   existing data satisfies constraint.
 * Clean up error messages a little
 * Docs

The following are possible TODO items, but I'd like to get some feedback
first:
 * It seems like an alternative language would be better:
     ALTER TABLE foo ADD INDEX CONSTRAINT optional_name (a =, b &&)
       USING foo_idx;
   This language would be more like a table constraint that happens to 
   use an index. I think it's better because it allows multiple 
   constraints to be enforced by the same index.
 * Right now it only supports index AMs that offer amgettuple, which 
   excludes GIN. Consider adding a crude implementation of gingettuple 
   that just calls gingetbitmap internally (obviously providing no 
   performance advantage over gingetbitmap).

Regards,
        Jeff Davis
diff --git a/src/backend/access/index/indexam.c b/src/backend/access/index/indexam.c
index 1515d9f..d88387b 100644
--- a/src/backend/access/index/indexam.c
+++ b/src/backend/access/index/indexam.c
@@ -26,6 +26,7 @@
  *		index_vacuum_cleanup	- post-deletion cleanup of an index
  *		index_getprocid - get a support procedure OID
  *		index_getprocinfo - get a support procedure's lookup info
+ *      index_check_constraint - check index constraints
  *
  * NOTES
  *		This file contains the index_ routines which used
@@ -64,9 +65,13 @@
 
 #include "access/relscan.h"
 #include "access/transam.h"
+#include "miscadmin.h"
 #include "pgstat.h"
 #include "storage/bufmgr.h"
 #include "storage/lmgr.h"
+#include "storage/lwlock.h"
+#include "storage/procarray.h"
+#include "utils/lsyscache.h"
 #include "utils/relcache.h"
 #include "utils/snapmgr.h"
 #include "utils/tqual.h"
@@ -116,6 +121,19 @@ do { \
 static IndexScanDesc index_beginscan_internal(Relation indexRelation,
 						 int nkeys, ScanKey key);
 
+typedef struct
+{
+	Oid					relid;
+	TransactionId		xid;
+	ItemPointerData		tid;
+} CurrentIndexInsertEntry;
+
+static CurrentIndexInsertEntry *CurrentIndexInsertsTable = NULL;
+
+static bool index_check_constraint_conflict(TupleTableSlot *slot,
+											HeapTuple tup, int2 *heap_attnums,
+											int2 index_natts,
+											Oid *constraint_procs);
 
 /* ----------------------------------------------------------------
  *				   index_ interface functions
@@ -846,3 +864,303 @@ index_getprocinfo(Relation irel,
 
 	return locinfo;
 }
+
+void
+index_check_constraint(Relation heap, Relation index,
+						ItemPointer tid, TupleTableSlot *slot)
+{
+		IndexScanDesc	 index_scan;
+		HeapTuple		 tup;
+		ScanKeyData		*scankeys;
+		int2vector		*constr_strats;
+		Oid				*constr_procs;
+		int				 i;
+		int2			*heap_attnums = index->rd_index->indkey.values;
+		int2			 index_natts  = index->rd_index->indnatts;
+		SnapshotData	 DirtySnapshot;
+		int				 nkeys		  = 0;
+
+		CurrentIndexInsertEntry	 potential_conflicts[MaxBackends];
+		int						 n_potential_conflicts = 0;
+
+		/* Find constraint strategy numbers */
+		constr_strats = RelationGetIndexConstraintStrategies(index);
+
+		/* return if no constraint */
+		if (constr_strats == NULL)
+			return;
+
+		/*
+		 * if any of the indexed columns are NULL, the constraint
+		 * is satisfied
+		 */
+		for (i = 0; i < index_natts; i++)
+			if (slot_attisnull(slot, heap_attnums[i]))
+				return;
+
+		/*
+		 * Find the function that tests for a conflict based on the
+		 * strategy number, operator family, and types.
+		 */
+		constr_procs = palloc(sizeof(Oid) * index_natts);
+		for (i = 0; i < index_natts; i++)
+		{
+			/*
+			 * Find the procedure implementing the strategy for the
+			 * index for two arguments both with the type of the
+			 * indexed attribute.
+			 */
+			Oid					oper;
+			Oid					opfamily = index->rd_opfamily[i];
+			StrategyNumber		strategy = constr_strats->values[i];
+			Oid	typeOid	= heap->rd_att->attrs[heap_attnums[i] - 1]->atttypid;
+
+			if (strategy == InvalidStrategy)
+				continue;
+
+			oper = get_opfamily_member(opfamily, typeOid, typeOid, strategy);
+
+			if(OidIsValid(oper))
+				constr_procs[i] = get_opcode(oper);
+			else
+				elog(ERROR, "cannot determine operator for type %d and "
+					 "strategy %d", typeOid, strategy);
+		}
+
+		/*
+		 * Check for conflicts with concurrent inserts. These are
+		 * inserts that are actually in-progress now, and have not
+		 * actually been put in the index yet.
+		 */
+
+		Assert (CurrentIndexInsertsTable != NULL);
+
+		LWLockAcquire(IndexConstraintLock, LW_SHARED);
+
+		for (i = 0; i < MaxBackends; i++)
+		{
+			CurrentIndexInsertEntry entry = CurrentIndexInsertsTable[i];
+
+			if (RelationGetRelid(heap) == entry.relid &&
+				!TransactionIdIsCurrentTransactionId(entry.xid) &&
+				TransactionIdIsInProgress(entry.xid))
+			{
+					potential_conflicts[n_potential_conflicts++] = entry;
+			}
+		}
+
+		LWLockRelease(IndexConstraintLock);
+
+		InitDirtySnapshot(DirtySnapshot);
+
+		for (i = 0; i < n_potential_conflicts; i++)
+		{
+			bool				does_conflict = true;
+			HeapTupleData		tup;
+			Buffer				buffer;
+
+			tup.t_self = potential_conflicts[i].tid;
+			if (!heap_fetch(heap, &DirtySnapshot, &tup, &buffer, false, NULL))
+				continue;
+
+			does_conflict = index_check_constraint_conflict(
+				slot, &tup, heap_attnums, index_natts, constr_procs);
+
+			ReleaseBuffer(buffer);
+
+			if (does_conflict)
+			{
+				CurrentIndexInsertEntry conflict = potential_conflicts[i];
+				if (TransactionIdIsCurrentTransactionId(conflict.xid))
+					elog(ERROR, "conflict detected 1");
+
+				XactLockTableWait(conflict.xid);
+				if (TransactionIdDidCommit(conflict.xid))
+					elog(ERROR, "conflict detected 2");
+			}
+		}
+
+		/*
+		 * Now search the tuples that are actually in the index for
+		 * any violations.
+		 */
+
+		scankeys = palloc(index_natts * sizeof(ScanKeyData));
+		for (i = 0; i < index_natts; i++)
+		{
+			Datum	key_datum;
+			bool	isnull;
+
+			key_datum = slot_getattr(slot, heap_attnums[i], &isnull);
+			Assert(!isnull); /* already checked above */
+
+			if (constr_strats->values[i] == InvalidStrategy)
+				continue;
+
+			ScanKeyInit(&scankeys[nkeys], i + 1, constr_strats->values[i],
+						constr_procs[i], key_datum);
+			nkeys++;
+		}
+
+		/*
+		 * We have to find all tuples, even those not visible
+		 * yet. Other transactions may have inserted many tuples (or
+		 * the transaction might be a prepared transaction), so there
+		 * may be some tuples that are not in the shared memory
+		 * structure and not visible.
+		 */
+		index_scan = index_beginscan(heap, index, &DirtySnapshot, nkeys,
+									 scankeys);
+		while((tup = index_getnext(index_scan, ForwardScanDirection)) != NULL)
+		{
+			if (index_scan->xs_recheck)
+			{
+				if (!index_check_constraint_conflict(
+						slot, tup, heap_attnums, index_natts, constr_procs))
+					continue;
+			}
+
+			/* If the in-progress inserting transaction aborts, proceed. */
+			if (TransactionIdIsValid(DirtySnapshot.xmin))
+			{
+				XactLockTableWait(DirtySnapshot.xmin);
+				if (TransactionIdDidAbort(DirtySnapshot.xmin))
+					continue;
+			}
+
+			/* If the in-progress deleting transaction commits, proceed. */
+			if (TransactionIdIsValid(DirtySnapshot.xmax))
+			{
+				XactLockTableWait(DirtySnapshot.xmax);
+				if (TransactionIdDidCommit(DirtySnapshot.xmax))
+					continue;
+			}
+
+			elog(ERROR, "conflict detected 3");
+		}
+
+		index_endscan(index_scan);
+		pfree(scankeys);
+
+		return;
+}
+
+/*
+ * For each attribute of the index, check for a conflict between the
+ * slot's tuple's value and the tuple's value. Only return true if all
+ * values conflict.
+ */
+static bool
+index_check_constraint_conflict(TupleTableSlot *slot, HeapTuple tup,
+								int2 *heap_attnums, int2 index_natts,
+								Oid* constraint_procs)
+{
+	int i;
+
+	for (i = 0; i < index_natts; i++)
+	{
+		Datum	input_datum;
+		Datum	existing_datum;
+		bool	isnull;
+
+		if (!OidIsValid(constraint_procs[i]))
+			continue;
+
+		input_datum = slot_getattr(slot, heap_attnums[i], &isnull);
+		if (isnull)
+			return false;
+
+		existing_datum = heap_getattr(
+			tup, heap_attnums[i], slot->tts_tupleDescriptor, &isnull);
+		if (isnull)
+			return false;
+
+		if (!DatumGetBool(OidFunctionCall2(constraint_procs[i],
+										   input_datum, existing_datum)))
+			return false;
+	}
+	return true;
+}
+
+void
+index_set_current_insert(Oid relid, ItemPointer tupleid)
+{
+	if (CurrentIndexInsertsTable == NULL)
+	{
+		bool found;
+
+		CurrentIndexInsertsTable = (CurrentIndexInsertEntry *)
+			ShmemInitStruct("Current Index Inserts Table",
+							CurrentIndexInsertsShmemSize(), &found);
+		Assert(found);
+	}
+
+	LWLockAcquire(IndexConstraintLock, LW_EXCLUSIVE);
+
+	CurrentIndexInsertsTable[MyBackendId - 1].relid = relid;
+	CurrentIndexInsertsTable[MyBackendId - 1].xid = GetCurrentTransactionId();
+	CurrentIndexInsertsTable[MyBackendId - 1].tid = *tupleid;
+
+	LWLockRelease(IndexConstraintLock);
+}
+
+void
+index_unset_current_insert(void)
+{
+	Assert(CurrentIndexInsertsTable != NULL);
+
+	LWLockAcquire(IndexConstraintLock, LW_EXCLUSIVE);
+
+	CurrentIndexInsertsTable[MyBackendId - 1].relid = InvalidOid;
+
+	LWLockRelease(IndexConstraintLock);
+}
+
+/*
+ * GistShmemSize --- report amount of shared memory space needed
+ */
+Size
+CurrentIndexInsertsShmemSize(void)
+{
+	return (sizeof(CurrentIndexInsertEntry) * MaxBackends);
+}
+
+/*
+ * GistShmemInit --- initialize this module's shared memory
+ */
+void
+CurrentIndexInsertsShmemInit(void)
+{
+	int							 i;
+	bool						 found;
+	CurrentIndexInsertEntry		*current_inserts;
+
+	current_inserts = (CurrentIndexInsertEntry *)
+		ShmemInitStruct("Current Index Inserts Table",
+						CurrentIndexInsertsShmemSize(),
+						&found);
+
+	if (!IsUnderPostmaster)
+	{
+		/* Initialize shared memory area */
+		Assert(!found);
+
+		for (i = 0; i < MaxBackends; i++)
+			current_inserts[i].relid = InvalidOid;
+	}
+	else
+		Assert(found);
+}
+
+void
+AtEOXact_IndexConstraints(void)
+{
+	if (CurrentIndexInsertsTable != NULL)
+	{
+		LWLockAcquire(IndexConstraintLock, LW_EXCLUSIVE);
+
+		CurrentIndexInsertsTable[MyBackendId - 1].relid = InvalidOid;
+
+		LWLockRelease(IndexConstraintLock);
+	}
+}
diff --git a/src/backend/access/transam/xact.c b/src/backend/access/transam/xact.c
index 117fdab..2716141 100644
--- a/src/backend/access/transam/xact.c
+++ b/src/backend/access/transam/xact.c
@@ -1707,6 +1707,7 @@ CommitTransaction(void)
 	AtEOXact_HashTables(true);
 	AtEOXact_PgStat(true);
 	AtEOXact_Snapshot(true);
+	AtEOXact_IndexConstraints();
 	pgstat_report_xact_timestamp(0);
 
 	CurrentResourceOwner = NULL;
@@ -1942,6 +1943,7 @@ PrepareTransaction(void)
 	AtEOXact_HashTables(true);
 	/* don't call AtEOXact_PgStat here */
 	AtEOXact_Snapshot(true);
+	AtEOXact_IndexConstraints();
 
 	CurrentResourceOwner = NULL;
 	ResourceOwnerDelete(TopTransactionResourceOwner);
@@ -2085,6 +2087,7 @@ AbortTransaction(void)
 	AtEOXact_HashTables(false);
 	AtEOXact_PgStat(false);
 	AtEOXact_Snapshot(false);
+	AtEOXact_IndexConstraints();
 	pgstat_report_xact_timestamp(0);
 
 	/*
diff --git a/src/backend/catalog/index.c b/src/backend/catalog/index.c
index c4e4cab..d285a78 100644
--- a/src/backend/catalog/index.c
+++ b/src/backend/catalog/index.c
@@ -86,6 +86,7 @@ static void UpdateIndexRelation(Oid indexoid, Oid heapoid,
 					IndexInfo *indexInfo,
 					Oid *classOids,
 					int16 *coloptions,
+					StrategyNumber *constrats,
 					bool primary,
 					bool isvalid);
 static void index_update_stats(Relation rel, bool hasindex, bool isprimary,
@@ -371,12 +372,14 @@ UpdateIndexRelation(Oid indexoid,
 					IndexInfo *indexInfo,
 					Oid *classOids,
 					int16 *coloptions,
+					StrategyNumber *constrats,
 					bool primary,
 					bool isvalid)
 {
 	int2vector *indkey;
 	oidvector  *indclass;
 	int2vector *indoption;
+	int2vector *indconstrats;
 	Datum		exprsDatum;
 	Datum		predDatum;
 	Datum		values[Natts_pg_index];
@@ -394,6 +397,8 @@ UpdateIndexRelation(Oid indexoid,
 		indkey->values[i] = indexInfo->ii_KeyAttrNumbers[i];
 	indclass = buildoidvector(classOids, indexInfo->ii_NumIndexAttrs);
 	indoption = buildint2vector(coloptions, indexInfo->ii_NumIndexAttrs);
+	indconstrats = buildint2vector((int2 *) constrats,
+								   indexInfo->ii_NumIndexAttrs);
 
 	/*
 	 * Convert the index expressions (if any) to a text datum
@@ -447,6 +452,12 @@ UpdateIndexRelation(Oid indexoid,
 	values[Anum_pg_index_indkey - 1] = PointerGetDatum(indkey);
 	values[Anum_pg_index_indclass - 1] = PointerGetDatum(indclass);
 	values[Anum_pg_index_indoption - 1] = PointerGetDatum(indoption);
+
+	if (constrats != NULL)
+		values[Anum_pg_index_indconstrats - 1] = PointerGetDatum(indconstrats);
+	else
+		nulls[Anum_pg_index_indconstrats - 1] = true;
+
 	values[Anum_pg_index_indexprs - 1] = exprsDatum;
 	if (exprsDatum == (Datum) 0)
 		nulls[Anum_pg_index_indexprs - 1] = true;
@@ -506,6 +517,7 @@ index_create(Oid heapRelationId,
 			 Oid tableSpaceId,
 			 Oid *classObjectId,
 			 int16 *coloptions,
+			 StrategyNumber *constrats,
 			 Datum reloptions,
 			 bool isprimary,
 			 bool isconstraint,
@@ -679,7 +691,8 @@ index_create(Oid heapRelationId,
 	 * ----------------
 	 */
 	UpdateIndexRelation(indexRelationId, heapRelationId, indexInfo,
-						classObjectId, coloptions, isprimary, !concurrent);
+						classObjectId, coloptions, constrats, isprimary,
+						!concurrent);
 
 	/*
 	 * Register constraint and dependencies for the index.
diff --git a/src/backend/catalog/toasting.c b/src/backend/catalog/toasting.c
index 6e7b5cf..1ab1a2b 100644
--- a/src/backend/catalog/toasting.c
+++ b/src/backend/catalog/toasting.c
@@ -252,7 +252,7 @@ create_toast_table(Relation rel, Oid toastOid, Oid toastIndexOid,
 							   indexInfo,
 							   BTREE_AM_OID,
 							   rel->rd_rel->reltablespace,
-							   classObjectId, coloptions, (Datum) 0,
+							   classObjectId, coloptions, NULL, (Datum) 0,
 							   true, false, true, false, false);
 
 	/*
diff --git a/src/backend/commands/indexcmds.c b/src/backend/commands/indexcmds.c
index 99ab0e5..7a9300f 100644
--- a/src/backend/commands/indexcmds.c
+++ b/src/backend/commands/indexcmds.c
@@ -36,6 +36,7 @@
 #include "optimizer/clauses.h"
 #include "parser/parse_coerce.h"
 #include "parser/parse_func.h"
+#include "parser/parse_oper.h"
 #include "parser/parsetree.h"
 #include "storage/lmgr.h"
 #include "storage/proc.h"
@@ -57,6 +58,8 @@ static void CheckPredicate(Expr *predicate);
 static void ComputeIndexAttrs(IndexInfo *indexInfo,
 				  Oid *classOidP,
 				  int16 *colOptionP,
+				  StrategyNumber *constrats,
+				  bool *has_constraints,
 				  List *attList,
 				  Oid relId,
 				  char *accessMethodName, Oid accessMethodId,
@@ -126,6 +129,8 @@ DefineIndex(RangeVar *heapRelation,
 	RegProcedure amoptions;
 	Datum		reloptions;
 	int16	   *coloptions;
+	StrategyNumber	   *constrats;
+	bool		has_constraints;
 	IndexInfo  *indexInfo;
 	int			numberOfAttributes;
 	VirtualTransactionId *old_lockholders;
@@ -422,9 +427,15 @@ DefineIndex(RangeVar *heapRelation,
 
 	classObjectId = (Oid *) palloc(numberOfAttributes * sizeof(Oid));
 	coloptions = (int16 *) palloc(numberOfAttributes * sizeof(int16));
-	ComputeIndexAttrs(indexInfo, classObjectId, coloptions, attributeList,
-					  relationId, accessMethodName, accessMethodId,
-					  amcanorder, isconstraint);
+	constrats = (StrategyNumber *) palloc(
+		numberOfAttributes * sizeof(StrategyNumber));
+	ComputeIndexAttrs(indexInfo, classObjectId, coloptions, constrats,
+					  &has_constraints, attributeList, relationId,
+					  accessMethodName, accessMethodId, amcanorder,
+					  isconstraint);
+
+	if (!has_constraints)
+		constrats = NULL;
 
 	/*
 	 * Report index creation if appropriate (delay this till after most of the
@@ -447,8 +458,9 @@ DefineIndex(RangeVar *heapRelation,
 		indexRelationId =
 			index_create(relationId, indexRelationName, indexRelationId,
 					  indexInfo, accessMethodId, tablespaceId, classObjectId,
-						 coloptions, reloptions, primary, isconstraint,
-						 allowSystemTableMods, skip_build, concurrent);
+						 coloptions, constrats, reloptions, primary,
+						 isconstraint, allowSystemTableMods, skip_build,
+						 concurrent);
 
 		return;					/* We're done, in the standard case */
 	}
@@ -465,7 +477,7 @@ DefineIndex(RangeVar *heapRelation,
 	indexRelationId =
 		index_create(relationId, indexRelationName, indexRelationId,
 					 indexInfo, accessMethodId, tablespaceId, classObjectId,
-					 coloptions, reloptions, primary, isconstraint,
+					 coloptions, constrats, reloptions, primary, isconstraint,
 					 allowSystemTableMods, true, concurrent);
 
 	/*
@@ -792,6 +804,8 @@ static void
 ComputeIndexAttrs(IndexInfo *indexInfo,
 				  Oid *classOidP,
 				  int16 *colOptionP,
+				  StrategyNumber *constrats, /* constraint strategies */
+				  bool *has_constraints,
 				  List *attList,	/* list of IndexElem's */
 				  Oid relId,
 				  char *accessMethodName,
@@ -802,6 +816,8 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 	ListCell   *rest;
 	int			attn = 0;
 
+	*has_constraints = false;
+
 	/*
 	 * process attributeList
 	 */
@@ -891,6 +907,21 @@ ComputeIndexAttrs(IndexInfo *indexInfo,
 										  accessMethodName,
 										  accessMethodId);
 
+		if (attribute->constraint_oper != NULL)
+		{
+			Oid opfamily = get_opclass_family(classOidP[attn]);
+			Oid opid = LookupOperName(NULL, attribute->constraint_oper,
+									  atttype, atttype, false, -1);
+			constrats[attn] = get_op_opfamily_strategy(opid, opfamily);
+			if (constrats[attn] == InvalidStrategy)
+				elog(ERROR, "no strategy found for operator %d "
+					 "in operator class %d", opid, classOidP[attn]);
+			*has_constraints = true;
+		}
+		else
+			constrats[attn] = InvalidStrategy;
+
+
 		/*
 		 * Set up the per-column options (indoption field).  For now, this is
 		 * zero for any un-ordered index, while ordered indexes have DESC and
diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c
index 0ccd862..7e0cb18 100644
--- a/src/backend/executor/execUtils.c
+++ b/src/backend/executor/execUtils.c
@@ -1067,6 +1067,14 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 	econtext->ecxt_scantuple = slot;
 
 	/*
+	 * before inserting, check index constraints for each index
+	 */
+	index_set_current_insert(RelationGetRelid(heapRelation), tupleid);
+	for (i = 0; i < numIndices; i++)
+		index_check_constraint(heapRelation, relationDescs[i],
+							   tupleid, slot);
+
+	/*
 	 * for each index, form and insert the index tuple
 	 */
 	for (i = 0; i < numIndices; i++)
@@ -1132,6 +1140,8 @@ ExecInsertIndexTuples(TupleTableSlot *slot,
 		 */
 		IncrIndexInserted();
 	}
+
+	index_unset_current_insert();
 }
 
 /*
diff --git a/src/backend/nodes/copyfuncs.c b/src/backend/nodes/copyfuncs.c
index 2c7d481..c575d18 100644
--- a/src/backend/nodes/copyfuncs.c
+++ b/src/backend/nodes/copyfuncs.c
@@ -2058,6 +2058,7 @@ _copyIndexElem(IndexElem *from)
 	COPY_NODE_FIELD(opclass);
 	COPY_SCALAR_FIELD(ordering);
 	COPY_SCALAR_FIELD(nulls_ordering);
+	COPY_NODE_FIELD(constraint_oper);
 
 	return newnode;
 }
diff --git a/src/backend/nodes/equalfuncs.c b/src/backend/nodes/equalfuncs.c
index c61de97..be8463f 100644
--- a/src/backend/nodes/equalfuncs.c
+++ b/src/backend/nodes/equalfuncs.c
@@ -2039,6 +2039,7 @@ _equalIndexElem(IndexElem *a, IndexElem *b)
 	COMPARE_NODE_FIELD(opclass);
 	COMPARE_SCALAR_FIELD(ordering);
 	COMPARE_SCALAR_FIELD(nulls_ordering);
+	COMPARE_NODE_FIELD(constraint_oper);
 
 	return true;
 }
diff --git a/src/backend/nodes/outfuncs.c b/src/backend/nodes/outfuncs.c
index 49f74d7..a5f7e38 100644
--- a/src/backend/nodes/outfuncs.c
+++ b/src/backend/nodes/outfuncs.c
@@ -1876,6 +1876,7 @@ _outIndexElem(StringInfo str, IndexElem *node)
 	WRITE_NODE_FIELD(opclass);
 	WRITE_ENUM_FIELD(ordering, SortByDir);
 	WRITE_ENUM_FIELD(nulls_ordering, SortByNulls);
+	WRITE_NODE_FIELD(constraint_oper);
 }
 
 static void
diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 20ab0ba..eb7d950 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -280,7 +280,7 @@ static TypeName *TableFuncTypeName(List *columns);
 				sort_clause opt_sort_clause sortby_list index_params
 				name_list from_clause from_list opt_array_bounds
 				qualified_name_list any_name any_name_list
-				any_operator expr_list attrs
+				any_operator expr_list attrs opt_index_constraint
 				target_list insert_column_list set_target_list
 				set_clause_list set_clause multiple_set_clause
 				ctext_expr_list ctext_row def_list indirection opt_indirection
@@ -4560,7 +4560,7 @@ index_params:	index_elem							{ $$ = list_make1($1); }
  * expressions in parens.  For backwards-compatibility reasons, we allow
  * an expression that's just a function call to be written without parens.
  */
-index_elem:	ColId opt_class opt_asc_desc opt_nulls_order
+index_elem:	ColId opt_class opt_asc_desc opt_nulls_order opt_index_constraint
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = $1;
@@ -4568,8 +4568,9 @@ index_elem:	ColId opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $2;
 					$$->ordering = $3;
 					$$->nulls_ordering = $4;
+					$$->constraint_oper = $5;
 				}
-			| func_expr opt_class opt_asc_desc opt_nulls_order
+			| func_expr opt_class opt_asc_desc opt_nulls_order opt_index_constraint
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = NULL;
@@ -4577,8 +4578,9 @@ index_elem:	ColId opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $2;
 					$$->ordering = $3;
 					$$->nulls_ordering = $4;
+					$$->constraint_oper = $5;
 				}
-			| '(' a_expr ')' opt_class opt_asc_desc opt_nulls_order
+			| '(' a_expr ')' opt_class opt_asc_desc opt_nulls_order opt_index_constraint
 				{
 					$$ = makeNode(IndexElem);
 					$$->name = NULL;
@@ -4586,6 +4588,7 @@ index_elem:	ColId opt_class opt_asc_desc opt_nulls_order
 					$$->opclass = $4;
 					$$->ordering = $5;
 					$$->nulls_ordering = $6;
+					$$->constraint_oper = $7;
 				}
 		;
 
@@ -4604,6 +4607,10 @@ opt_nulls_order: NULLS_FIRST				{ $$ = SORTBY_NULLS_FIRST; }
 			| /*EMPTY*/						{ $$ = SORTBY_NULLS_DEFAULT; }
 		;
 
+opt_index_constraint: CONSTRAINT any_operator		{ $$ = $2; }
+			| /*EMPTY*/								{ $$ = NULL; }
+		;
+
 
 /*****************************************************************************
  *
diff --git a/src/backend/storage/ipc/ipci.c b/src/backend/storage/ipc/ipci.c
index 3022867..8c04940 100644
--- a/src/backend/storage/ipc/ipci.c
+++ b/src/backend/storage/ipc/ipci.c
@@ -15,6 +15,7 @@
 #include "postgres.h"
 
 #include "access/clog.h"
+#include "access/genam.h"
 #include "access/heapam.h"
 #include "access/multixact.h"
 #include "access/nbtree.h"
@@ -115,6 +116,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 		size = add_size(size, BgWriterShmemSize());
 		size = add_size(size, AutoVacuumShmemSize());
 		size = add_size(size, BTreeShmemSize());
+		size = add_size(size, CurrentIndexInsertsShmemSize());
 		size = add_size(size, SyncScanShmemSize());
 #ifdef EXEC_BACKEND
 		size = add_size(size, ShmemBackendArraySize());
@@ -215,6 +217,7 @@ CreateSharedMemoryAndSemaphores(bool makePrivate, int port)
 	 * Set up other modules that need some shared memory space
 	 */
 	BTreeShmemInit();
+	CurrentIndexInsertsShmemInit();
 	SyncScanShmemInit();
 
 #ifdef EXEC_BACKEND
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index 29976e7..24583d3 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -3284,6 +3284,22 @@ RelationGetIndexAttrBitmap(Relation relation)
 	return indexattrs;
 }
 
+int2vector *
+RelationGetIndexConstraintStrategies(Relation relation)
+{
+	bool		isnull;
+	Datum		constraint_strategies;
+
+	constraint_strategies = heap_getattr(relation->rd_indextuple,
+										 Anum_pg_index_indconstrats,
+										 GetPgIndexDescriptor(),
+										 &isnull);
+	if (isnull)
+		return NULL;
+
+	return (int2vector *) DatumGetPointer(constraint_strategies);
+
+}
 
 /*
  *	load_relcache_init_file, write_relcache_init_file
diff --git a/src/include/access/genam.h b/src/include/access/genam.h
index a6ac5db..af4346b 100644
--- a/src/include/access/genam.h
+++ b/src/include/access/genam.h
@@ -16,6 +16,8 @@
 
 #include "access/sdir.h"
 #include "access/skey.h"
+#include "access/xact.h"
+#include "executor/tuptable.h"
 #include "nodes/tidbitmap.h"
 #include "storage/buf.h"
 #include "storage/lock.h"
@@ -129,6 +131,16 @@ extern RegProcedure index_getprocid(Relation irel, AttrNumber attnum,
 				uint16 procnum);
 extern FmgrInfo *index_getprocinfo(Relation irel, AttrNumber attnum,
 				  uint16 procnum);
+extern void index_set_current_insert(Oid relid, ItemPointer tid);
+extern void index_unset_current_insert(void);
+extern void index_check_constraint(Relation heapRelation,
+								   Relation indexRelation,
+								   ItemPointer tid,
+								   TupleTableSlot *slot);
+
+extern Size CurrentIndexInsertsShmemSize(void);
+extern void CurrentIndexInsertsShmemInit(void);
+extern void AtEOXact_IndexConstraints(void);
 
 /*
  * index access method support routines (in genam.c)
diff --git a/src/include/catalog/index.h b/src/include/catalog/index.h
index 7275641..bf14c3a 100644
--- a/src/include/catalog/index.h
+++ b/src/include/catalog/index.h
@@ -36,6 +36,7 @@ extern Oid index_create(Oid heapRelationId,
 			 Oid tableSpaceId,
 			 Oid *classObjectId,
 			 int16 *coloptions,
+			 StrategyNumber *constrats,
 			 Datum reloptions,
 			 bool isprimary,
 			 bool isconstraint,
diff --git a/src/include/catalog/pg_attribute.h b/src/include/catalog/pg_attribute.h
index eaa405f..413cf0a 100644
--- a/src/include/catalog/pg_attribute.h
+++ b/src/include/catalog/pg_attribute.h
@@ -477,6 +477,7 @@ DATA(insert ( 1259 tableoid			26 0  4  -7 0 -1 -1 t p i t f f t 0 _null_));
 { 0, {"indclass"},			30, -1, -1, 11, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
 { 0, {"indoption"},			22, -1, -1, 12, 1, -1, -1, false, 'p', 'i', true, false, false, true, 0, { 0 } }, \
 { 0, {"indexprs"},			25, -1, -1, 13, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
-{ 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }
+{ 0, {"indpred"},			25, -1, -1, 14, 0, -1, -1, false, 'x', 'i', false, false, false, true, 0, { 0 } }, \
+{ 0, {"indconstrats"},		22, -1, -1, 15, 1, -1, -1, false, 'p', 'i', false, false, false, true, 0, { 0 } }
 
 #endif   /* PG_ATTRIBUTE_H */
diff --git a/src/include/catalog/pg_index.h b/src/include/catalog/pg_index.h
index 19069db..9ab905c 100644
--- a/src/include/catalog/pg_index.h
+++ b/src/include/catalog/pg_index.h
@@ -49,6 +49,7 @@ CATALOG(pg_index,2610) BKI_WITHOUT_OIDS
 								 * each zero entry in indkey[] */
 	text		indpred;		/* expression tree for predicate, if a partial
 								 * index; else NULL */
+	int2vector	indconstrats;	/* index constraint strategies */
 } FormData_pg_index;
 
 /* ----------------
@@ -62,7 +63,7 @@ typedef FormData_pg_index *Form_pg_index;
  *		compiler constants for pg_index
  * ----------------
  */
-#define Natts_pg_index					14
+#define Natts_pg_index					15
 #define Anum_pg_index_indexrelid		1
 #define Anum_pg_index_indrelid			2
 #define Anum_pg_index_indnatts			3
@@ -77,6 +78,7 @@ typedef FormData_pg_index *Form_pg_index;
 #define Anum_pg_index_indoption			12
 #define Anum_pg_index_indexprs			13
 #define Anum_pg_index_indpred			14
+#define Anum_pg_index_indconstrats		15
 
 /*
  * Index AMs that support ordered scans must support these two indoption
diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h
index a108b80..acfcdc0 100644
--- a/src/include/nodes/parsenodes.h
+++ b/src/include/nodes/parsenodes.h
@@ -501,6 +501,7 @@ typedef struct IndexElem
 	List	   *opclass;		/* name of desired opclass; NIL = default */
 	SortByDir	ordering;		/* ASC/DESC/default */
 	SortByNulls nulls_ordering; /* FIRST/LAST/default */
+	List	   *constraint_oper;	/* name of constraint operator */
 } IndexElem;
 
 /*
diff --git a/src/include/storage/lwlock.h b/src/include/storage/lwlock.h
index e389c61..9e6f93e 100644
--- a/src/include/storage/lwlock.h
+++ b/src/include/storage/lwlock.h
@@ -63,6 +63,7 @@ typedef enum LWLockId
 	TwoPhaseStateLock,
 	TablespaceCreateLock,
 	BtreeVacuumLock,
+	IndexConstraintLock,
 	AddinShmemInitLock,
 	AutovacuumLock,
 	AutovacuumScheduleLock,
diff --git a/src/include/utils/relcache.h b/src/include/utils/relcache.h
index 7d4d914..305d1d2 100644
--- a/src/include/utils/relcache.h
+++ b/src/include/utils/relcache.h
@@ -43,6 +43,7 @@ extern Oid	RelationGetOidIndex(Relation relation);
 extern List *RelationGetIndexExpressions(Relation relation);
 extern List *RelationGetIndexPredicate(Relation relation);
 extern Bitmapset *RelationGetIndexAttrBitmap(Relation relation);
+extern int2vector *RelationGetIndexConstraintStrategies(Relation relation);
 
 extern void RelationSetIndexList(Relation relation,
 					 List *indexIds, Oid oidIndex);
-- 
Sent via pgsql-hackers mailing list (pgsql-hackers@postgresql.org)
To make changes to your subscription:
http://www.postgresql.org/mailpref/pgsql-hackers

Reply via email to