]> granicus.if.org Git - postgresql/commitdiff
check_exclusion_constraint didn't actually work correctly for index
authorTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Jan 2010 17:53:57 +0000 (17:53 +0000)
committerTom Lane <tgl@sss.pgh.pa.us>
Sat, 2 Jan 2010 17:53:57 +0000 (17:53 +0000)
expressions: FormIndexDatum requires the estate's scantuple to already point
at the tuple the values are supposedly being extracted from.  Adjust test
case so that this type of confusion will be exposed.
Per report from hubert depesz lubaczewski.

src/backend/executor/execUtils.c
src/test/regress/input/constraints.source
src/test/regress/output/constraints.source

index c6ae2d4296faba4190190f6d9bbc634c728603fc..5d6473dfc69a765274b4996308153458bb9204b9 100644 (file)
@@ -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;
index ee396f370372a3198a3b1fb490352b5bc84ca0ea..0d278212c02a4801cd0919b4c2a134b448a2ac42 100644 (file)
@@ -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;
 
index 684394fd83d2a624e1c5ca5d4c454f05f9c8c251..0800365c269596e1ddf46ed162b1185d0571ee82 100644 (file)
@@ -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 (