]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Refactor the INSERT, DELETE, and UPDATE code generators to distinguish between
authordrh <drh@noemail.net>
Thu, 31 Oct 2013 11:15:09 +0000 (11:15 +0000)
committerdrh <drh@noemail.net>
Thu, 31 Oct 2013 11:15:09 +0000 (11:15 +0000)
the "data cursor" and the "first index cursor", which are no longer consecutive
in the case of a WITHOUT ROWID table.

FossilOrigin-Name: 1adfca6019847d37dee4a297669f29d5ca184066

manifest
manifest.uuid
src/delete.c
src/insert.c
src/pragma.c
src/sqliteInt.h
src/update.c
src/vdbe.c
src/vdbeaux.c
test/without_rowid1.test

index 966cce8d776287e49fd2f6dd50fa10132e0200d8..5e03b35ba4db237dc72284793688049d49a2ce65 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Continue\sworking\sto\sget\sUPDATE\soperational\sfor\sWITHOUT\sROWID\stables.\nFix\sPRAGMA\sintegrity_check\sso\sthat\sit\sworks\son\sWITHOUT\sROWID\stables.
-D 2013-10-30T20:22:55.102
+C Refactor\sthe\sINSERT,\sDELETE,\sand\sUPDATE\scode\sgenerators\sto\sdistinguish\sbetween\nthe\s"data\scursor"\sand\sthe\s"first\sindex\scursor",\swhich\sare\sno\slonger\sconsecutive\nin\sthe\scase\sof\sa\sWITHOUT\sROWID\stable.
+D 2013-10-31T11:15:09.631
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in 0522b53cdc1fcfc18f3a98e0246add129136c654
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -173,7 +173,7 @@ F src/callback.c f99a8957ba2adf369645fac0db09ad8adcf1caa2
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c ea4b7f3623a0fcb1146e7f245d7410033e86859c
 F src/date.c 593c744b2623971e45affd0bde347631bdfa4625
-F src/delete.c 7b56fcc7e290f52e1825692cce37e2f001c7286b
+F src/delete.c d50cc704030139e19f2e9d5ac7a49db04dfe08a9
 F src/expr.c 3180b6332072b263f845592e72e92971af562ab0
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 628f81177299660a86e40359b3689b81f517e125
@@ -182,7 +182,7 @@ F src/global.c 5caf4deab621abb45b4c607aad1bd21c20aac759
 F src/hash.c ac3470bbf1ca4ae4e306a8ecb0fdf1731810ffe4
 F src/hash.h 8890a25af81fb85a9ad7790d32eedab4b994da22
 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08
-F src/insert.c 4d832cca6d235ca0fc7f2c4acff23ca3246c8548
+F src/insert.c 076f600e99cd49ce4509bcff3e0620df0fdcf46d
 F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d
 F src/legacy.c 0df0b1550b9cc1f58229644735e317ac89131f12
 F src/lempar.c cdf0a000315332fc9b50b62f3b5e22e080a0952b
@@ -212,7 +212,7 @@ F src/parse.y 073a8294e1826f1b1656e84806b77e4199f4bb57
 F src/pcache.c f8043b433a57aba85384a531e3937a804432a346
 F src/pcache.h a5e4f5d9f5d592051d91212c5949517971ae6222
 F src/pcache1.c a467393909a4ed7ca9de066d85ba5c5b04a5be63
-F src/pragma.c c6612470d2db2cc30d226c1990faeaff7320a296
+F src/pragma.c 74dec25a3f0d3e5da796345a0ca817cb445e9d2a
 F src/prepare.c f47ba2bba7ac5650881ab6c41f6d33a6de1a8d52
 F src/printf.c da9119eb31a187a4b99f60aa4a225141c0ebb74b
 F src/random.c 0b2dbc37fdfbfa6bd455b091dfcef5bdb32dba68
@@ -223,7 +223,7 @@ F src/shell.c d5eebdc6034014103de2b9d58e1d3f6f7de0fb50
 F src/sqlite.h.in 547a44dd4ff4d975e92a645ea2d609e543a83d0f
 F src/sqlite3.rc 11094cc6a157a028b301a9f06b3d03089ea37c3e
 F src/sqlite3ext.h 886f5a34de171002ad46fae8c36a7d8051c190fc
-F src/sqliteInt.h f8fc23b598245de9460af2de163c91fc31d4fb27
+F src/sqliteInt.h c41205f31edb0c803a7b1bad92fe91d552a9eec7
 F src/sqliteLimit.h 164b0e6749d31e0daa1a4589a169d31c0dec7b3d
 F src/status.c 7ac05a5c7017d0b9f0b4bcd701228b784f987158
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
@@ -275,15 +275,15 @@ F src/test_vfstrace.c 34b544e80ba7fb77be15395a609c669df2e660a2
 F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9
 F src/tokenize.c 70061085a51f2f4fc15ece94f32c03bcb78e63b2
 F src/trigger.c 53d6b5d50b3b23d4fcd0a36504feb5cff9aed716
-F src/update.c 103ab76ccd4211b4c298ad4fe4c7a16fbd274818
+F src/update.c 3be9af558558062d335e35acb13f7507f053ff76
 F src/utf.c 6fc6c88d50448c469c5c196acf21617a24f90269
 F src/util.c 2fa6c821d28bbdbeec1b2a7b091a281c9ef8f918
 F src/vacuum.c 3728d74919d4fb1356f9e9a13e27773db60b7179
-F src/vdbe.c 05857502186641716e8d9204de138b642208628f
+F src/vdbe.c da933a7c58470db06e5705d001013d52020ef7e2
 F src/vdbe.h c18a2dd91c838601b867a214e43c5f66d5d001ba
 F src/vdbeInt.h 42dcff74dbeb2b071e569b53f885fc9c2e4b4cb0
 F src/vdbeapi.c 93a22a9ba2abe292d5c2cf304d7eb2e894dde0ed
-F src/vdbeaux.c 347cfece32afdbac935000fd6ea2b58930a99e8a
+F src/vdbeaux.c 717c8c2eb30641a75790311669ee0dfe5504ec56
 F src/vdbeblob.c ef973d8d9f8170015343dd8824f795da675caa87
 F src/vdbemem.c 6087553f2c61c06c8e1ab3959a60e174d6240c98
 F src/vdbesort.c 3937e06b2a0e354500e17dc206ef4c35770a5017
@@ -1076,7 +1076,7 @@ F test/wherelimit.test 5e9fd41e79bb2b2d588ed999d641d9c965619b31
 F test/wild001.test bca33f499866f04c24510d74baf1e578d4e44b1c
 F test/win32lock.test 7a6bd73a5dcdee39b5bb93e92395e1773a194361
 F test/win32longpath.test e2aafc07e6990fe86c69be22a3d1a0e210cd329b
-F test/without_rowid1.test 1c3d5a5df986d931a3c5c19ffef5804bd324d9e5
+F test/without_rowid1.test fb3ceaa20bda4e0338f594696a49014c3cbeb30c
 F test/zeroblob.test caaecfb4f908f7bc086ed238668049f96774d688
 F test/zerodamage.test 209d7ed441f44cc5299e4ebffbef06fd5aabfefd
 F tool/build-all-msvc.bat 38623a30fd58288fda5cc7f7df2682aaab75c9d5 x
@@ -1128,7 +1128,7 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381
 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4
 F tool/warnings.sh d1a6de74685f360ab718efda6265994b99bbea01
 F tool/win/sqlite.vsix 030f3eeaf2cb811a3692ab9c14d021a75ce41fff
-P 6d9af6065fc0da8337aee2297a8da7511eecccf1
-R 00013e769d264c62972e72b68f63eb56
+P 0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
+R 5cee3ee2f21ff3dcfee1d1450366398f
 U drh
-Z 05e092e5dbaf4f4f4e2497c5914c1170
+Z 8325d71a27ada5d7265b86dd95f46d5a
index 5b6052dd47c8886419816a2a106e2770055ebe97..cf92754a40583078f16c5e1ae097899814562a05 100644 (file)
@@ -1 +1 @@
-0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54
\ No newline at end of file
+1adfca6019847d37dee4a297669f29d5ca184066
\ No newline at end of file
index b7601f8af4ed1343b8bd389c6059e8edb308f3c5..fc0d4813ddb5cc4ba719e0363e52945c8cb29253 100644 (file)
@@ -231,7 +231,9 @@ void sqlite3DeleteFrom(
   int i;                 /* Loop counter */
   WhereInfo *pWInfo;     /* Information about the WHERE clause */
   Index *pIdx;           /* For looping over indices of the table */
-  int iCur;              /* VDBE Cursor number for pTab */
+  int iTabCur;           /* Cursor number for the table */
+  int iDataCur;          /* VDBE cursor for the canonical data source */
+  int iIdxCur;           /* Cursor number of the first index */
   sqlite3 *db;           /* Main database structure */
   AuthContext sContext;  /* Authorization context */
   NameContext sNC;       /* Name context to resolve expressions in */
@@ -296,7 +298,7 @@ void sqlite3DeleteFrom(
   /* Assign  cursor number to the table and all its indices.
   */
   assert( pTabList->nSrc==1 );
-  iCur = pTabList->a[0].iCursor = pParse->nTab++;
+  iTabCur = pTabList->a[0].iCursor = pParse->nTab++;
   for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){
     pParse->nTab++;
   }
@@ -321,7 +323,7 @@ void sqlite3DeleteFrom(
   */
 #if !defined(SQLITE_OMIT_VIEW) && !defined(SQLITE_OMIT_TRIGGER)
   if( isView ){
-    sqlite3MaterializeView(pParse, pTab, pWhere, iCur);
+    sqlite3MaterializeView(pParse, pTab, pWhere, iTabCur);
   }
 #endif
 
@@ -385,7 +387,7 @@ void sqlite3DeleteFrom(
     pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, 0, 0);
     if( pWInfo==0 ) goto delete_from_cleanup;
     for(i=0; i<nPk; i++){
-      sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, pPk->aiColumn[i], iPk+i);
+      sqlite3ExprCodeGetColumnOfTable(v, pTab, iTabCur, pPk->aiColumn[i],iPk+i);
     }
     sqlite3VdbeAddOp4(v, OP_MakeRecord, iPk, nPk, iKey,
                       sqlite3IndexAffinityStr(v, pPk), P4_TRANSIENT);
@@ -394,23 +396,27 @@ void sqlite3DeleteFrom(
 
     /* Open cursors for all indices of the table.
     */
-    sqlite3OpenTableAndIndices(pParse, pTab, iCur, iCur, OP_OpenWrite);
+    sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite,
+                               iTabCur, &iDataCur, &iIdxCur);
+    assert( iDataCur!=iTabCur );
+    assert( iDataCur>=iIdxCur );
 
     /* Loop over the primary keys to be deleted. */
     addr = sqlite3VdbeAddOp1(v, OP_Rewind, iEph);
     sqlite3VdbeAddOp2(v, OP_RowKey, iEph, iPk);
 
     /* Delete the row */
-    sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iCur, iPk, 0,
-                             1, OE_Default);
+    sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
+                             iPk, nPk, 1, OE_Default);
 
     /* End of the delete loop */
     sqlite3VdbeAddOp2(v, OP_Next, iEph, addr+1);
     sqlite3VdbeJumpHere(v, addr);
 
     /* Close the cursors open on the table and its indexes. */
-    for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-      sqlite3VdbeAddOp2(v, OP_Close, pIdx==pPk ? iCur : iCur + i, pIdx->tnum);
+    assert( iDataCur>=iIdxCur );
+    for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+      sqlite3VdbeAddOp1(v, OP_Close, iIdxCur+i);
     }
   }else{
     /* There is a WHERE clause on a rowid table.  Run a loop that extracts
@@ -427,7 +433,7 @@ void sqlite3DeleteFrom(
         pParse, pTabList, pWhere, 0, 0, WHERE_DUPLICATES_OK, 0
     );
     if( pWInfo==0 ) goto delete_from_cleanup;
-    regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iCur, iRowid, 0);
+    regRowid = sqlite3ExprCodeGetColumn(pParse, pTab, -1, iTabCur, iRowid, 0);
     sqlite3VdbeAddOp2(v, OP_RowSetAdd, iRowSet, regRowid);
     if( db->flags & SQLITE_CountRows ){
       sqlite3VdbeAddOp2(v, OP_AddImm, memCnt, 1);
@@ -444,7 +450,10 @@ void sqlite3DeleteFrom(
     ** only effect this statement has is to fire the INSTEAD OF 
     ** triggers.  */
     if( !isView ){
-      sqlite3OpenTableAndIndices(pParse, pTab, iCur, -1, OP_OpenWrite);
+      sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur,
+                                 &iDataCur, &iIdxCur);
+      assert( iDataCur==iTabCur );
+      assert( iIdxCur==iDataCur+1 );
     }
 
     addr = sqlite3VdbeAddOp3(v, OP_RowSetRead, iRowSet, end, iRowid);
@@ -461,8 +470,8 @@ void sqlite3DeleteFrom(
 #endif
     {
       int count = (pParse->nested==0);    /* True to count changes */
-      sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iCur, iRowid, 0,
-                               count, OE_Default);
+      sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
+                               iRowid, 1, count, OE_Default);
     }
 
     /* End of the delete loop */
@@ -471,10 +480,10 @@ void sqlite3DeleteFrom(
 
     /* Close the cursors open on the table and its indexes. */
     if( !isView && !IsVirtual(pTab) ){
-      for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-        sqlite3VdbeAddOp2(v, OP_Close, iCur + i, pIdx->tnum);
+      sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
+      for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+        sqlite3VdbeAddOp1(v, OP_Close, iIdxCur + i);
       }
-      sqlite3VdbeAddOp1(v, OP_Close, iCur);
     }
   }
 
@@ -519,15 +528,16 @@ delete_from_cleanup:
 ** The VDBE must be in a particular state when this routine is called.
 ** These are the requirements:
 **
-**   1.  A read/write cursor pointing to pTab, the table containing the row
-**       to be deleted, must be opened as cursor number iCur (except for
-**       WITHOUT ROWID tables which do not have a main table).
+**   1.  iDataCur is an open cursor on the btree that is the primary data
+**       repository for the table.  This will be either the table itself,
+**       in the case of a rowid table, or the PRIMARY KEY index in the case
+**       of a WITHOUT ROWID table.
 **
 **   2.  Read/write cursors for all indices of pTab must be open as
-**       cursor number iCur+i for the i-th index.
+**       cursor number iIdxCur+i for the i-th index.
 **
 **   3.  The primary key for the row to be deleted must be stored in a
-**       sequence of memory cells starting at iPk. 
+**       sequence of nPk memory cells starting at iPk. 
 **
 ** This routine generates code to remove both the table record and all 
 ** index entries that point to that record.
@@ -536,7 +546,8 @@ void sqlite3GenerateRowDelete(
   Parse *pParse,     /* Parsing context */
   Table *pTab,       /* Table containing the row to be deleted */
   Trigger *pTrigger, /* List of triggers to (potentially) fire */
-  int iCur,          /* Cursor number for the table */
+  int iDataCur,      /* Cursor from which column data is extracted */
+  int iIdxCur,       /* First index cursor */
   int iPk,           /* First memory cell containing the PRIMARY KEY */
   i16 nPk,           /* Number of PRIMARY KEY memory cells */
   u8 count,          /* If non-zero, increment the row change counter */
@@ -549,15 +560,15 @@ void sqlite3GenerateRowDelete(
 
   /* Vdbe is guaranteed to have been allocated by this stage. */
   assert( v );
-  VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d)",
-                         iCur, iPk, (int)nPk));
+  VdbeModuleComment((v, "BEGIN: GenerateRowDelete(%d,%d,%d,%d)",
+                         iDataCur, iIdxCur, iPk, (int)nPk));
 
   /* Seek cursor iCur to the row to delete. If this row no longer exists 
   ** (this can happen if a trigger program has already deleted it), do
   ** not attempt to delete it or fire any DELETE triggers.  */
   iLabel = sqlite3VdbeMakeLabel(v);
   opSeek = HasRowid(pTab) ? OP_NotExists : OP_NotFound;
-  sqlite3VdbeAddOp4Int(v, opSeek, iCur, iLabel, iPk, nPk);
+  sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
  
   /* If there are any triggers to fire, allocate a range of registers to
   ** use for the old.* references in the triggers.  */
@@ -579,7 +590,7 @@ void sqlite3GenerateRowDelete(
     sqlite3VdbeAddOp2(v, OP_Copy, iPk, iOld);
     for(iCol=0; iCol<pTab->nCol; iCol++){
       if( mask==0xffffffff || mask&(1<<iCol) ){
-        sqlite3ExprCodeGetColumnOfTable(v, pTab, iCur, iCol, iOld+iCol+1);
+        sqlite3ExprCodeGetColumnOfTable(v, pTab, iDataCur, iCol, iOld+iCol+1);
       }
     }
 
@@ -592,7 +603,7 @@ void sqlite3GenerateRowDelete(
     ** the BEFORE triggers coded above have already removed the row
     ** being deleted. Do not attempt to delete the row a second time, and 
     ** do not fire AFTER triggers.  */
-    sqlite3VdbeAddOp4Int(v, opSeek, iCur, iLabel, iPk, nPk);
+    sqlite3VdbeAddOp4Int(v, opSeek, iDataCur, iLabel, iPk, nPk);
 
     /* Do FK processing. This call checks that any FK constraints that
     ** refer to this table (i.e. constraints attached to other tables) 
@@ -604,11 +615,8 @@ void sqlite3GenerateRowDelete(
   ** a view (in which case the only effect of the DELETE statement is to
   ** fire the INSTEAD OF triggers).  */ 
   if( pTab->pSelect==0 ){
-    Index *pPk;
-    int iMainCur;
-    sqlite3PrincipleBtree(pTab, iCur, &pPk, &iMainCur);
-    sqlite3GenerateRowIndexDelete(pParse, pTab, iMainCur, 0);
-    sqlite3VdbeAddOp2(v, OP_Delete, iMainCur, (count?OPFLAG_NCHANGE:0));
+    sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
+    sqlite3VdbeAddOp2(v, OP_Delete, iDataCur, (count?OPFLAG_NCHANGE:0));
     if( count ){
       sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
     }
@@ -638,23 +646,22 @@ void sqlite3GenerateRowDelete(
 ** The VDBE must be in a particular state when this routine is called.
 ** These are the requirements:
 **
-**   1.  A read/write cursor pointing to pTab, the table containing the row
-**       to be deleted, must be opened as cursor number "iCur".  For
-**       WITHOUT ROWID tables that do not have a main table, the iCur
-**       cursor is unused.
+**   1.  A read/write cursor "iDataCur" pointing to canonical storage
+**       tree for the table pTab, which will be either the table itself
+**       for rowid tables or to the primary key index for WITHOUT ROWID
+**       tables.
 **
 **   2.  Read/write cursors for all indices of pTab must be open as
-**       cursor number iCur+i for the i-th index.
+**       cursor number iIdxCur+i for the i-th index.
 **
-**   3.  The "iCur" cursor must be pointing to the row that is to be
-**       deleted.  Or, for WITHOUT ROWID tables, the iCur+i cursor for
-**       the PRIMARY KEY index must be pointing to the row to that is
-**       to be deleted.
+**   3.  The "iDataCur" cursor must be pointing to the row that is to be
+**       deleted.
 */
 void sqlite3GenerateRowIndexDelete(
   Parse *pParse,     /* Parsing and code generating context */
   Table *pTab,       /* Table containing the row to be deleted */
-  int iCur,          /* Cursor number for the table */
+  int iDataCur,      /* Cursor of table holding data. */
+  int iIdxCur,       /* First index cursor */
   int *aRegIdx       /* Only delete if aRegIdx!=0 && aRegIdx[i]>0 */
 ){
   int i;
@@ -665,11 +672,11 @@ void sqlite3GenerateRowIndexDelete(
   Index *pPk;
 
   pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
-  for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
-    if( aRegIdx!=0 && aRegIdx[i-1]==0 ) continue;
+  for(i=0, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){
+    if( aRegIdx!=0 && aRegIdx[i]==0 ) continue;
     if( pIdx==pPk ) continue;
-    r1 = sqlite3GenerateIndexKey(pParse, pIdx, iCur, 0, 1, &iPartIdxLabel);
-    sqlite3VdbeAddOp3(v, OP_IdxDelete, iCur+i, r1,
+    r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 1, &iPartIdxLabel);
+    sqlite3VdbeAddOp3(v, OP_IdxDelete, iIdxCur+i, r1,
                       pIdx->uniqNotNull ? pIdx->nKeyCol : pIdx->nColumn);
     sqlite3VdbeResolveLabel(v, iPartIdxLabel);
   }
@@ -679,7 +686,8 @@ void sqlite3GenerateRowIndexDelete(
 ** Generate code that will assemble an index key and stores it in register
 ** regOut.  The key with be for index pIdx which is an index on pTab.
 ** iCur is the index of a cursor open on the pTab table and pointing to
-** the entry that needs indexing.
+** the entry that needs indexing.  If pTab is a WITHOUT ROWID table, then
+** iCur must be the cursor of the PRIMARY KEY index.
 **
 ** Return a register number which is the first in a block of
 ** registers that holds the elements of the index key.  The
@@ -696,7 +704,7 @@ void sqlite3GenerateRowIndexDelete(
 int sqlite3GenerateIndexKey(
   Parse *pParse,       /* Parsing context */
   Index *pIdx,         /* The index for which to generate a key */
-  int iCur,            /* Cursor number for the pIdx->pTable table */
+  int iDataCur,        /* Cursor number from which to take column data */
   int regOut,          /* Put the new key into this register if not 0 */
   int prefixOnly,      /* Compute only a unique prefix of the key */
   int *piPartIdxLabel  /* OUT: Jump to this label to skip partial index */
@@ -711,7 +719,7 @@ int sqlite3GenerateIndexKey(
   if( piPartIdxLabel ){
     if( pIdx->pPartIdxWhere ){
       *piPartIdxLabel = sqlite3VdbeMakeLabel(v);
-      pParse->iPartIdxTab = iCur;
+      pParse->iPartIdxTab = iDataCur;
       sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, *piPartIdxLabel, 
                          SQLITE_JUMPIFNULL);
     }else{
@@ -725,9 +733,9 @@ int sqlite3GenerateIndexKey(
     i16 idx = pIdx->aiColumn[j];
     if( pPk ) idx = sqlite3ColumnOfIndex(pPk, idx);
     if( idx<0 || idx==pTab->iPKey ){
-      sqlite3VdbeAddOp2(v, OP_Rowid, iCur, regBase+j);
+      sqlite3VdbeAddOp2(v, OP_Rowid, iDataCur, regBase+j);
     }else{
-      sqlite3VdbeAddOp3(v, OP_Column, iCur, idx, regBase+j);
+      sqlite3VdbeAddOp3(v, OP_Column, iDataCur, idx, regBase+j);
       sqlite3ColumnDefault(v, pTab, pIdx->aiColumn[j], -1);
     }
   }
index 752d40167989475ed39b9985c044af77db235de4..66f3f568705a6b5b8c89887303bba11d18b1bf54 100644 (file)
 #include "sqliteInt.h"
 
 /*
-** Generate code that will open table pTab for reading or writing
-** on cursor iCur.
+** Generate code that will 
 **
-** Always acquire a table lock.  Always do the open for rowid tables.
-** For WITHOUT ROWID tables, only do read opens, and then open the
-** PRIMARY KEY index, not the main table, since the main table doesn't
-** exist.
+**   (1) acquire a lock for table pTab then
+**   (2) open pTab as cursor iCur.
+**
+** If pTab is a WITHOUT ROWID table, then it is the PRIMARY KEY index
+** for that table that is actually opened.
 */
 void sqlite3OpenTable(
   Parse *p,       /* Generate code into this VDBE */
@@ -38,7 +38,7 @@ void sqlite3OpenTable(
   if( HasRowid(pTab) ){
     sqlite3VdbeAddOp4Int(v, opcode, iCur, pTab->tnum, iDb, pTab->nCol);
     VdbeComment((v, "%s", pTab->zName));
-  }else if( opcode==OP_OpenRead ){
+  }else{
     Index *pPk = sqlite3PrimaryKeyIndex(pTab);
     assert( pPk!=0 );
     assert( pPk->tnum=pTab->tnum );
@@ -553,7 +553,8 @@ void sqlite3Insert(
   Index *pIdx;          /* For looping over indices of the table */
   int nColumn;          /* Number of columns in the data */
   int nHidden = 0;      /* Number of hidden columns if TABLE is virtual */
-  int baseCur = 0;      /* VDBE Cursor number for pTab */
+  int iDataCur = 0;     /* VDBE cursor that is the main data repository */
+  int iIdxCur = 0;      /* First index cursor */
   int ipkColumn = -1;   /* Column that is the INTEGER PRIMARY KEY */
   int endOfLoop;        /* Label for the end of the insertion loop */
   int useTempTable = 0; /* Store SELECT results in intermediate table */
@@ -818,9 +819,8 @@ void sqlite3Insert(
   /* If this is not a view, open the table and and all indices */
   if( !isView ){
     int nIdx;
-
-    baseCur = pParse->nTab - withoutRowid;
-    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, baseCur, -1, OP_OpenWrite);
+    nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1,
+                                      &iDataCur, &iIdxCur);
     aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1));
     if( aRegIdx==0 ){
       goto insert_cleanup;
@@ -959,7 +959,7 @@ void sqlite3Insert(
         if( ALWAYS(pOp) && pOp->opcode==OP_Null && !IsVirtual(pTab) ){
           appendFlag = 1;
           pOp->opcode = OP_NewRowid;
-          pOp->p1 = baseCur;
+          pOp->p1 = iDataCur;
           pOp->p2 = regRowid;
           pOp->p3 = regAutoinc;
         }
@@ -971,7 +971,7 @@ void sqlite3Insert(
         int j1;
         if( !IsVirtual(pTab) ){
           j1 = sqlite3VdbeAddOp1(v, OP_NotNull, regRowid);
-          sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
+          sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
           sqlite3VdbeJumpHere(v, j1);
         }else{
           j1 = sqlite3VdbeCurrentAddr(v);
@@ -982,7 +982,7 @@ void sqlite3Insert(
     }else if( IsVirtual(pTab) || withoutRowid ){
       sqlite3VdbeAddOp2(v, OP_Null, 0, regRowid);
     }else{
-      sqlite3VdbeAddOp3(v, OP_NewRowid, baseCur, regRowid, regAutoinc);
+      sqlite3VdbeAddOp3(v, OP_NewRowid, iDataCur, regRowid, regAutoinc);
       appendFlag = 1;
     }
     autoIncStep(pParse, regAutoinc, regRowid);
@@ -1039,13 +1039,12 @@ void sqlite3Insert(
 #endif
     {
       int isReplace;    /* Set to true if constraints may cause a replace */
-      sqlite3GenerateConstraintChecks(pParse, pTab, baseCur, regIns, aRegIdx,
-          ipkColumn>=0, 0, onError, endOfLoop, &isReplace
+      sqlite3GenerateConstraintChecks(pParse, pTab, iDataCur, iIdxCur,
+          regIns, aRegIdx, ipkColumn>=0, 0, onError, endOfLoop, &isReplace
       );
       sqlite3FkCheck(pParse, pTab, 0, regIns, 0, 0);
-      sqlite3CompleteInsertion(
-          pParse, pTab, baseCur, regIns, aRegIdx, 0, appendFlag, isReplace==0
-      );
+      sqlite3CompleteInsertion(pParse, pTab, iDataCur, iIdxCur,
+                               regIns, aRegIdx, 0, appendFlag, isReplace==0);
     }
   }
 
@@ -1076,9 +1075,9 @@ void sqlite3Insert(
 
   if( !IsVirtual(pTab) && !isView ){
     /* Close all tables opened */
-    if( !withoutRowid ) sqlite3VdbeAddOp1(v, OP_Close, baseCur);
-    for(idx=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
-      sqlite3VdbeAddOp1(v, OP_Close, idx+baseCur);
+    if( iDataCur<iIdxCur ) sqlite3VdbeAddOp1(v, OP_Close, iDataCur);
+    for(idx=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, idx++){
+      sqlite3VdbeAddOp1(v, OP_Close, idx+iIdxCur);
     }
   }
 
@@ -1123,42 +1122,6 @@ insert_cleanup:
  #undef tmask
 #endif
 
-/*
-** If regFirst is a set of value for a table row in table order and pPk
-** is the PRIMARY KEY index for that table, then return the index of the
-** first register in a contiguous array of registers that are the primary
-** key values for the table row.
-**
-** For the common cases where the PRIMARY KEY has only a single value or
-** where a multi-value PRIMARY KEY is contiguous in table order, this
-** routine simply returns a pointer into the regFirst array.  But if there
-** is a multi-value PRIMARY KEY with the values out-of-order, this routine
-** has to generate code that will copy PRIMARY KEY values into newly
-** allocated contiguous registers.
-*/
-static int sqlite3PrimaryKeyRegisters(Parse *pParse, Index *pPk, int regFirst){
-  int i;
-  int nKeyCol = pPk->nKeyCol;
-  int regPk;
-  assert( pParse->pVdbe!=0 );
-  if( nKeyCol==1 ){
-    return regFirst + pPk->aiColumn[0];
-  }
-  for(i=1; i<nKeyCol; i++){
-    if( pPk->aiColumn[i-1]+1!=pPk->aiColumn[i] ) break;
-  }
-  if( i==nKeyCol ){
-    return regFirst + pPk->aiColumn[0];
-  }
-  regPk = pParse->nMem+1;
-  pParse->nMem += nKeyCol;
-  for(i=0; i<nKeyCol; i++){
-    int x = pPk->aiColumn[i];
-    sqlite3VdbeAddOp2(pParse->pVdbe, OP_SCopy, regFirst+x, regPk+i);
-  }
-  return regPk;
-}
-
 /*
 ** Locate the "principle btree" for a table.  This is the table itself for
 ** ordinary tables, but for WITHOUT ROWID tables, the principle btree is the
@@ -1274,7 +1237,8 @@ void sqlite3PrincipleBtree(
 void sqlite3GenerateConstraintChecks(
   Parse *pParse,      /* The parser context */
   Table *pTab,        /* the table into which we are inserting */
-  int baseCur,        /* A read/write cursor pointing at pTab */
+  int iDataCur,       /* Cursor of the canonical data tree */
+  int iIdxCur,        /* First index cursor */
   int regRowid,       /* First register in a range holding values to insert */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
   int pkChng,         /* Non-zero if the rowid or PRIMARY KEY changed */
@@ -1288,15 +1252,13 @@ void sqlite3GenerateConstraintChecks(
   int nCol;           /* Number of columns */
   int onError;        /* Conflict resolution strategy */
   int j1;             /* Addresss of jump instruction */
+  int ix;             /* Index loop counter */
   int regData;        /* Register containing first data column */
-  int iCur;           /* Table cursor number */
   Index *pIdx;         /* Pointer to one of the indices */
   Index *pPk = 0;      /* The PRIMARY KEY index */
   sqlite3 *db;         /* Database connection */
   int seenReplace = 0; /* True if REPLACE is used to resolve INT PK conflict */
   int regOldPk;        /* Previous rowid or PRIMARY KEY value */
-  int regNewPk = 0;    /* New PRIMARY KEY value */
-  int pkCur = 0;       /* Cursor used by the PRIMARY KEY */
   int nPkField;        /* Number of fields in PRIMARY KEY. 1 for ROWID tables */
 
   regOldPk = (pkChng && isUpdate) ? pkChng : regRowid;
@@ -1309,12 +1271,17 @@ void sqlite3GenerateConstraintChecks(
 
   /* For WITHOUT ROWID tables, we'll need to know the Index and the cursor
   ** number for the PRIMARY KEY index */
-  sqlite3PrincipleBtree(pTab, baseCur, &pPk, &pkCur);
-  nPkField = pPk ? pPk->nKeyCol : 1;
+  if( HasRowid(pTab) ){
+    pPk = 0;
+    nPkField = 1;
+  }else{
+    pPk = sqlite3PrimaryKeyIndex(pTab);
+    nPkField = pPk->nKeyCol;
+  }
 
   /* Record that this module has started */
   VdbeModuleComment((v, "BEGIN: GenCnstCks(%d,%d,%d,%d,%d)",
-                     baseCur, regRowid, pkChng, regOldPk, pkCur));
+                     iDataCur, iIdxCur, regRowid, pkChng, regOldPk));
 
   /* Test all NOT NULL constraints.
   */
@@ -1409,7 +1376,7 @@ void sqlite3GenerateConstraintChecks(
     if( isUpdate ){
       sqlite3VdbeAddOp3(v, OP_Eq, regRowid, addrRowidOk, pkChng);
     }
-    sqlite3VdbeAddOp3(v, OP_NotExists, baseCur, addrRowidOk, regRowid);
+    sqlite3VdbeAddOp3(v, OP_NotExists, iDataCur, addrRowidOk, regRowid);
     switch( onError ){
       default: {
         onError = OE_Abort;
@@ -1451,12 +1418,11 @@ void sqlite3GenerateConstraintChecks(
         }
         if( pTrigger || sqlite3FkRequired(pParse, pTab, 0, 0) ){
           sqlite3MultiWrite(pParse);
-          sqlite3GenerateRowDelete(
-              pParse, pTab, pTrigger, baseCur, regRowid, 0, 0, OE_Replace
-          );
+          sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
+                                   regRowid, 1, 0, OE_Replace);
         }else if( pTab->pIndex ){
           sqlite3MultiWrite(pParse);
-          sqlite3GenerateRowIndexDelete(pParse, pTab, baseCur, 0);
+          sqlite3GenerateRowIndexDelete(pParse, pTab, iDataCur, iIdxCur, 0);
         }
         seenReplace = 1;
         break;
@@ -1474,16 +1440,16 @@ void sqlite3GenerateConstraintChecks(
   ** index and making sure that duplicate entries do not already exist.
   ** Compute the revised record entries for indices as we go.
   */
-  for(iCur=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, iCur++){
+  for(ix=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, ix++){
     int regIdx;
     int regR;
-    int idxCur = baseCur+iCur+1;
+    int iThisCur = iIdxCur+ix;
     int addrUniqueOk = sqlite3VdbeMakeLabel(v);
 
-    if( aRegIdx[iCur]==0 ) continue;  /* Skip indices that do not change */
+    if( aRegIdx[ix]==0 ) continue;  /* Skip indices that do not change */
 
     if( pIdx->pPartIdxWhere ){
-      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[iCur]);
+      sqlite3VdbeAddOp2(v, OP_Null, 0, aRegIdx[ix]);
       pParse->ckBase = regData;
       sqlite3ExprIfFalse(pParse, pIdx->pPartIdxWhere, addrUniqueOk,
                          SQLITE_JUMPIFNULL);
@@ -1493,21 +1459,22 @@ void sqlite3GenerateConstraintChecks(
     /* Create a key for accessing the index entry */
     regIdx = sqlite3GetTempRange(pParse, pIdx->nColumn);
     for(i=0; i<pIdx->nColumn; i++){
-      i16 idx = pIdx->aiColumn[i];
-      if( idx<0 || idx==pTab->iPKey ){
+      i16 iField = pIdx->aiColumn[i];
+      if( iField<0 || iField==pTab->iPKey ){
         sqlite3VdbeAddOp2(v, OP_SCopy, regRowid, regIdx+i);
       }else{
-        sqlite3VdbeAddOp2(v, OP_SCopy, regData+idx, regIdx+i);
+        sqlite3VdbeAddOp2(v, OP_SCopy, regData+iField, regIdx+i);
       }
     }
-    sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[iCur]);
+    sqlite3VdbeAddOp3(v, OP_MakeRecord, regIdx, pIdx->nColumn, aRegIdx[ix]);
     sqlite3VdbeChangeP4(v, -1, sqlite3IndexAffinityStr(v, pIdx), P4_TRANSIENT);
+    VdbeComment((v, "for %s", pIdx->zName));
     sqlite3ExprCacheAffinityChange(pParse, regIdx, pIdx->nColumn);
 
     /* Find out what action to take in case there is an indexing conflict */
     onError = pIdx->onError;
     if( onError==OE_None ){ 
-      sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nKeyCol+1);
+      sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
       sqlite3VdbeResolveLabel(v, addrUniqueOk);
       continue;  /* pIdx is not a UNIQUE index */
     }
@@ -1523,46 +1490,48 @@ void sqlite3GenerateConstraintChecks(
     
     /* Check to see if the new index entry will be unique */
     regR = sqlite3GetTempRange(pParse, nPkField);
-    sqlite3VdbeAddOp4Int(v, OP_NoConflict, idxCur, addrUniqueOk,
+    sqlite3VdbeAddOp4Int(v, OP_NoConflict, iThisCur, addrUniqueOk,
                          regIdx, pIdx->nKeyCol);
-#if 0
-    if( !isUpdate ){
-      /* A pre-existing row is always a conflict on an insert */
-    }else
-#endif
     if( HasRowid(pTab) ){
       /* Conflict only if the rowid of the existing index entry
       ** is different from old-rowid */
-      sqlite3VdbeAddOp2(v, OP_IdxRowid, idxCur, regR);
+      sqlite3VdbeAddOp2(v, OP_IdxRowid, iThisCur, regR);
       sqlite3VdbeAddOp3(v, OP_Eq, regR, addrUniqueOk, regOldPk);
-    }else if( pIdx->autoIndex==2 ){
-      /* For PRIMARY KEY index on a WITHOUT ROWID table, conflict only
-      ** if the PRIMARY KEY has changed.  If the PRIMARY KEY is unchanged,
-      ** then the matching entry is just the original row that is being
-      ** modified. */
-      if( onError!=OE_Replace ){
-        int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
+    }else{
+      /* Extract the PRIMARY KEY from the end of the index entry and
+      ** store it in register regR..regR+nPk-1 */
+      for(i=0; i<pPk->nKeyCol; i++){
+        int x = sqlite3ColumnOfIndex(pIdx, pPk->aiColumn[i]);
+        sqlite3VdbeAddOp3(v, OP_Column, iThisCur, x, regR+i);
+        VdbeComment((v, "%s.%s", pTab->zName,
+                     pTab->aCol[pPk->aiColumn[i]].zName));
+      }
+      if( pIdx->autoIndex==2 ){
+        /* For a PRIMARY KEY index on a WITHOUT ROWID table, always conflict
+        ** on an INSERT.  On an UPDATE, only conflict if the PRIMARY KEY
+        ** has changed. */
+        if( isUpdate ){
+          int addrPkConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
+          for(i=0; i<pPk->nKeyCol-1; i++){
+            sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
+                              addrPkConflict, regIdx+i);
+          }
+          sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
+                            addrUniqueOk, regIdx+i);
+        }
+      }else{
+        /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
+        ** PRIMARY KEY value of the match is different from the old PRIMARY KEY
+        ** value from before the update. */
+        int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol;
+        assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
         for(i=0; i<pPk->nKeyCol-1; i++){
-          sqlite3VdbeAddOp3(v, OP_Ne, regOldPk+pPk->aiColumn[i]+1,
-                            addrPkConflict, regIdx+i);
+          sqlite3VdbeAddOp3(v, OP_Ne,
+                            regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
         }
-        sqlite3VdbeAddOp3(v, OP_Eq, regOldPk+pPk->aiColumn[i]+1,
-                          addrUniqueOk, regIdx+i);
-      }
-    }else{
-      /* For a UNIQUE index on a WITHOUT ROWID table, conflict only if the
-      ** PRIMARY KEY value of the match is different from the old PRIMARY KEY
-      ** value from before the update. */
-      int addrConflict = sqlite3VdbeCurrentAddr(v)+pPk->nKeyCol*2;
-      assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn );
-      for(i=0; i<pPk->nKeyCol-1; i++){
-        sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
-        sqlite3VdbeAddOp3(v, OP_Ne,
-                          regOldPk+pPk->aiColumn[i], addrConflict, regR+i);
+        sqlite3VdbeAddOp3(v, OP_Eq,
+                          regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
       }
-      sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i);
-      sqlite3VdbeAddOp3(v, OP_Eq,
-                        regOldPk+pPk->aiColumn[i], addrUniqueOk, regR+i);
     }
     sqlite3ReleaseTempRange(pParse, regIdx, pIdx->nColumn);
 
@@ -1607,19 +1576,14 @@ void sqlite3GenerateConstraintChecks(
         if( db->flags&SQLITE_RecTriggers ){
           pTrigger = sqlite3TriggersExist(pParse, pTab, TK_DELETE, 0, 0);
         }
-        if( pIdx==pPk ){
-          /*sqlite3VdbeAddOp3(v, OP_IdxDelete, pkCur, regIdx, pIdx->nColumn);*/
-          sqlite3VdbeAddOp1(v, OP_Delete, pkCur);
-        }else{
-          sqlite3GenerateRowDelete(pParse, pTab, pTrigger, baseCur, 
-                                   regR, nPkField, 0, OE_Replace);
-        }
+        sqlite3GenerateRowDelete(pParse, pTab, pTrigger, iDataCur, iIdxCur,
+                                 regR, nPkField, 0, OE_Replace);
         seenReplace = 1;
         break;
       }
     }
     sqlite3VdbeResolveLabel(v, addrUniqueOk);
-    sqlite3ReleaseTempReg(pParse, regR);
+    sqlite3ReleaseTempRange(pParse, regR, nPkField);
   }
   
   if( pbMayReplace ){
@@ -1640,7 +1604,8 @@ void sqlite3GenerateConstraintChecks(
 void sqlite3CompleteInsertion(
   Parse *pParse,      /* The parser context */
   Table *pTab,        /* the table into which we are inserting */
-  int baseCur,        /* Index of a read/write cursor pointing at pTab */
+  int iDataCur,       /* Cursor of the canonical data source */
+  int iIdxCur,        /* First index cursor */
   int regRowid,       /* Range of content */
   int *aRegIdx,       /* Register used by each index.  0 for unused indices */
   int isUpdate,       /* True for UPDATE, False for INSERT */
@@ -1662,7 +1627,7 @@ void sqlite3CompleteInsertion(
     if( pIdx->pPartIdxWhere ){
       sqlite3VdbeAddOp2(v, OP_IsNull, aRegIdx[i], sqlite3VdbeCurrentAddr(v)+2);
     }
-    sqlite3VdbeAddOp2(v, OP_IdxInsert, baseCur+i+1, aRegIdx[i]);
+    sqlite3VdbeAddOp2(v, OP_IdxInsert, iIdxCur+i, aRegIdx[i]);
     if( useSeekResult ){
       sqlite3VdbeChangeP5(v, OPFLAG_USESEEKRESULT);
     }
@@ -1685,7 +1650,7 @@ void sqlite3CompleteInsertion(
   if( useSeekResult ){
     pik_flags |= OPFLAG_USESEEKRESULT;
   }
-  sqlite3VdbeAddOp3(v, OP_Insert, baseCur, regRec, regRowid);
+  sqlite3VdbeAddOp3(v, OP_Insert, iDataCur, regRec, regRowid);
   if( !pParse->nested ){
     sqlite3VdbeChangeP4(v, -1, pTab->zName, P4_TRANSIENT);
   }
@@ -1693,43 +1658,64 @@ void sqlite3CompleteInsertion(
 }
 
 /*
-** Generate code that will open cursors for a table and for all
-** indices of that table.  The "baseCur" parameter is the cursor number used
-** for the table.  Indices are opened on subsequent cursors.
-**
-** Return the number of indices on the table.
+** Allocate cursors for the pTab table and all its indices and generate
+** code to open and initialized those cursors.
+**
+** The cursor for the object that contains the complete data (normally
+** the table itself, but the PRIMARY KEY index in the case of a WITHOUT
+** ROWID table) is returned in *piDataCur.  The first index cursor is
+** returned in *piIdxCur.  The number of indices is returned.
+**
+** Use iBase as the first cursor (either the *piDataCur for rowid tables
+** or the first index for WITHOUT ROWID tables) if it is non-negative.
+** If iBase is negative, then allocate the next available cursor.
+**
+** For a rowid table, *piDataCur will be exactly one less than *piIdxCur.
+** For a WITHOUT ROWID table, *piDataCur will be somewhere in the range
+** of *piIdxCurs, depending on where the PRIMARY KEY index appears on the
+** pTab->pIndex list.
 */
 int sqlite3OpenTableAndIndices(
   Parse *pParse,   /* Parsing context */
   Table *pTab,     /* Table to be opened */
-  int baseCur,     /* Cursor number assigned to the table */
-  int pkCur,       /* Cursor number for the primary key */
-  int op           /* OP_OpenRead or OP_OpenWrite */
+  int op,          /* OP_OpenRead or OP_OpenWrite */
+  int iBase,       /* Use this for the table cursor, if there is one */
+  int *piDataCur,  /* Write the database source cursor number here */
+  int *piIdxCur    /* Write the first index cursor number here */
 ){
   int i;
   int iDb;
   Index *pIdx;
   Vdbe *v;
 
-  if( IsVirtual(pTab) ) return 0;
+  assert( op==OP_OpenRead || op==OP_OpenWrite );
+  if( IsVirtual(pTab) ){
+    *piDataCur = 0;
+    *piIdxCur = 1;
+    return 0;
+  }
   iDb = sqlite3SchemaToIndex(pParse->db, pTab->pSchema);
   v = sqlite3GetVdbe(pParse);
   assert( v!=0 );
-  if( pkCur<0 ){
-    sqlite3OpenTable(pParse, baseCur, iDb, pTab, op);
+  if( iBase<0 ) iBase = pParse->nTab;
+  if( HasRowid(pTab) ){
+    *piDataCur = iBase++;
+    sqlite3OpenTable(pParse, *piDataCur, iDb, pTab, op);
   }else{
-    sqlite3TableLock(pParse, iDb, pTab->tnum, 0, pTab->zName);
+    sqlite3TableLock(pParse, iDb, pTab->tnum, op==OP_OpenWrite, pTab->zName);
   }
-  for(i=1, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
+  *piIdxCur = iBase;
+  for(i=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, i++){
     KeyInfo *pKey = sqlite3IndexKeyinfo(pParse, pIdx);
-    int iCur = (pkCur>=0 && pIdx->autoIndex==2) ? pkCur : i+baseCur;
+    int iIdxCur = iBase++;
     assert( pIdx->pSchema==pTab->pSchema );
-    sqlite3VdbeAddOp4(v, op, iCur, pIdx->tnum, iDb,
+    if( pIdx->autoIndex==2 && !HasRowid(pTab) ) *piDataCur = iIdxCur;
+    sqlite3VdbeAddOp4(v, op, iIdxCur, pIdx->tnum, iDb,
                       (char*)pKey, P4_KEYINFO_HANDOFF);
     VdbeComment((v, "%s", pIdx->zName));
   }
-  if( pParse->nTab<=i+baseCur ) pParse->nTab = i+baseCur;
-  return i-1;
+  if( iBase>pParse->nTab ) pParse->nTab = iBase;
+  return i;
 }
 
 
index 02fbc0335351f74e27e9402552bec13d019d062e..5516c6dee1f8f9f1d77b73d7c0e09d529aaa3903 100644 (file)
@@ -1877,30 +1877,31 @@ void sqlite3Pragma(
         Table *pTab = sqliteHashData(x);
         Index *pIdx, *pPk;
         int loopTop;
-        int pkCur;
+        int iDataCur, iIdxCur;
 
         if( pTab->pIndex==0 ) continue;
-        sqlite3PrincipleBtree(pTab, 1, &pPk, &pkCur);
-        pkCur = (pPk==0) ? -1 : 1;
+        pPk = HasRowid(pTab) ? 0 : sqlite3PrimaryKeyIndex(pTab);
         addr = sqlite3VdbeAddOp1(v, OP_IfPos, 1);  /* Stop if out of errors */
         sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
         sqlite3VdbeJumpHere(v, addr);
         sqlite3ExprCacheClear(pParse);
-        sqlite3OpenTableAndIndices(pParse, pTab, 1, pkCur, OP_OpenRead);
+        sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead,
+                                   1, &iDataCur, &iIdxCur);
         sqlite3VdbeAddOp2(v, OP_Integer, 0, 7);
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           sqlite3VdbeAddOp2(v, OP_Integer, 0, 8+j); /* index entries counter */
         }
         pParse->nMem = MAX(pParse->nMem, 8+j);
-        sqlite3VdbeAddOp2(v, OP_Rewind, 1, 0);
+        sqlite3VdbeAddOp2(v, OP_Rewind, iDataCur, 0);
         loopTop = sqlite3VdbeAddOp2(v, OP_AddImm, 7, 1);
         for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){
           int jmp2, jmp3, jmp4;
           int r1;
           if( pPk==pIdx ) continue;
-          r1 = sqlite3GenerateIndexKey(pParse, pIdx, 1, 0, 0, &jmp3);
+          r1 = sqlite3GenerateIndexKey(pParse, pIdx, iDataCur, 0, 0, &jmp3);
           sqlite3VdbeAddOp2(v, OP_AddImm, 8+j, 1);  /* increment entry count */
-          jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, j+2, 0, r1, pIdx->nKeyCol+1);
+          jmp2 = sqlite3VdbeAddOp4Int(v, OP_Found, iIdxCur+j, 0, r1,
+                                      pIdx->nKeyCol+1);
           sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1); /* Decrement error limit */
           sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, "row ", P4_STATIC);
           sqlite3VdbeAddOp3(v, OP_Concat, 7, 3, 3);
@@ -1926,7 +1927,7 @@ void sqlite3Pragma(
           addr = sqlite3VdbeCurrentAddr(v);
           sqlite3VdbeAddOp2(v, OP_IfPos, 1, addr+2);
           sqlite3VdbeAddOp2(v, OP_Halt, 0, 0);
-          sqlite3VdbeAddOp2(v, OP_Count, j+2, 3);
+          sqlite3VdbeAddOp2(v, OP_Count, iIdxCur+j, 3);
           sqlite3VdbeAddOp3(v, OP_Eq, 8+j, addr+8, 3);
           sqlite3VdbeAddOp2(v, OP_AddImm, 1, -1);
           sqlite3VdbeAddOp4(v, OP_String8, 0, 3, 0, pIdx->zName, P4_TRANSIENT);
index d730bf9b7c3a93304024f7f9ed1795430285ae88..e4c68a0de9119fae8f1ad5c0841911ec62181119 100644 (file)
@@ -2919,14 +2919,14 @@ int sqlite3ExprCanBeNull(const Expr*);
 void sqlite3ExprCodeIsNullJump(Vdbe*, const Expr*, int, int);
 int sqlite3ExprNeedsNoAffinityChange(const Expr*, char);
 int sqlite3IsRowid(const char*);
-void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,i16,u8,u8);
-void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int*);
+void sqlite3GenerateRowDelete(Parse*,Table*,Trigger*,int,int,int,i16,u8,u8);
+void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*);
 int sqlite3GenerateIndexKey(Parse*, Index*, int, int, int, int*);
 void sqlite3PrincipleBtree(Table*,int,Index**,int*);
-void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,
+void sqlite3GenerateConstraintChecks(Parse*,Table*,int,int,int,
                                      int*,int,int,int,int,int*);
-void sqlite3CompleteInsertion(Parse*, Table*, int, int, int*, int, int, int);
-int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int);
+void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int);
+int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, int*, int*);
 void sqlite3BeginWriteOperation(Parse*, int, int);
 void sqlite3MultiWrite(Parse*);
 void sqlite3MayAbort(Parse*);
index 9863456496db8c0e9646c4181b8545f4fcf8059c..db300bd2af7ecbbb14667271efdc57ab5787467a 100644 (file)
@@ -109,7 +109,6 @@ void sqlite3Update(
                          ** an expression for the i-th column of the table.
                          ** aXRef[i]==-1 if the i-th column is not changed. */
   int chngRowid;         /* True if the record number is being changed */
-  int chngPk;            /* The PRIMARY KEY of a WITHOUT ROWID table changed */
   Expr *pRowidExpr = 0;  /* Expression defining the new record number */
   int openAll = 0;       /* True if all indices need to be opened */
   AuthContext sContext;  /* The authorization context */
@@ -202,7 +201,7 @@ void sqlite3Update(
   ** column to be updated, make sure we have authorization to change
   ** that column.
   */
-  chngPk = chngRowid = 0;
+  chngRowid = 0;
   for(i=0; i<pChanges->nExpr; i++){
     if( sqlite3ResolveExprNames(&sNC, pChanges->a[i].pExpr) ){
       goto update_cleanup;
@@ -212,8 +211,6 @@ void sqlite3Update(
         if( j==pTab->iPKey ){
           chngRowid = 1;
           pRowidExpr = pChanges->a[i].pExpr;
-        }else if( pPk && (pTab->aCol[j].colFlags & COLFLAG_PRIMKEY)!=0 ){
-          chngPk = 1;
         }
         aXRef[j] = i;
         break;
@@ -526,7 +523,7 @@ void sqlite3Update(
     int j1;                       /* Address of jump instruction */
 
     /* Do constraint checks. */
-    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, regNewRowid,
+    sqlite3GenerateConstraintChecks(pParse, pTab, iCur, iCur+1, regNewRowid,
         aRegIdx, (chngRowid?regOldRowid:0), 1, onError, addr, 0);
 
     /* Do FK constraint checks. */
@@ -536,10 +533,10 @@ void sqlite3Update(
 
     /* Delete the index entries associated with the current record.  */
     if( pPk ){
-      /*j1 = sqlite3VdbeAddOp3(v, OP_NotFound, pkCur, */
+      j1 = sqlite3VdbeAddOp4Int(v, OP_NotFound, pkCur, 0, regOldRowid, 1);
     }else{
       j1 = sqlite3VdbeAddOp3(v, OP_NotExists, iCur, 0, regOldRowid);
-      sqlite3GenerateRowIndexDelete(pParse, pTab, iCur, aRegIdx);
+      sqlite3GenerateRowIndexDelete(pParse, pTab, pkCur, iCur+1, aRegIdx);
     }
   
     /* If changing the record number, delete the old record.  */
@@ -553,7 +550,8 @@ void sqlite3Update(
     }
   
     /* Insert the new index entries and the new record. */
-    sqlite3CompleteInsertion(pParse, pTab, iCur, regNewRowid, aRegIdx, 1, 0, 0);
+    sqlite3CompleteInsertion(pParse, pTab, iCur, iCur+1,
+                             regNewRowid, aRegIdx, 1, 0, 0);
 
     /* Do any ON CASCADE, SET NULL or SET DEFAULT operations required to
     ** handle rows (possibly in other tables) that refer via a foreign key
index 2423754072e483c2d40d9fb4485b0fdb81fa3dba..403b27e25f6ef01302e92941efa70629cd7e7198 100644 (file)
@@ -1119,7 +1119,7 @@ case OP_Copy: {
 ** during the lifetime of the copy.  Use OP_Copy to make a complete
 ** copy.
 */
-case OP_SCopy: {            /* in1, out2 */
+case OP_SCopy: {            /* out2 */
   pIn1 = &aMem[pOp->p1];
   pOut = &aMem[pOp->p2];
   assert( pOut!=pIn1 );
@@ -1127,7 +1127,6 @@ case OP_SCopy: {            /* in1, out2 */
 #ifdef SQLITE_DEBUG
   if( pOut->pScopyFrom==0 ) pOut->pScopyFrom = pIn1;
 #endif
-  REGISTER_TRACE(pOp->p2, pOut);
   break;
 }
 
index 91288c886706bb8f63715812acc14c55c2ffdb92..e2ef4eee1b49456d1b4b00597a21a221ab027d29 100644 (file)
@@ -1133,7 +1133,7 @@ void sqlite3VdbePrintOp(FILE *pOut, int pc, Op *pOp){
   char *zP4;
   char zPtr[50];
   char zCom[100];
-  static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-4s %.2X %s\n";
+  static const char *zFormat1 = "%4d %-13s %4d %4d %4d %-13s %.2X %s\n";
   if( pOut==0 ) pOut = stdout;
   zP4 = displayP4(pOp, zPtr, sizeof(zPtr));
 #ifdef SQLITE_ENABLE_EXPLAIN_COMMENTS
index 4c8665a84886c62ec56a8a14567a8854ee5509cb..9bb2ecb0cb1453641e3cf80e423756ac7d7a6724 100644 (file)
@@ -46,7 +46,6 @@ do_execsql_test without_rowid1-1.12 {
   SELECT *, '|' FROM t1 ORDER BY +b, d;
 } {dynamic juliet flipper command | journal sherman ammonia helena | journal sherman gamma patriot | arctic sleep ammonia helena |}
 
-if 0 {
 # Trying to insert a duplicate PRIMARY KEY fails.
 #
 do_test without_rowid1-1.21 {
@@ -61,6 +60,5 @@ do_execsql_test without_rowid1-1.22 {
   REPLACE INTO t1 VALUES('dynamic','phone','flipper','harvard');
   SELECT *, '|' FROM t1 ORDER BY c, a;
 } {}
-}
 
 finish_test