diff --git a/manifest b/manifest index 966cce8d77..5e03b35ba4 100644 --- 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 diff --git a/manifest.uuid b/manifest.uuid index 5b6052dd47..cf92754a40 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0d4fea7462c0f61cd1c736cbcd7bea5ec2034d54 \ No newline at end of file +1adfca6019847d37dee4a297669f29d5ca184066 \ No newline at end of file diff --git a/src/delete.c b/src/delete.c index b7601f8af4..fc0d4813dd 100644 --- a/src/delete.c +++ b/src/delete.c @@ -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; iaiColumn[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; iColnCol; iCol++){ if( mask==0xffffffff || mask&(1<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); } } diff --git a/src/insert.c b/src/insert.c index 752d401679..66f3f56870 100644 --- a/src/insert.c +++ b/src/insert.c @@ -15,13 +15,13 @@ #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( iDataCurpIndex; 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; iaiColumn[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; iaiColumn[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; inColumn; 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; - for(i=0; inKeyCol-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*2; - assert( pIdx->nKeyCol + pPk->nKeyCol == pIdx->nColumn ); - for(i=0; inKeyCol-1; i++){ - sqlite3VdbeAddOp3(v, OP_Column, idxCur, pIdx->nKeyCol+i, regR+i); - sqlite3VdbeAddOp3(v, OP_Ne, - regOldPk+pPk->aiColumn[i], addrConflict, regR+i); + /* Extract the PRIMARY KEY from the end of the index entry and + ** store it in register regR..regR+nPk-1 */ + for(i=0; inKeyCol; 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; inKeyCol-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; inKeyCol-1; 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. +** Allocate cursors for the pTab table and all its indices and generate +** code to open and initialized those cursors. ** -** Return the number of indices on the table. +** 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; } diff --git a/src/pragma.c b/src/pragma.c index 02fbc03353..5516c6dee1 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -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); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index d730bf9b7c..e4c68a0de9 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -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*); diff --git a/src/update.c b/src/update.c index 9863456496..db300bd2af 100644 --- a/src/update.c +++ b/src/update.c @@ -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; inExpr; 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 diff --git a/src/vdbe.c b/src/vdbe.c index 2423754072..403b27e25f 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 91288c8867..e2ef4eee1b 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -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 diff --git a/test/without_rowid1.test b/test/without_rowid1.test index 4c8665a848..9bb2ecb0cb 100644 --- a/test/without_rowid1.test +++ b/test/without_rowid1.test @@ -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