More work toward converting the VM into a register-based machine. (CVS 4704)

FossilOrigin-Name: 8cbd46517f407b3b1ce187b623db10f00aa415ea
diff --git a/src/insert.c b/src/insert.c
index 7258570..7577f46 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.221 2008/01/10 03:46:36 drh Exp $
+** $Id: insert.c,v 1.222 2008/01/10 23:50:11 drh Exp $
 */
 #include "sqliteInt.h"
 
@@ -28,6 +28,9 @@
 **  'c'            NUMERIC
 **  'd'            INTEGER
 **  'e'            REAL
+**
+** An extra 'b' is appended to the end of the string to cover the
+** rowid that appears as the last column in every index.
 */
 void sqlite3IndexAffinityStr(Vdbe *v, Index *pIdx){
   if( !pIdx->zColAff ){
@@ -42,14 +45,15 @@
     int n;
     Table *pTab = pIdx->pTable;
     sqlite3 *db = sqlite3VdbeDb(v);
-    pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+1);
+    pIdx->zColAff = (char *)sqlite3DbMallocZero(db, pIdx->nColumn+2);
     if( !pIdx->zColAff ){
       return;
     }
     for(n=0; n<pIdx->nColumn; n++){
       pIdx->zColAff[n] = pTab->aCol[pIdx->aiColumn[n]].affinity;
     }
-    pIdx->zColAff[pIdx->nColumn] = '\0';
+    pIdx->zColAff[n++] = SQLITE_AFF_NONE;
+    pIdx->zColAff[n] = 0;
   }
  
   sqlite3VdbeChangeP4(v, -1, pIdx->zColAff, 0);
@@ -679,6 +683,9 @@
   */
   endOfLoop = sqlite3VdbeMakeLabel(v);
   if( triggers_exist & TRIGGER_BEFORE ){
+    int regRowid;
+    int regCols;
+    int regRec;
 
     /* build the NEW.* reference row.  Note that if there is an INTEGER
     ** PRIMARY KEY into which a NULL is being inserted, that NULL will be
@@ -686,20 +693,19 @@
     ** we do not know what the unique ID will be (because the insert has
     ** not happened yet) so we substitute a rowid of -1
     */
+    regRowid = sqlite3GetTempReg(pParse);
     if( keyColumn<0 ){
-      sqlite3VdbeAddOp2(v, OP_Integer, -1, 0);
+      sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
     }else if( useTempTable ){
-      sqlite3VdbeAddOp2(v, OP_Column, srcTab, keyColumn);
+      sqlite3VdbeAddOp3(v, OP_Column, srcTab, keyColumn, regRowid);
     }else{
       int j1;
       assert( pSelect==0 );  /* Otherwise useTempTable is true */
-      sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, 0);
-      sqlite3VdbeAddOp0(v, OP_SCopy);
-      j1 = sqlite3VdbeAddOp0(v, OP_NotNull);
-      sqlite3VdbeAddOp1(v, OP_Pop, 1);
-      sqlite3VdbeAddOp1(v, OP_Integer, -1);
+      sqlite3ExprCode(pParse, pList->a[keyColumn].pExpr, regRowid);
+      j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
+      sqlite3VdbeAddOp2(v, OP_Integer, -1, regRowid);
       sqlite3VdbeJumpHere(v, j1);
-      sqlite3VdbeAddOp0(v, OP_MustBeInt);
+      sqlite3VdbeAddOp1(v, OP_MustBeInt, regRowid);
     }
 
     /* Cannot have triggers on a virtual table. If it were possible,
@@ -709,6 +715,7 @@
 
     /* Create the new column data
     */
+    regCols = sqlite3GetTempRange(pParse, pTab->nCol);
     for(i=0; i<pTab->nCol; i++){
       if( pColumn==0 ){
         j = i;
@@ -718,15 +725,16 @@
         }
       }
       if( pColumn && j>=pColumn->nId ){
-        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, 0);
+        sqlite3ExprCode(pParse, pTab->aCol[i].pDflt, regCols+i);
       }else if( useTempTable ){
-        sqlite3VdbeAddOp2(v, OP_Column, srcTab, j); 
+        sqlite3VdbeAddOp3(v, OP_Column, srcTab, j, regCols+i); 
       }else{
         assert( pSelect==0 ); /* Otherwise useTempTable is true */
-        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr);
+        sqlite3ExprCodeAndCache(pParse, pList->a[j].pExpr, regCols+i);
       }
     }
-    sqlite3VdbeAddOp2(v, OP_MakeRecord, pTab->nCol, 0);
+    regRec = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, regCols, pTab->nCol, regRec);
 
     /* If this is an INSERT on a view with an INSTEAD OF INSERT trigger,
     ** do not attempt any conversions before assembling the record.
@@ -736,7 +744,10 @@
     if( !isView ){
       sqlite3TableAffinityStr(v, pTab);
     }
-    sqlite3CodeInsert(pParse, newIdx, OPFLAG_APPEND);
+    sqlite3VdbeAddOp3(v, OP_Insert, newIdx, regRec, regRowid);
+    sqlite3ReleaseTempReg(pParse, regRec);
+    sqlite3ReleaseTempReg(pParse, regRowid);
+    sqlite3ReleaseTempRange(pParse, regCols, pTab->nCol);
 
     /* Fire BEFORE or INSTEAD OF triggers */
     if( sqlite3CodeRowTrigger(pParse, TK_INSERT, 0, TRIGGER_BEFORE, pTab, 
@@ -1123,7 +1134,7 @@
         break;
       }
       case OE_Replace: {
-        sqlite3GenerateRowIndexDelete(v, pTab, baseCur, 0);
+        sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
         if( isUpdate ){
           sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
         }
@@ -1148,20 +1159,25 @@
   ** Add the new records to the indices as we go.
   */
   for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
+    int regIdx;
+    int regR;
+
     if( aRegIdx[iCur]==0 ) continue;  /* Skip unused indices */
 
     /* Create a key for accessing the index entry */
-    sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+    regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn+1);
     for(i=0; i<pIdx->nColumn; i++){
       int idx = pIdx->aiColumn[i];
       if( idx==pTab->iPKey ){
-        sqlite3VdbeAddOp1(v, OP_SCopy, regRowid);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
       }else{
-        sqlite3VdbeAddOp1(v, OP_SCopy, regData+idx);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
       }
     }
-    j2 = sqlite3VdbeAddOp3(v, OP_MakeIdxRec, pIdx->nColumn, 0, aRegIdx[iCur]);
+    sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
+    sqlite3VdbeAddOp3(v, OP_RegMakeRec, regIdx, pIdx->nColumn+1, aRegIdx[iCur]);
     sqlite3IndexAffinityStr(v, pIdx);
+    sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn+1);
 
     /* Find out what action to take in case there is an indexing conflict */
     onError = pIdx->onError;
@@ -1178,9 +1194,11 @@
     
 
     /* Check to see if the new index entry will be unique */
-    sqlite3VdbeAddOp1(v, OP_SCopy, aRegIdx[iCur]);
-    sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-    j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0, 0, 0, P4_INT32);
+    j2 = sqlite3VdbeAddOp3(v, OP_IsNull, regIdx, 0, pIdx->nColumn);
+    regR = sqlite3GetTempReg(pParse);
+    sqlite3VdbeAddOp2(v, OP_SCopy, regRowid-hasTwoRowids, regR);
+    j3 = sqlite3VdbeAddOp4(v, OP_IsUnique, baseCur+iCur+1, 0,
+                           regR, (char*)aRegIdx[iCur], P4_INT32);
 
     /* Generate code that executes if the new index entry is not unique */
     assert( onError==OE_Rollback || onError==OE_Abort || onError==OE_Fail
@@ -1217,26 +1235,21 @@
       }
       case OE_Ignore: {
         assert( seenReplace==0 );
-        sqlite3VdbeAddOp1(v, OP_Pop, 2+hasTwoRowids);
         sqlite3VdbeAddOp2(v, OP_Goto, 0, ignoreDest);
         break;
       }
       case OE_Replace: {
-        int iRowid = sqlite3StackToReg(pParse, 1);
-        sqlite3GenerateRowDelete(pParse->db, v, pTab, baseCur, iRowid, 0);
+        sqlite3GenerateRowDelete(pParse, pTab, baseCur, regR, 0);
         if( isUpdate ){
-          sqlite3VdbeAddOp1(v, OP_SCopy, regRowid-hasTwoRowids);
-          sqlite3VdbeAddOp2(v, OP_MoveGe, baseCur, 0);
+          sqlite3VdbeAddOp3(v, OP_MoveGe, baseCur, 0, regRowid-hasTwoRowids);
         }
         seenReplace = 1;
         break;
       }
     }
-    sqlite3VdbeJumpHere(v, j3);
-    sqlite3VdbeAddOp1(v, OP_Pop, 1);
-#if NULL_DISTINCT_FOR_UNIQUE
     sqlite3VdbeJumpHere(v, j2);
-#endif
+    sqlite3VdbeJumpHere(v, j3);
+    sqlite3ReleaseTempReg(pParse, regR);
   }
 }