diff --git a/src/backend/executor/execUtils.c b/src/backend/executor/execUtils.c index c6ae2d4296..5d6473dfc6 100644 --- a/src/backend/executor/execUtils.c +++ b/src/backend/executor/execUtils.c @@ -8,7 +8,7 @@ * * * IDENTIFICATION - * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.168 2010/01/02 16:57:41 momjian Exp $ + * $PostgreSQL: pgsql/src/backend/executor/execUtils.c,v 1.169 2010/01/02 17:53:56 tgl Exp $ * *------------------------------------------------------------------------- */ @@ -1167,7 +1167,9 @@ check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, int i; bool conflict; bool found_self; + ExprContext *econtext; TupleTableSlot *existing_slot; + TupleTableSlot *save_scantuple; /* * If any of the input values are NULL, the constraint check is assumed @@ -1194,9 +1196,19 @@ check_exclusion_constraint(Relation heap, Relation index, IndexInfo *indexInfo, values[i]); } - /* Need a TupleTableSlot to put existing tuples in */ + /* + * Need a TupleTableSlot to put existing tuples in. + * + * To use FormIndexDatum, we have to make the econtext's scantuple point + * to this slot. Be sure to save and restore caller's value for + * scantuple. + */ existing_slot = MakeSingleTupleTableSlot(RelationGetDescr(heap)); + econtext = GetPerTupleExprContext(estate); + save_scantuple = econtext->ecxt_scantuple; + econtext->ecxt_scantuple = existing_slot; + /* * May have to restart scan from this point if a potential * conflict is found. @@ -1311,6 +1323,8 @@ retry: RelationGetRelationName(index)), errhint("This may be because of a non-immutable index expression."))); + econtext->ecxt_scantuple = save_scantuple; + ExecDropSingleTupleTableSlot(existing_slot); return !conflict; diff --git a/src/test/regress/input/constraints.source b/src/test/regress/input/constraints.source index ee396f3703..0d278212c0 100644 --- a/src/test/regress/input/constraints.source +++ b/src/test/regress/input/constraints.source @@ -376,26 +376,26 @@ CREATE TABLE circles ( c1 CIRCLE, c2 TEXT, EXCLUDE USING gist - (c1 WITH &&, (c2::circle) WITH ~=) + (c1 WITH &&, (c2::circle) WITH &&) WHERE (circle_center(c1) <> '(0,0)') ); -- these should succeed because they don't match the index predicate INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>'); -INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>'); +INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 4>'); -- succeed INSERT INTO circles VALUES('<(10,10), 10>', '<(0,0), 5>'); -- fail, overlaps -INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 5>'); +INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 4>'); -- succeed because c1 doesn't overlap INSERT INTO circles VALUES('<(20,20), 1>', '<(0,0), 5>'); --- succeed because c2 is not the same -INSERT INTO circles VALUES('<(20,20), 10>', '<(1,1), 5>'); +-- succeed because c2 doesn't overlap +INSERT INTO circles VALUES('<(20,20), 10>', '<(10,10), 5>'); -- should fail on existing data without the WHERE clause ALTER TABLE circles ADD EXCLUDE USING gist - (c1 WITH &&, (c2::circle) WITH ~=); + (c1 WITH &&, (c2::circle) WITH &&); DROP TABLE circles; diff --git a/src/test/regress/output/constraints.source b/src/test/regress/output/constraints.source index 684394fd83..0800365c26 100644 --- a/src/test/regress/output/constraints.source +++ b/src/test/regress/output/constraints.source @@ -520,29 +520,29 @@ CREATE TABLE circles ( c1 CIRCLE, c2 TEXT, EXCLUDE USING gist - (c1 WITH &&, (c2::circle) WITH ~=) + (c1 WITH &&, (c2::circle) WITH &&) WHERE (circle_center(c1) <> '(0,0)') ); NOTICE: CREATE TABLE / EXCLUDE will create implicit index "circles_c1_c2_exclusion" for table "circles" -- these should succeed because they don't match the index predicate INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>'); -INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 5>'); +INSERT INTO circles VALUES('<(0,0), 5>', '<(0,0), 4>'); -- succeed INSERT INTO circles VALUES('<(10,10), 10>', '<(0,0), 5>'); -- fail, overlaps -INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 5>'); +INSERT INTO circles VALUES('<(20,20), 10>', '<(0,0), 4>'); ERROR: conflicting key value violates exclusion constraint "circles_c1_c2_exclusion" -DETAIL: Key (c1, (c2::circle))=(<(20,20),10>, <(0,0),5>) conflicts with existing key (c1, (c2::circle))=(<(10,10),10>, <(0,0),5>). +DETAIL: Key (c1, (c2::circle))=(<(20,20),10>, <(0,0),4>) conflicts with existing key (c1, (c2::circle))=(<(10,10),10>, <(0,0),5>). -- succeed because c1 doesn't overlap INSERT INTO circles VALUES('<(20,20), 1>', '<(0,0), 5>'); --- succeed because c2 is not the same -INSERT INTO circles VALUES('<(20,20), 10>', '<(1,1), 5>'); +-- succeed because c2 doesn't overlap +INSERT INTO circles VALUES('<(20,20), 10>', '<(10,10), 5>'); -- should fail on existing data without the WHERE clause ALTER TABLE circles ADD EXCLUDE USING gist - (c1 WITH &&, (c2::circle) WITH ~=); + (c1 WITH &&, (c2::circle) WITH &&); NOTICE: ALTER TABLE / ADD EXCLUDE will create implicit index "circles_c1_c2_exclusion1" for table "circles" ERROR: could not create exclusion constraint "circles_c1_c2_exclusion1" -DETAIL: Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>). +DETAIL: Key (c1, (c2::circle))=(<(0,0),5>, <(0,0),5>) conflicts with key (c1, (c2::circle))=(<(0,0),5>, <(0,0),4>). DROP TABLE circles; -- Check deferred exclusion constraint CREATE TABLE deferred_excl (