Cleanup and simplification of constraint processing.  Simplifications
to the VM for better test coverage. (CVS 4729)

FossilOrigin-Name: d9ebe9d78c558af050c44ac4437ce0ef8193a4a8
diff --git a/src/insert.c b/src/insert.c
index e62e623..6136454 100644
--- a/src/insert.c
+++ b/src/insert.c
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle INSERT statements in SQLite.
 **
-** $Id: insert.c,v 1.225 2008/01/17 16:22:15 drh Exp $
+** $Id: insert.c,v 1.226 2008/01/19 03:35:59 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -943,7 +943,7 @@
 **
 **    1.  The rowid of the row to be updated before the update.  This
 **        value is omitted unless we are doing an UPDATE that involves a
-**        change to the record number. (Or writing to a virtual table.)
+**        change to the record number or writing to a virtual table.
 **
 **    2.  The rowid of the row after the update.
 **
@@ -957,7 +957,10 @@
 **
 ** The old rowid shown as entry (1) above is omitted unless both isUpdate
 ** and rowidChng are 1.  isUpdate is true for UPDATEs and false for
-** INSERTs and rowidChng is true if the record number is being changed.
+** INSERTs.  RowidChng means that the new rowid is explicitly specified by
+** the update or insert statement.  If rowidChng is false, it means that
+** the rowid is computed automatically in an insert or that the rowid value
+** is not modified by the update.
 **
 ** The code generated by this routine store new index entries into
 ** registers identified by aRegIdx[].  No index entry is created for
@@ -1009,12 +1012,6 @@
 ** read/write cursors with cursor number baseCur+i for the i-th cursor.
 ** Except, if there is no possibility of a REPLACE action then
 ** cursors do not need to be open for indices where aRegIdx[i]==0.
-**
-** If the isUpdate flag is true, it means that the "baseCur" cursor is
-** initially pointing to an entry that is being updated.  The isUpdate
-** flag causes extra code to be generated so that the "baseCur" cursor
-** is still pointing at the same entry after the routine returns.
-** Without the isUpdate flag, the "baseCur" cursor might be moved.
 */
 void sqlite3GenerateConstraintChecks(
   Parse *pParse,      /* The parser context */
@@ -1022,7 +1019,7 @@
   int baseCur,        /* Index of a read/write cursor pointing at pTab */
   int regRowid,       /* Index of the range of input registers */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
-  int rowidChng,      /* True if the rowid will change */
+  int rowidChng,      /* True if the rowid might collide with existing entry */
   int isUpdate,       /* True for UPDATE, False for INSERT */
   int overrideError,  /* Override onError to this if not OE_Default */
   int ignoreDest      /* Jump to this label on an OE_Ignore resolution */
@@ -1031,7 +1028,7 @@
   Vdbe *v;
   int nCol;
   int onError;
-  int j1, j2, j3;     /* Address of jump instructions */
+  int j1, j2, j3;     /* Addresses of jump instructions */
   int regData;        /* Register containing first data column */
   int iCur;
   Index *pIdx;
@@ -1116,41 +1113,41 @@
       onError = OE_Abort;
     }
     
-    if( isUpdate ){
-      j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1);
-    }
-    j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
-    switch( onError ){
-      default: {
-        onError = OE_Abort;
-        /* Fall thru into the next case */
+    if( onError==OE_Replace && pTab->pIndex==0 ){
+      seenReplace = 1;
+    }else{
+      if( isUpdate ){
+        j2 = sqlite3VdbeAddOp3(v, OP_Eq, regRowid, 0, regRowid-1);
       }
-      case OE_Rollback:
-      case OE_Abort:
-      case OE_Fail: {
-        sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
-                         "PRIMARY KEY must be unique", P4_STATIC);
-        break;
-      }
-      case OE_Replace: {
-        sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
-        if( isUpdate ){
-          sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
+      j3 = sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, 0, regRowid);
+      switch( onError ){
+        default: {
+          onError = OE_Abort;
+          /* Fall thru into the next case */
         }
-        seenReplace = 1;
-        break;
+        case OE_Rollback:
+        case OE_Abort:
+        case OE_Fail: {
+          sqlite3VdbeAddOp4(v, OP_Halt, SQLITE_CONSTRAINT, onError, 0,
+                           "PRIMARY KEY must be unique", P4_STATIC);
+          break;
+        }
+        case OE_Replace: {
+          sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
+          seenReplace = 1;
+          break;
+        }
+        case OE_Ignore: {
+          assert( seenReplace==0 );
+          sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
+          break;
+        }
       }
-      case OE_Ignore: {
-        assert( seenReplace==0 );
-        sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
-        break;
+      sqlite3VdbeJumpHere(v, j3);
+      if( isUpdate ){
+        sqlite3VdbeJumpHere(v, j2);
       }
     }
-    sqlite3VdbeJumpHere(v, j3);
-    if( isUpdate ){
-      sqlite3VdbeJumpHere(v, j2);
-      sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-1);
-    }
   }
 
   /* Test all UNIQUE constraints by creating entries for each UNIQUE
@@ -1239,9 +1236,6 @@
       }
       case OE_Replace: {
         sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0);
-        if( isUpdate ){
-          sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
-        }
         seenReplace = 1;
         break;
       }