diff --git a/manifest b/manifest index a66f2b7f81..289ffeb941 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Merge\sin\sall\strunk\schanges\sprior\sto\sthe\sBTREE_FORDELETE\senhancement. -D 2015-10-26T18:51:09.614 +C Merge\sthe\sBTREE_FORDELETE\senhancement\swith\sthis\sbranch. +D 2015-10-26T20:11:24.886 F Makefile.in 2ea961bc09e441874eb3d1bf7398e04feb24f3ee F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 702d3e98f3afc6587a78481257f3c4c900efc3a4 @@ -280,8 +280,8 @@ F src/auth.c b56c78ebe40a2110fd361379f7e8162d23f92240 F src/backup.c c3a9c4209439b806c44cf30daf466955727bf46c F src/bitvec.c d1f21d7d91690747881f03940584f4cc548c9d3d F src/btmutex.c 45a968cc85afed9b5e6cf55bf1f42f8d18107f79 -F src/btree.c 6e7cafdb9f245e0670c3478136a3c0c39ff5cf7b -F src/btree.h 9cc758f0f1e0002049d9eb0232f9783f21f25ac5 +F src/btree.c 8022201b3008c9ff151cf56cf2c36a0db93689fd +F src/btree.h 1957827f808875473750026cf60ca0c2b3676c98 F src/btreeInt.h 8177c9ab90d772d6d2c6c517e05bed774b7c92c0 F src/build.c d6162335d690396dfc5c4bd59e8b2b0c14ba6285 F src/callback.c 7b44ce59674338ad48b0e84e7b72f935ea4f68b0 @@ -289,7 +289,7 @@ F src/complete.c addcd8160b081131005d5bc2d34adf20c1c5c92f F src/ctime.c 509ef9c64d1321f42448f111da86400b1799218a F src/date.c fb1c99172017dcc8e237339132c91a21a0788584 F src/dbstat.c e637e7a7ff40ef32132a418c6fdf1cfb63aa27c7 -F src/delete.c 35c939eb8bacc9dd8a6715964e5f69feb8c20e44 +F src/delete.c c4c6fb9da78b946fcba2a6aac5b24bc5c15e752a F src/expr.c ea3e0c2981ffc7bd358714fa6d5132cb2cd5fc3a F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb F src/fkey.c 31900763094a3736a5fc887469202eb579fef2d0 @@ -298,7 +298,7 @@ F src/global.c 508e4087f7b41d688e4762dcf4d4fe28cfbc87f9 F src/hash.c 4263fbc955f26c2e8cdc0cf214bc42435aa4e4f5 F src/hash.h c8f3c31722cf3277d03713909761e152a5b81094 F src/hwtime.h d32741c8f4df852c7d959236615444e2b1063b08 -F src/insert.c 6dadbb671c2cc035ddbbf11a0b0209185d5bfe2c +F src/insert.c 419a947f27ce2da18eebf440a5aa80cc825defae F src/journal.c b4124532212b6952f42eb2c12fa3c25701d8ba8d F src/legacy.c ba1863ea58c4c840335a84ec276fc2b25e22bc4e F src/lempar.c d344a95d60c24e2f490ee59db9784b1b17439012 @@ -331,7 +331,7 @@ F src/parse.y f599aa5e871a493330d567ced93de696f61f48f7 F src/pcache.c 24be750c79272e0ca7b6e007bc94999700f3e5ef F src/pcache.h 9968603796240cdf83da7e7bef76edf90619cea9 F src/pcache1.c 902e1bc7bdaa81b40f8543407c5e2ac8ef4dc035 -F src/pragma.c dcfe3a35d2de935feeaba1455528b4a5c4f1208c +F src/pragma.c 8fd4c8a12e25f0d916426f160255ebe25415eba7 F src/pragma.h 631a91c8b0e6ca8f051a1d8a4a0da4150e04620a F src/prepare.c 82e5db1013846a819f198336fed72c44c974e7b1 F src/printf.c 0c4bcdd1c2e2521024f0a69cb5eb334f86b3652a @@ -343,14 +343,14 @@ F src/shell.c d25df04168d6ba5a4fa05bdbf859df667f9eb621 F src/sqlite.h.in 839c818e16ea68703d90d17bd2bb3607191debce F src/sqlite3.rc 992c9f5fb8285ae285d6be28240a7e8d3a7f2bad F src/sqlite3ext.h 4b66e3e3435da4b4c8c83696d0349f0c503b3924 -F src/sqliteInt.h af76837cad8fb696e6527ec2745f175de7cb9093 +F src/sqliteInt.h b1e72ffe282c91ae30a2bf403319126dbaebd556 F src/sqliteLimit.h 216557999cb45f2e3578ed53ebefe228d779cb46 F src/status.c 70912d7be68e9e2dbc4010c93d344af61d4c59ba F src/table.c 51b46b2a62d1b3a959633d593b89bab5e2c9155e F src/tclsqlite.c d9439b6a910985b7fff43ba6756bcef00de22649 F src/test1.c 8fff9c5aa63d6490f516d018b70c12a9cb9a4d8a F src/test2.c 577961fe48961b2f2e5c8b56ee50c3f459d3359d -F src/test3.c 64d2afdd68feac1bb5e2ffb8226c8c639f798622 +F src/test3.c f7ae1d6a4aa07aac257de18a43800c1199b513fc F src/test4.c d168f83cc78d02e8d35567bb5630e40dcd85ac1e F src/test5.c 5a34feec76d9b3a86aab30fd4f6cc9c48cbab4c1 F src/test6.c 41cacf3b0dd180823919bf9e1fbab287c9266723 @@ -397,11 +397,11 @@ F src/threads.c bbfb74450643cb5372a43ad4f6cffd7e9dfcecb0 F src/tokenize.c 338bc8f7c9dd103188952cda7964696bacac6d22 F src/treeview.c 154f0acc622fa3514de8777dcedf4c8a8802b4ce F src/trigger.c 322f23aad694e8f31d384dcfa386d52a48d3c52f -F src/update.c aa10336a2719bd1b9f89004f3d7ba6d566623a49 +F src/update.c 40e51cd0883cb5bfd6abb7d8a7cd8aa47fab2945 F src/utf.c fc6b889ba0779b7722634cdeaa25f1930d93820c F src/util.c fc612367108b74573c5fd13a85d0a23027f438bd F src/vacuum.c 2ddd5cad2a7b9cef7f9e431b8c7771634c6b1701 -F src/vdbe.c 10d66354fec90acb5fc908ad36da404ef9796170 +F src/vdbe.c 1cdfa13e37dba217916112fffc639dee83406192 F src/vdbe.h efb7a8c1459e31f3ea4377824c6a7e4cb5068637 F src/vdbeInt.h 33403622c6a8feaaac5f0f3f17f5d1bf6df42286 F src/vdbeapi.c 020681b943e77766b32ae1cddf86d7831b7374ca @@ -415,7 +415,7 @@ F src/vxworks.h c18586c8edc1bddbc15c004fa16aeb1e1342b4fb F src/wal.c 18b0ed49830cf04fe2d68224b41838a73ac6cd24 F src/wal.h df01efe09c5cb8c8e391ff1715cca294f89668a4 F src/walker.c 2e14d17f592d176b6dc879c33fbdec4fbccaa2ba -F src/where.c 51cca249502ee71fb77b425687dac611277925b2 +F src/where.c 6aceb72cc58dc06922a9e1604d559c8ca4c3e728 F src/whereInt.h 7892bb54cf9ca0ae5c7e6094491b94c9286dc647 F src/wherecode.c 9aa2043685ec3eb73e87fa6f50aa4ec092f197dd F src/whereexpr.c e63244ca06c503e5f3c5b7f3c9aea0db826089ed @@ -629,6 +629,7 @@ F test/fkey6.test abb59f866c1b44926fd02d1fdd217d831fe04f48 F test/fkey7.test 72e915890ee4a005daaf3002cb208e8fe973ac13 F test/fkey8.test 8f08203458321e6c19a263829de4cfc936274ab0 F test/fkey_malloc.test 594a7ea1fbab553c036c70813cd8bd9407d63749 +F test/fordelete.test ba12ec1d27cc34a4c23db4446029126d773f3849 F test/format4.test 1f0cac8ff3895e9359ed87e41aaabee982a812eb F test/fts-9fd058691.test 78b887e30ae6816df0e1fed6259de4b5a64ad33c F test/fts1a.test 46090311f85da51bb33bd5ce84f7948359c6d8d7 @@ -1392,7 +1393,7 @@ F tool/vdbe_profile.tcl 246d0da094856d72d2c12efec03250d71639d19f F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh 48bd54594752d5be3337f12c72f28d2080cb630b F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f -P 26fa091d68e89a0b6af61ba706d23a9f37e8025a 138783b553602a055b3efdeac5947cf5ccd76b5d -R 4b723e99df9abf57da690efface1cef0 -U drh -Z 936e93924f01554045ee6552abb7ef82 +P 53d5a4add6b60722ad77daf98b6b8983b081e16a de6972515f65c5cf5da7cfdf876a05718299e9b8 +R eb548650b5c16f458e4886ea4649dc57 +U dan +Z 682420f21bcc754cb8ec9b887c5ab3d8 diff --git a/manifest.uuid b/manifest.uuid index 13182502f3..02251806a8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -53d5a4add6b60722ad77daf98b6b8983b081e16a \ No newline at end of file +20da0849ce910ceb445954dfc5f985acf9a02695 \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index 2ddcc8a7dd..1370bef2d0 100644 --- a/src/btree.c +++ b/src/btree.c @@ -4076,13 +4076,16 @@ static int btreeCursor( BtCursor *pX; /* Looping over other all cursors */ assert( sqlite3BtreeHoldsMutex(p) ); - assert( wrFlag==0 || wrFlag==1 ); + assert( wrFlag==0 + || wrFlag==BTREE_WRCSR + || wrFlag==(BTREE_WRCSR|BTREE_FORDELETE) + ); /* The following assert statements verify that if this is a sharable ** b-tree database, the connection is holding the required table locks, ** and that no other connection has any open cursor that conflicts with ** this lock. */ - assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, wrFlag+1) ); + assert( hasSharedCacheTableLock(p, iTable, pKeyInfo!=0, (wrFlag?2:1)) ); assert( wrFlag==0 || !hasReadConflicts(p, iTable) ); /* Assert that the caller has opened the required transaction. */ @@ -4107,8 +4110,7 @@ static int btreeCursor( pCur->pKeyInfo = pKeyInfo; pCur->pBtree = p; pCur->pBt = pBt; - assert( wrFlag==0 || wrFlag==BTCF_WriteFlag ); - pCur->curFlags = wrFlag; + pCur->curFlags = wrFlag ? BTCF_WriteFlag : 0; pCur->curPagerFlags = wrFlag ? 0 : PAGER_GET_READONLY; /* If there are two or more cursors on the same btree, then all such ** cursors *must* have the BTCF_Multiple flag set. */ diff --git a/src/btree.h b/src/btree.h index 910abe6b85..ba6cc5a948 100644 --- a/src/btree.h +++ b/src/btree.h @@ -201,6 +201,22 @@ int sqlite3BtreeNewDb(Btree *p); #define BTREE_BULKLOAD 0x00000001 /* Used to full index in sorted order */ #define BTREE_SEEK_EQ 0x00000002 /* EQ seeks only - no range seeks */ +/* +** Flags passed as the third argument to sqlite3BtreeCursor(). +** +** For read-only cursors the wrFlag argument is always zero. For read-write +** cursors it may be set to either (BTREE_WRCSR|BTREE_FORDELETE) or +** (BTREE_WRCSR). If the BTREE_FORDELETE flag is set, then the cursor will +** only be used by SQLite for the following: +** +** * to seek to and delete specific entries, and/or +** +** * to read values that will be used to create keys that other +** BTREE_FORDELETE cursors will seek to and delete. +*/ +#define BTREE_WRCSR 0x00000004 /* read-write cursor */ +#define BTREE_FORDELETE 0x00000008 /* Cursor is for seek/delete only */ + int sqlite3BtreeCursor( Btree*, /* BTree containing table to open */ int iTable, /* Index of root page */ diff --git a/src/delete.c b/src/delete.c index faef3a814e..cd683e37d8 100644 --- a/src/delete.c +++ b/src/delete.c @@ -478,12 +478,13 @@ void sqlite3DeleteFrom( */ if( !isView ){ int iAddrOnce = 0; + u8 p5 = (eOnePass==ONEPASS_OFF ? 0 : OPFLAG_FORDELETE); if( eOnePass==ONEPASS_MULTI ){ iAddrOnce = sqlite3CodeOnce(pParse); VdbeCoverage(v); } testcase( IsVirtual(pTab) ); - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iTabCur, aToOpen, - &iDataCur, &iIdxCur); + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, p5, iTabCur, + aToOpen, &iDataCur, &iIdxCur); assert( pPk || IsVirtual(pTab) || iDataCur==iTabCur ); assert( pPk || IsVirtual(pTab) || iIdxCur==iDataCur+1 ); if( eOnePass==ONEPASS_MULTI ) sqlite3VdbeJumpHere(v, iAddrOnce); diff --git a/src/insert.c b/src/insert.c index 9274b0771d..3d213a8d37 100644 --- a/src/insert.c +++ b/src/insert.c @@ -762,7 +762,7 @@ void sqlite3Insert( /* If this is not a view, open the table and and all indices */ if( !isView ){ int nIdx; - nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, -1, 0, + nIdx = sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, -1, 0, &iDataCur, &iIdxCur); aRegIdx = sqlite3DbMallocRaw(db, sizeof(int)*(nIdx+1)); if( aRegIdx==0 ){ @@ -1650,6 +1650,7 @@ int sqlite3OpenTableAndIndices( Parse *pParse, /* Parsing context */ Table *pTab, /* Table to be opened */ int op, /* OP_OpenRead or OP_OpenWrite */ + u8 p5, /* P5 value for OP_Open* instructions */ int iBase, /* Use this for the table cursor, if there is one */ u8 *aToOpen, /* If not NULL: boolean for each table and index */ int *piDataCur, /* Write the database source cursor number here */ @@ -1662,6 +1663,7 @@ int sqlite3OpenTableAndIndices( Vdbe *v; assert( op==OP_OpenRead || op==OP_OpenWrite ); + assert( op==OP_OpenWrite || p5==0 ); if( IsVirtual(pTab) ){ /* This routine is a no-op for virtual tables. Leave the output ** variables *piDataCur and *piIdxCur uninitialized so that valgrind @@ -1689,6 +1691,7 @@ int sqlite3OpenTableAndIndices( if( aToOpen==0 || aToOpen[i+1] ){ sqlite3VdbeAddOp3(v, op, iIdxCur, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); + sqlite3VdbeChangeP5(v, p5); VdbeComment((v, "%s", pIdx->zName)); } } diff --git a/src/pragma.c b/src/pragma.c index 64614a7ebc..14c4811746 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1465,7 +1465,7 @@ void sqlite3Pragma( sqlite3VdbeAddOp2(v, OP_Halt, 0, 0); sqlite3VdbeJumpHere(v, addr); sqlite3ExprCacheClear(pParse); - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenRead, 0, 1, 0, &iDataCur, &iIdxCur); sqlite3VdbeAddOp2(v, OP_Integer, 0, 7); for(j=0, pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext, j++){ diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7f33841d27..96f43070c7 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -2795,7 +2795,8 @@ struct AuthContext { #define OPFLAG_TYPEOFARG 0x80 /* OP_Column only used for typeof() */ #define OPFLAG_BULKCSR 0x01 /* OP_Open** used to open bulk cursor */ #define OPFLAG_SEEKEQ 0x02 /* OP_Open** cursor uses EQ seek only */ -#define OPFLAG_P2ISREG 0x04 /* P2 to OP_Open** is a register number */ +#define OPFLAG_FORDELETE 0x08 /* OP_Open is opening for-delete csr */ +#define OPFLAG_P2ISREG 0x10 /* P2 to OP_Open** is a register number */ #define OPFLAG_PERMUTE 0x01 /* OP_Compare: use the permutation */ /* @@ -3466,7 +3467,7 @@ void sqlite3ResolvePartIdxLabel(Parse*,int); void sqlite3GenerateConstraintChecks(Parse*,Table*,int*,int,int,int,int, u8,u8,int,int*); void sqlite3CompleteInsertion(Parse*,Table*,int,int,int,int*,int,int,int); -int sqlite3OpenTableAndIndices(Parse*, Table*, int, int, u8*, int*, int*); +int sqlite3OpenTableAndIndices(Parse*, Table*, int, u8, int, u8*, int*, int*); void sqlite3BeginWriteOperation(Parse*, int, int); void sqlite3MultiWrite(Parse*); void sqlite3MayAbort(Parse*); diff --git a/src/test3.c b/src/test3.c index 07d12d28c0..212dff5fad 100644 --- a/src/test3.c +++ b/src/test3.c @@ -214,11 +214,12 @@ static int btree_cursor( pBt = sqlite3TestTextToPtr(argv[1]); if( Tcl_GetInt(interp, argv[2], &iTable) ) return TCL_ERROR; if( Tcl_GetBoolean(interp, argv[3], &wrFlag) ) return TCL_ERROR; + if( wrFlag ) wrFlag = BTREE_WRCSR; pCur = (BtCursor *)ckalloc(sqlite3BtreeCursorSize()); memset(pCur, 0, sqlite3BtreeCursorSize()); sqlite3BtreeEnter(pBt); #ifndef SQLITE_OMIT_SHARED_CACHE - rc = sqlite3BtreeLockTable(pBt, iTable, wrFlag); + rc = sqlite3BtreeLockTable(pBt, iTable, !!wrFlag); #endif if( rc==SQLITE_OK ){ rc = sqlite3BtreeCursor(pBt, iTable, wrFlag, 0, pCur); @@ -598,6 +599,48 @@ static int btree_set_cache_size( return TCL_OK; } +/* +** usage: btree_insert CSR ?KEY? VALUE +** +** Set the size of the cache used by btree $ID. +*/ +static int btree_insert( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[] +){ + BtCursor *pCur; + int rc; + void *pKey = 0; + int nKey = 0; + void *pData = 0; + int nData = 0; + + if( objc!=4 && objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "?-intkey? CSR KEY VALUE"); + return TCL_ERROR; + } + + if( objc==4 ){ + if( Tcl_GetIntFromObj(interp, objv[2], &nKey) ) return TCL_ERROR; + pData = (void*)Tcl_GetByteArrayFromObj(objv[3], &nData); + }else{ + pKey = (void*)Tcl_GetByteArrayFromObj(objv[2], &nKey); + } + pCur = (BtCursor*)sqlite3TestTextToPtr(Tcl_GetString(objv[1])); + + sqlite3BtreeEnter(pCur->pBtree); + rc = sqlite3BtreeInsert(pCur, pKey, nKey, pData, nData, 0, 0, 0); + sqlite3BtreeLeave(pCur->pBtree); + + Tcl_ResetResult(interp); + if( rc ){ + Tcl_AppendResult(interp, sqlite3ErrName(rc), 0); + return TCL_ERROR; + } + return TCL_OK; +} /* @@ -629,5 +672,7 @@ int Sqlitetest3_Init(Tcl_Interp *interp){ Tcl_CreateCommand(interp, aCmd[i].zName, aCmd[i].xProc, 0, 0); } + Tcl_CreateObjCommand(interp, "btree_insert", btree_insert, 0, 0); + return TCL_OK; } diff --git a/src/update.c b/src/update.c index 5cb5574909..1335c269ed 100644 --- a/src/update.c +++ b/src/update.c @@ -429,7 +429,7 @@ void sqlite3Update( if( aiCurOnePass[0]>=0 ) aToOpen[aiCurOnePass[0]-iBaseCur] = 0; if( aiCurOnePass[1]>=0 ) aToOpen[aiCurOnePass[1]-iBaseCur] = 0; } - sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, iBaseCur, aToOpen, + sqlite3OpenTableAndIndices(pParse, pTab, OP_OpenWrite, 0, iBaseCur, aToOpen, 0, 0); } diff --git a/src/vdbe.c b/src/vdbe.c index a8a3dab167..d702313b84 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -3324,7 +3324,6 @@ case OP_ReopenIdx: { case OP_OpenRead: case OP_OpenWrite: - assert( (pOp->p5&(OPFLAG_P2ISREG|OPFLAG_BULKCSR|OPFLAG_SEEKEQ))==pOp->p5 ); assert( pOp->opcode==OP_OpenWrite || pOp->p5==0 || pOp->p5==OPFLAG_SEEKEQ ); assert( p->bIsReader ); assert( pOp->opcode==OP_OpenRead || pOp->opcode==OP_ReopenIdx @@ -3345,7 +3344,8 @@ case OP_OpenWrite: pX = pDb->pBt; assert( pX!=0 ); if( pOp->opcode==OP_OpenWrite ){ - wrFlag = 1; + assert( OPFLAG_FORDELETE==BTREE_FORDELETE ); + wrFlag = BTREE_WRCSR | (pOp->p5 & OPFLAG_FORDELETE); assert( sqlite3SchemaMutexHeld(db, iDb, 0) ); if( pDb->pSchema->file_format < p->minWriteFileFormat ){ p->minWriteFileFormat = pDb->pSchema->file_format; @@ -3469,11 +3469,11 @@ case OP_OpenEphemeral: { assert( pKeyInfo->db==db ); assert( pKeyInfo->enc==ENC(db) ); pCx->pKeyInfo = pKeyInfo; - rc = sqlite3BtreeCursor(pCx->pBt, pgno, 1, pKeyInfo, pCx->pCursor); + rc = sqlite3BtreeCursor(pCx->pBt, pgno, BTREE_WRCSR, pKeyInfo, pCx->pCursor); } pCx->isTable = 0; }else{ - rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, 1, 0, pCx->pCursor); + rc = sqlite3BtreeCursor(pCx->pBt, MASTER_ROOT, BTREE_WRCSR, 0, pCx->pCursor); pCx->isTable = 1; } } diff --git a/src/where.c b/src/where.c index 365a376aa0..1c87706ea2 100644 --- a/src/where.c +++ b/src/where.c @@ -4010,6 +4010,7 @@ WhereInfo *sqlite3WhereBegin( int ii; /* Loop counter */ sqlite3 *db; /* Database connection */ int rc; /* Return code */ + u8 bFordelete = 0; assert( (wctrlFlags & WHERE_ONEPASS_MULTIROW)==0 || ( (wctrlFlags & WHERE_ONEPASS_DESIRED)!=0 @@ -4265,8 +4266,11 @@ WhereInfo *sqlite3WhereBegin( && 0==(wsFlags & WHERE_VIRTUALTABLE) )){ pWInfo->eOnePass = bOnerow ? ONEPASS_SINGLE : ONEPASS_MULTI; - if( HasRowid(pTabList->a[0].pTab) ){ - pWInfo->a[0].pWLoop->wsFlags &= ~WHERE_IDX_ONLY; + if( HasRowid(pTabList->a[0].pTab) && (wsFlags & WHERE_IDX_ONLY) ){ + if( wctrlFlags & WHERE_ONEPASS_MULTIROW ){ + bFordelete = OPFLAG_FORDELETE; + } + pWInfo->a[0].pWLoop->wsFlags = (wsFlags & ~WHERE_IDX_ONLY); } } } @@ -4315,8 +4319,13 @@ WhereInfo *sqlite3WhereBegin( assert( n<=pTab->nCol ); } #ifdef SQLITE_ENABLE_CURSOR_HINTS - if( pLoop->u.btree.pIndex!=0 ) sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ); + if( pLoop->u.btree.pIndex!=0 ){ + sqlite3VdbeChangeP5(v, OPFLAG_SEEKEQ|bFordelete); + }else #endif + { + sqlite3VdbeChangeP5(v, bFordelete); + } #ifdef SQLITE_ENABLE_COLUMN_USED_MASK sqlite3VdbeAddOp4Dup8(v, OP_ColumnsUsed, pTabItem->iCursor, 0, 0, (const u8*)&pTabItem->colUsed, P4_INT64); diff --git a/test/fordelete.test b/test/fordelete.test new file mode 100644 index 0000000000..1e860e8867 --- /dev/null +++ b/test/fordelete.test @@ -0,0 +1,130 @@ +# 2001 September 15 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# This file implements regression tests for SQLite library. The +# focus of this file is testing the SELECT statement. +# +# $Id: select1.test,v 1.70 2009/05/28 01:00:56 drh Exp $ + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set ::testprefix fordelete + +# This function returns a list of the tables or indexes opened with +# OP_OpenWrite instructions when the SQL statement passed as the only +# argument is executed. If the OPFLAG_FORDELETE flag is specified on +# the OP_OpenWrite, an asterix is appended to the object name. The list +# is sorted in [lsort] order before it is returned. +# +proc analyze_delete_program {sql} { + # Build a map from root page to table/index name. + db eval { + SELECT name, rootpage FROM sqlite_master + } { + set T($rootpage) $name + } + + # Calculate the results. + set res [list] + db eval "EXPLAIN $sql" R { + if {$R(opcode) == "OpenWrite"} { + set obj $T($R(p2)) + if {"0x$R(p5)" & 0x08} { append obj *} + lappend res $obj + } + } + + lsort $res +} + +proc do_adp_test {tn sql res} { + uplevel [list do_test $tn [list analyze_delete_program $sql] [list {*}$res]] +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a PRIMARY KEY, b); +} + +foreach {tn sql res} { + 1 { DELETE FROM t1 WHERE a=?} { sqlite_autoindex_t1_1 t1* } + 2 { DELETE FROM t1 WHERE a=? AND b=? } { sqlite_autoindex_t1_1 t1 } + 3 { DELETE FROM t1 WHERE a>? } { sqlite_autoindex_t1_1 t1* } + 4 { DELETE FROM t1 WHERE rowid=? } { sqlite_autoindex_t1_1* t1 } +} { + do_adp_test 1.$tn $sql $res +} + +do_execsql_test 2.0 { + CREATE TABLE t2(a, b, c); + CREATE INDEX t2a ON t2(a); + CREATE INDEX t2b ON t2(b); + CREATE INDEX t2c ON t2(c); +} +foreach {tn sql res} { + 1 { DELETE FROM t2 WHERE a=?} { t2* t2a t2b* t2c* } + 2 { DELETE FROM t2 WHERE a=? AND +b=?} { t2 t2a t2b* t2c* } + 3 { DELETE FROM t2 WHERE a=? OR b=?} { t2 t2a* t2b* t2c* } + 4 { DELETE FROM t2 WHERE +a=? } { t2 t2a* t2b* t2c* } + 5 { DELETE FROM t2 WHERE rowid=? } { t2 t2a* t2b* t2c* } +} { + do_adp_test 2.$tn $sql $res +} + +#------------------------------------------------------------------------- +# Test that a record that consists of the bytes: +# +# 0x01 0x00 +# +# is interpreted by OP_Column as a vector of NULL values (assuming the +# default column values are NULL). Also test that: +# +# 0x00 +# +# is handled in the same way. +# +do_execsql_test 3.0 { + CREATE TABLE x1(a INTEGER PRIMARY KEY, b, c, d); + CREATE TABLE x2(a INTEGER PRIMARY KEY, b, c, d); +} + +do_test 3.1 { + set root [db one { SELECT rootpage FROM sqlite_master WHERE name = 'x1' }] + db eval { + BEGIN IMMEDIATE; + } + set bt [btree_from_db db] + set csr [btree_cursor $bt $root 1] + btree_insert $csr 5 "\000" + btree_close_cursor $csr + db eval { COMMIT } + + db eval { + SELECT * FROM x1; + } +} {5 {} {} {}} + +do_test 3.2 { + set root [db one { SELECT rootpage FROM sqlite_master WHERE name = 'x2' }] + db eval { + BEGIN IMMEDIATE; + } + set bt [btree_from_db db] + set csr [btree_cursor $bt $root 1] + btree_insert $csr 6 "\000" + btree_close_cursor $csr + db eval { COMMIT } + + db eval { + SELECT * FROM x2; + } +} {6 {} {} {}} + +finish_test +