diff --git a/manifest b/manifest index 26acdd9abf..8ffa882cd6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sbtree\scursors\sto\spersist\sthrough\sBtreeDelete()\scalls.\s(CVS\s2103) -D 2004-11-16T04:57:24 +C Perform\sdeletes\sin\sa\ssingle\spass.\s(CVS\s2104) +D 2004-11-16T15:50:20 F Makefile.in e747bb5ba34ccbdd81f79dcf1b2b33c02817c21d F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -29,11 +29,11 @@ F sqlite3.def dbaeb20c153e1d366e8f421b55a573f5dfc00863 F sqlite3.pc.in 985b9bf34192a549d7d370e0f0b6b34a4f61369a F src/attach.c e49d09dad9f5f9fb10b4b0c1be5a70ae4c45e689 F src/auth.c 3b81f2a42f48a62c2c9c9b0eda31a157c681edea -F src/btree.c 967b42616d0dc06d1bc9eb12d0af95252163df01 +F src/btree.c c878e87a415a429a335bf26d834a311c5c40f5d1 F src/btree.h 861e40b759a195ba63819740e484390012cf81ab F src/build.c a95eb1181247368b0ffe2eed121a43735976a964 F src/date.c 65536e7ea04fdde6e0551264fca15966966e171f -F src/delete.c f0af21a1ede15524a5edd59fe10ef486283a1ee9 +F src/delete.c be9d039b819f4a5d0fdfaeceace139ba189ef819 F src/expr.c 4ee3e47358c92a919062255b14057a7a8f641e01 F src/func.c 181ea4b8bbc621457838494a440d2e4e2307ab70 F src/hash.c a97721a55440b7bea31ffe471bb2f6b4123cddd5 @@ -58,10 +58,10 @@ F src/parse.y 3282026b619e1c7f932fd8ecef9627fa86da048a F src/pragma.c 0b43b8cac4870bfa041bf2ca29d7ce47b76362d6 F src/printf.c 3d20b21cfecadacecac3fb7274e746cb81d3d357 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 -F src/select.c 156990c636102bb6b8de85e7ff3396a62568476b +F src/select.c cf4b7952d6d214931c52636ee726f19ee2a275c5 F src/shell.c 55adda3cf3c1cc2f6c1919aac17b2318f9c2a96f F src/sqlite.h.in a44eac0716bf4751447160d5c8ed049ece66d45a -F src/sqliteInt.h 8569ce94e891a854de71d7bd628da1d25ee6dfe4 +F src/sqliteInt.h dd26056a172a5d488a78846b5ed8db6953db4e5d F src/table.c 25b3ff2b39b7d87e8d4a5da0713d68dfc06cbee9 F src/tclsqlite.c 7f1a1a678140e6901c8954590ca2aabe50b48f71 F src/test1.c 8c330b53aa04d234ea7da6a90141ce9958a8901c @@ -71,7 +71,7 @@ F src/test4.c 7c6b9fc33dd1f3f93c7f1ee6e5e6d016afa6c1df F src/test5.c 64f08b2a50ef371a1bd68ff206829e7b1b9997f5 F src/tokenize.c 2ad3d1ae1a0a70746db0b31a0a74f58050a3c39a F src/trigger.c 0c91b56182560263733e4b035acdb939bd1cf0e2 -F src/update.c 3cc67f6053495152e82a6a48c93ed331218e936e +F src/update.c 395a2b270dfcbc96c20e40c9cb42b0533768ce30 F src/utf.c e45ce11be6922408cd381561721f6cca7d3b992a F src/util.c 005fdf2d008f3429d081766ad6098fdd86d8d8e6 F src/vacuum.c ecb4a2c6f1ac5cc9b394dc64d3bb14ca650c4f60 @@ -81,7 +81,7 @@ F src/vdbeInt.h 6017100adff362b8dfa37a69e3f1431f084bfa5b F src/vdbeapi.c 74be7f96c0a1ac275661f8b32276ac521d9ce37c F src/vdbeaux.c c6da55e0096e141211f918837eca98e0be6400b4 F src/vdbemem.c 5876c8abf4374fef671f4fd8dc333ef3fc95a2f0 -F src/where.c 6e637a6b3e61fe3104adc4e5caa4738bf6570daa +F src/where.c 4d28167e450255372b45abf1bc8cd5f0e9264d7b F test/all.test 929bfa932b55e75c96fe2203f7650ba451c1862c F test/alter.test ea6b104fa83da6970b1ce61885827817bdaced3a F test/attach.test e305dd59a375e37c658c6d401f19f8a95880bf9a @@ -101,9 +101,9 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test a6d3b842db22af97dd14b989e90a2fd96066b72f -F test/btree8.test f0841e71ea311faf3fa04d5c80a75ccb9dc6d2c9 -F test/capi2.test 1ec97bf8896185aec2366c7d07b01edef6ae4b7e -F test/capi3.test c9b162838cda7f61c6cfefed304b69287f2fc688 +F test/btree8.test 12db22f6963d9b33a5aa8e8b766033afc82b22c2 +F test/capi2.test cd5e149564094bda9a587e70ec5949863222cd23 +F test/capi3.test da88858ea5318c0cbd0990be9d8db0237496a3dc F test/capi3b.test 5b6a66f9f295f79f443b5d3f33187fa5ef6cf336 F test/collate1.test f79736d2ebf5492167ee4d1f4ab4c09dda776b03 F test/collate2.test 12fd658d8f5106a8a5c8a77d66919d8c89394036 @@ -117,7 +117,7 @@ F test/crash.test 48b481769dd0ead25b0dfc0150853bfa39a3b65c F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/date.test dda578ec1857837156bd8b32f8e09d81d7d7881c F test/delete.test fc29491f6a7ac899ce29f4549a104809e245d9a6 -F test/delete2.test 1d3f99f52f50eb6ed10c803f80540a6857307a7d +F test/delete2.test 04a19e248d88156324ae964676bb4584b65b46f4 F test/diskfull.test e2f6cfd868713ead06dc82b84a4938e868128fc0 F test/enc.test 7a03417a1051fe8bc6c7641cf4c8c3f7e0066d52 F test/enc2.test 6d1a2650e9da43eab499d18ca694a0cb6ec69dee @@ -140,7 +140,7 @@ F test/join4.test 8dec387d06b3a4685e1104048065cf5236b99b93 F test/lastinsert.test 09ac3a359ced3d4510feccc0dcbae3d80e449cf9 F test/laststmtchanges.test 9cb56c5935103cacd0070d9d25d8dde322928db1 F test/limit.test f7c06fccd76755e8d083b61c06bc31cf461b9c35 -F test/lock.test 7cb9395919a0986ee4dd08bd49d34df93c8fc4fe +F test/lock.test ba72c211499b0874c56643b9ede1df4018bb20de F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 F test/main.test 5f9deae11b93336da1ccc5f91cf8be075c91ddf1 @@ -149,7 +149,7 @@ F test/memdb.test 34ee8598de307a16ccc3ac91b85cee9c668ae5ed F test/memleak.test f1fa233f8295dd1d955a00d5e5ee857850f27f29 F test/minmax.test c0f92d3f7b11656221735385f2c8b1878bbbdaf6 F test/misc1.test 744f60d1025fa978708b96cb222a07a1feb1524a -F test/misc2.test 9d9403f7e6092699f3f92bb1e26ff55165528e7c +F test/misc2.test 53cf5e931547962563df3600f85ba49e86ffa1fe F test/misc3.test 928a2f1e1189924ed14e1ae074e34f40688bdf94 F test/misc4.test d005a75f095bb04db09a5d096144405ae566b622 F test/misuse.test 2d7c46160f7c214f761fc5d030684a37ae8832a6 @@ -258,7 +258,7 @@ F www/tclsqlite.tcl 560ecd6a916b320e59f2917317398f3d59b7cc25 F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl fdacb0ba2d39831e8a6240d05a490026ad4c4e4c -P 33c9b647aa70d1a9dab0e999daf853aa71d7df37 -R 50b298d755ddcbf483d54572fec74d25 +P 6ad5fc8e1a119b750a82fc1426704164a2042d57 +R db6ab1c6b37169af000d8cc9fa56bcb7 U danielk1977 -Z 8f5fe953592a6b674b59302a9768154c +Z 9bd342e5e06ad9732b13806797d3998c diff --git a/manifest.uuid b/manifest.uuid index d6372e52c2..6de650482c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6ad5fc8e1a119b750a82fc1426704164a2042d57 \ No newline at end of file +a2e1c35b327e33684ab19e5f65727c42c7b2949c \ No newline at end of file diff --git a/src/btree.c b/src/btree.c index daaf397069..4aa6538a44 100644 --- a/src/btree.c +++ b/src/btree.c @@ -9,7 +9,7 @@ ** May you share freely, never taking more than you give. ** ************************************************************************* -** $Id: btree.c,v 1.218 2004/11/16 04:57:24 danielk1977 Exp $ +** $Id: btree.c,v 1.219 2004/11/16 15:50:20 danielk1977 Exp $ ** ** This file implements a external (disk-based) database using BTrees. ** For a detailed discussion of BTrees, refer to @@ -4307,11 +4307,6 @@ static int balance(MemPage *pPage){ ** then this routine returns SQLITE_OK. */ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ - BtCursor *p; - for(p=pBt->pCursor; p; p=p->pNext){ - if( p->pgnoRoot!=pgnoRoot || p==pExclude ) continue; - if( p->wrFlag==0 ) return SQLITE_LOCKED; - } return SQLITE_OK; } @@ -4512,7 +4507,6 @@ int sqlite3BtreeDelete(BtCursor *pCur){ BtCursor leafCur; unsigned char *pNext; int szNext; - int notUsed; unsigned char *tempCell; assert( !pPage->leafData ); diff --git a/src/delete.c b/src/delete.c index 0ed2a7d175..43ee228424 100644 --- a/src/delete.c +++ b/src/delete.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** -** $Id: delete.c,v 1.88 2004/11/05 17:17:50 drh Exp $ +** $Id: delete.c,v 1.89 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -64,7 +64,6 @@ void sqlite3OpenTableForReading( sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } - /* ** Process a DELETE FROM statement. */ @@ -76,7 +75,7 @@ void sqlite3DeleteFrom( Vdbe *v; /* The virtual database engine */ Table *pTab; /* The table from which records will be deleted */ const char *zDb; /* Name of database holding pTab */ - int end, addr = 0; /* A couple addresses of generated code */ + int addr = 0; /* A couple addresses of generated code */ int i; /* Loop counter */ WhereInfo *pWInfo; /* Information about the WHERE clause */ Index *pIdx; /* For looping over indices of the table */ @@ -150,10 +149,15 @@ void sqlite3DeleteFrom( oldIdx = pParse->nTab++; } - /* Resolve the column names in all the expressions. + /* Resolve the column names in all the expressions. Allocate cursors + ** for the table and indices first, in case an expression needs to use + ** a cursor (e.g. an IN() expression). */ assert( pTabList->nSrc==1 ); iCur = pTabList->a[0].iCursor = pParse->nTab++; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + pParse->nTab++; + } if( sqlite3ExprResolveAndCheck(pParse, pTabList, 0, pWhere, 0, 0) ){ goto delete_from_cleanup; } @@ -227,22 +231,6 @@ void sqlite3DeleteFrom( } } - /* Begin the database scan - */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0); - if( pWInfo==0 ) goto delete_from_cleanup; - - /* Remember the key of every item to be deleted. - */ - sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); - if( db->flags & SQLITE_CountRows ){ - sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); - } - - /* End the database scan loop. - */ - sqlite3WhereEnd(pWInfo); - /* Open the pseudo-table used to store OLD if there are triggers. */ if( row_triggers_exist ){ @@ -250,80 +238,49 @@ void sqlite3DeleteFrom( sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); } - /* Delete every item whose key was written to the list during the - ** database scan. We have to delete items after the scan is complete - ** because deleting an item can change the scan order. - */ - sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0); - end = sqlite3VdbeMakeLabel(v); + /* Open cursors for the table and indices we are deleting from. */ + if( !isView ){ + sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); + } - /* This is the beginning of the delete loop when there are - ** row triggers. + /* Begin the database scan + */ + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, isView?0:iCur); + if( pWInfo==0 ) goto delete_from_cleanup; + addr = pWInfo->iContinue; + + /* If row-triggers exist, copy the record being deleted into the + ** oldIdx psuedo-table. Then invoke the BEFORE triggers. */ if( row_triggers_exist ){ - addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); - sqlite3VdbeAddOp(v, OP_Dup, 0, 0); - if( !isView ){ - sqlite3OpenTableForReading(v, iCur, pTab); - } - sqlite3VdbeAddOp(v, OP_MoveGe, iCur, 0); sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); - if( !isView ){ - sqlite3VdbeAddOp(v, OP_Close, iCur, 0); - } - (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } - if( !isView ){ - /* Open cursors for the table we are deleting from and all its - ** indices. If there are row triggers, this happens inside the - ** OP_ListRead loop because the cursor have to all be closed - ** before the trigger fires. If there are no row triggers, the - ** cursors are opened only once on the outside the loop. - */ - sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); - - /* This is the beginning of the delete loop when there are no - ** row triggers */ - if( !row_triggers_exist ){ - addr = sqlite3VdbeAddOp(v, OP_ListRead, 0, end); - } - - /* Delete the row */ - sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); - } - - /* If there are row triggers, close all cursors then invoke - ** the AFTER triggers + /* Delete the row. Increment the callback value if the count-rows flag + ** is set. */ + if( db->flags & SQLITE_CountRows ){ + sqlite3VdbeAddOp(v, OP_AddImm, 1, 0); + } + sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); + sqlite3GenerateRowDelete(db, v, pTab, iCur, pParse->nested==0); + + /* Code the AFTER triggers. */ if( row_triggers_exist ){ - if( !isView ){ - for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ - sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); - } - sqlite3VdbeAddOp(v, OP_Close, iCur, 0); - } (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } - /* End of the delete loop */ - sqlite3VdbeAddOp(v, OP_Goto, 0, addr); - sqlite3VdbeResolveLabel(v, end); - sqlite3VdbeAddOp(v, OP_ListReset, 0, 0); - - /* Close the cursors after the loop if there are no row triggers */ - if( !row_triggers_exist ){ - for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ - sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); - } - sqlite3VdbeAddOp(v, OP_Close, iCur, 0); + /* End the database scan loop and close indices. */ + sqlite3WhereEnd(pWInfo); + for(i=1, pIdx=pTab->pIndex; pIdx; i++, pIdx=pIdx->pNext){ + sqlite3VdbeAddOp(v, OP_Close, iCur + i, pIdx->tnum); } } diff --git a/src/select.c b/src/select.c index 155ae9c0a2..00ffa40607 100644 --- a/src/select.c +++ b/src/select.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** -** $Id: select.c,v 1.213 2004/10/31 02:22:49 drh Exp $ +** $Id: select.c,v 1.214 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -2523,7 +2523,7 @@ int sqlite3Select( /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, - pGroupBy ? 0 : &pOrderBy); + pGroupBy ? 0 : &pOrderBy, -1); if( pWInfo==0 ) goto select_end; /* Use the standard inner loop if we are not dealing with diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 4f4e1b294c..810aa622a0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.339 2004/11/12 13:42:31 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.340 2004/11/16 15:50:20 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -1313,9 +1313,10 @@ void sqlite3SelectUnbind(Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*); +void sqlite3OpenTable(Vdbe*, int iCur, Table*, int); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); -WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**); +WhereInfo *sqlite3WhereBegin(Parse*, SrcList*, Expr*, int, ExprList**, int); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCode(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*); diff --git a/src/update.c b/src/update.c index d53d86f77a..b56574cb6c 100644 --- a/src/update.c +++ b/src/update.c @@ -12,7 +12,7 @@ ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** -** $Id: update.c,v 1.94 2004/11/05 17:17:50 drh Exp $ +** $Id: update.c,v 1.95 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -235,7 +235,7 @@ void sqlite3Update( /* Begin the database scan */ - pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0); + pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, -1); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. diff --git a/src/where.c b/src/where.c index eb51bdfac8..f1a9a0c0b2 100644 --- a/src/where.c +++ b/src/where.c @@ -12,7 +12,7 @@ ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** -** $Id: where.c,v 1.116 2004/10/04 13:38:09 drh Exp $ +** $Id: where.c,v 1.117 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -471,13 +471,18 @@ static void codeEqualityTerm( ** ** If the where clause loops cannot be arranged to provide the correct ** output order, then the *ppOrderBy is unchanged. +** +** If parameter iTabCur is non-negative, then it is a cursor already open +** on table pTabList->aSrc[0]. Use this cursor instead of opening a new +** one. */ WhereInfo *sqlite3WhereBegin( - Parse *pParse, /* The parser context */ - SrcList *pTabList, /* A list of all tables to be scanned */ - Expr *pWhere, /* The WHERE clause */ - int pushKey, /* If TRUE, leave the table key on the stack */ - ExprList **ppOrderBy /* An ORDER BY clause, or NULL */ + Parse *pParse, /* The parser context */ + SrcList *pTabList, /* A list of all tables to be scanned */ + Expr *pWhere, /* The WHERE clause */ + int pushKey, /* If TRUE, leave the table key on the stack */ + ExprList **ppOrderBy, /* An ORDER BY clause, or NULL */ + int iTabCur /* Cursor for pTabList->aSrc[0] */ ){ int i; /* Loop counter */ WhereInfo *pWInfo; /* Will become the return value of this function */ @@ -773,7 +778,9 @@ WhereInfo *sqlite3WhereBegin( pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; - sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab); + if( i>0 || iTabCur<0 ){ + sqlite3OpenTableForReading(v, pTabList->a[i].iCursor, pTab); + } sqlite3CodeVerifySchema(pParse, pTab->iDb); if( (pIx = pWInfo->a[i].pIdx)!=0 ){ sqlite3VdbeAddOp(v, OP_Integer, pIx->iDb, 0); diff --git a/test/btree8.test b/test/btree8.test index e45569a5b4..2e5b0529ba 100644 --- a/test/btree8.test +++ b/test/btree8.test @@ -13,15 +13,65 @@ # this file tests that existing cursors are correctly repositioned # when entries are inserted into or deleted from btrees. # -# $Id: btree8.test,v 1.2 2004/11/16 04:57:25 danielk1977 Exp $ +# $Id: btree8.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl +# Test organization: +# +# btree-8.1.*: Test cursor persistence when inserting records into tables. +# btree-8.2.*: Test cursor persistence when deleting records from tables. +# btree-8.3.*: Test cursor persistence when inserting records into indices. +# btree-8.4.*: Test cursor persistence when deleting records from indices. +# + + +# Transform the number $num into a string of length $len by repeating the +# string representation of the number as many times as necessary. Repeats +# are seperated by a '.' character. Eg: +# +# [num_to_string 456 10] -> "456.456.45" +# +proc num_to_string {num len} { + set num [format %.4d $num] + return [string range [string repeat "$num." $len] 0 [expr $len-1]] +} + +# Proc lshuffle takes a list as an argument and returns a copy of that +# list in randomized order. It uses the K-combinator for speed. +# +proc K {x y} {set x} +proc lshuffle { list } { + set n [llength $list] + while {$n>0} { + set j [expr {int(rand()*$n)}] + lappend slist [lindex $list $j] + set list [lreplace [K $list [set list {}]] $j $j] + incr n -1 + } + return $slist +} + +# Proc lremove takes two arguments, a list (the first argument) and a key +# (the second argument). A copy of the list is returned with all elements +# equal to $key removed. +# +proc lremove {list key} { + while { [set i [lsearch $list $key]] != -1 } { + set list [concat \ + [lrange $list 0 [expr $i-1]] \ + [lrange $list [expr $i+1] end] + ] + } + return $list +} + + # Use the SQL interface to create a couple of btree tables, one using # the flags for an SQL table, the other an SQL index. # -do_test btree8-1.0 { +do_test btree8-0.0 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE INDEX i1 ON t1(b); @@ -31,6 +81,16 @@ set tnum [execsql {SELECT rootpage FROM sqlite_master where type = 'table'}] set inum [execsql {SELECT rootpage FROM sqlite_master where type = 'index'}] db close +#------------------------------------------------------------------------- +# Tests btree8-1.* insert a handful of records (~10) into the type of +# b-tree created for an SQL table. The records have integer keys in the +# range 1..5000. A cursor is left pointing to each of these records. +# Then, a record is inserted for each key value between 1 and 5000, +# including the values for which a record already exists (overwriting +# the original). After each record is inserted, the existing cursors +# are checked to ensure they still point at the same key-value. +# + # Open the database at the btree level and begin a transaction do_test btree8-1.1 { set ::bt [btree_open test.db 100 0] @@ -79,6 +139,14 @@ for {set i $testnum} {$i < 5000 && $nErr==0 } {incr i} { } } +#------------------------------------------------------------------------- +# Tests btree8-2.* loop through the tree created by tests btree8-1.*, +# deleting records in sequential order. After each record is deleted, +# each of the open cursors is checked to ensure that it still points +# to the same key-value or, if that key value has been deleted, returns +# 0 as the integer key value. +# + # Now delete entries from the table. btree_first $::write_csr for {set i $first_entry} {$i < 5000 && $nErr==0 } {incr i} { @@ -103,6 +171,7 @@ for {set i $first_entry} {$i < 5000 && $nErr==0 } {incr i} { } } +# Close all existing cursors and conclude the open transaction. btree_close_cursor $::write_csr btree_commit $::bt if {$::nErr>0} { puts $::csr_list ; exit } @@ -111,16 +180,12 @@ foreach csr $csr_list { } set csr_list [list] -# Transform the number $num into a string of length $len by repeating the -# string representation of the number as many times as necessary. Repeats -# are seperated by a '.' character. Eg: +#------------------------------------------------------------------------- +# Tests btree8-3.* are analogous to btree8-1.*, but use the type of btree +# created for an SQL index, not an SQL table. Instead of integers, key +# values are strings 20 bytes long created by transforming integers +# into string using the [num_to_string] proc (see above). # -# [num_to_string 456 10] -> "456.456.45" -# -proc num_to_string {num len} { - set num [format %.4d $num] - return [string range [string repeat "$num." $len] 0 [expr $len-1]] -} foreach key $keys { lappend skeys [num_to_string $key 20] @@ -144,8 +209,6 @@ foreach key $skeys { } btree_commit $::bt -# set btree_trace 1 - # Now write more entries to the index (and overwrite the ones that exist). # After each write, check that the cursors created above still point to the # same entries. @@ -170,21 +233,13 @@ for {set i $testnum} {$i < 5000 && $nErr==0 } {incr i} { btree_commit $::bt btree_begin_transaction $::bt -proc lremove {l key} { - set idx [lsearch $l $key] - return [concat [lrange $l 0 [expr $idx-1]] [lrange $l [expr $idx+1] end]] -} -proc K {x y} {set x} -proc lshuffle { list } { - set n [llength $list] - while {$n>0} { - set j [expr {int(rand()*$n)}] - lappend slist [lindex $list $j] - set list [lreplace [K $list [set list {}]] $j $j] - incr n -1 - } - return $slist -} +#------------------------------------------------------------------------- +# Tests btree8-4.* are analogous to btree8-2.*, but use the type of btree +# created for an SQL index, not an SQL table. Instead of integers, key +# values are strings 20 bytes long created by transforming integers +# into string using the [num_to_string] proc (see above). Also, keys +# are deleted in random order, calculated by the [lshuffle] proc (see above). +# # Now delete entries from the index. Do this in a random order, to try to # ensure that internal and external nodes are deleted. @@ -202,7 +257,6 @@ foreach i $delete_order { do_test btree8-4.$i.2 { btree_delete $::write_csr } {} - set delete_order [lremove $delete_order $i] set testnum 2 foreach csr $csr_list key $keys { diff --git a/test/capi2.test b/test/capi2.test index 0d7176fd1d..9ac8d724e8 100644 --- a/test/capi2.test +++ b/test/capi2.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi2.test,v 1.20 2004/11/03 16:27:02 drh Exp $ +# $Id: capi2.test,v 1.21 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -450,15 +450,22 @@ do_test capi2-6.12 { [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 5 {x counter}} + +# The next test used to report that the database was locked. +# As of 3.1 this is no longer the case, the UPDATE works +# even though there is a SELECT active on the table. Rows +# scanned by subsequent calls to sqlite3_step report the +# updated values. +# do_test capi2-6.13 { catchsql {UPDATE t3 SET x=x+1} -} {1 {database table is locked}} +} {0 {}} do_test capi2-6.14 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 6 {x counter}} +} {SQLITE_ROW 1 7 {x counter}} do_test capi2-6.15 { execsql {SELECT * FROM t1} } {1 2 3} @@ -467,7 +474,7 @@ do_test capi2-6.16 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 7 {x counter}} +} {SQLITE_ROW 1 8 {x counter}} do_test capi2-6.17 { catchsql {UPDATE t1 SET b=b+1} } {0 {}} @@ -476,7 +483,7 @@ do_test capi2-6.18 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 8 {x counter}} +} {SQLITE_ROW 1 9 {x counter}} do_test capi2-6.19 { execsql {SELECT * FROM t1} } {1 3 3} @@ -485,7 +492,7 @@ do_test capi2-6.20 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 9 {x counter}} +} {SQLITE_ROW 1 10 {x counter}} #do_test capi2-6.21 { # execsql {ROLLBACK; SELECT * FROM t1} #} {1 2 3} @@ -494,7 +501,7 @@ do_test capi2-6.22 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 10 {x counter}} +} {SQLITE_ROW 1 11 {x counter}} #do_test capi2-6.23 { # execsql {BEGIN TRANSACTION;} #} {} @@ -503,7 +510,7 @@ do_test capi2-6.24 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 11 {x counter}} +} {SQLITE_ROW 1 12 {x counter}} do_test capi2-6.25 { execsql { INSERT INTO t1 VALUES(2,3,4); @@ -515,7 +522,7 @@ do_test capi2-6.26 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 12 {x counter}} +} {SQLITE_ROW 1 13 {x counter}} do_test capi2-6.27 { catchsql { INSERT INTO t1 VALUES(2,4,5); @@ -527,7 +534,7 @@ do_test capi2-6.28 { [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] -} {SQLITE_ROW 1 13 {x counter}} +} {SQLITE_ROW 1 14 {x counter}} do_test capi2-6.99 { sqlite3_finalize $VM1 } {SQLITE_OK} diff --git a/test/capi3.test b/test/capi3.test index 0e29d9a59a..515577f74f 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.23 2004/11/14 21:56:31 drh Exp $ +# $Id: capi3.test,v 1.24 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -759,11 +759,16 @@ do_test capi3-12.2 { INSERT INTO t1 VALUES(3, NULL); } } {0 {}} + +# The following test used to report "database is locked". As of 3.10 +# this is no longer the case, the INSERT is legal. The inserted row +# will be returned after all others (because the scan is being done +# in rowid order). do_test capi3-12.3 { catchsql { INSERT INTO t2 VALUES(4); } -} {1 {database table is locked}} +} {0 {}} do_test capi3-12.4 { catchsql { BEGIN; @@ -775,16 +780,18 @@ do_test capi3-12.5 { } {SQLITE_ROW} do_test capi3-12.6 { sqlite3_step $STMT -} {SQLITE_DONE} +} {SQLITE_ROW} do_test capi3-12.7 { + sqlite3_step $STMT +} {SQLITE_DONE} +do_test capi3-12.8 { sqlite3_finalize $STMT } {SQLITE_OK} -do_test capi3-12.8 { +do_test capi3-12.9 { execsql { COMMIT; SELECT a FROM t1; } } {1 2 3 4} - finish_test diff --git a/test/delete2.test b/test/delete2.test index 064da17f77..eb0d57928f 100644 --- a/test/delete2.test +++ b/test/delete2.test @@ -29,7 +29,7 @@ # The solution to the problem was to detect that the table is locked # before the index entry is deleted. # -# $Id: delete2.test,v 1.2 2004/11/04 14:47:13 drh Exp $ +# $Id: delete2.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -66,27 +66,26 @@ do_test delete2-1.4 { } SQLITE_ROW integrity_check delete2-1.5 -# Try to delete a row from the table. The delete should fail. +# Try to delete a row from the table. Before version 3.10 the DELETE +# would fail because of the SELECT active on the table. In 3.10 the +# DELETE is legal. # do_test delete2-1.6 { catchsql { DELETE FROM q WHERE rowid=1 } -} {1 {database table is locked}} +} {0 {}} integrity_check delete2-1.7 do_test delete2-1.8 { execsql { SELECT * FROM q; } -} {hello id.1 goodbye id.2 again id.3} +} {goodbye id.2 again id.3} -# Finalize the query, thus clearing the lock on the table. Then -# retry the delete. The delete should work this time. -# do_test delete2-1.9 { sqlite3_finalize $STMT catchsql { - DELETE FROM q WHERE rowid=1 + DELETE FROM q WHERE rowid=2 } } {0 {}} integrity_check delete2-1.10 @@ -94,6 +93,6 @@ do_test delete2-1.11 { execsql { SELECT * FROM q; } -} {goodbye id.2 again id.3} +} {again id.3} finish_test diff --git a/test/lock.test b/test/lock.test index a89fa5639d..d004252b70 100644 --- a/test/lock.test +++ b/test/lock.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script is database locks. # -# $Id: lock.test,v 1.27 2004/08/07 23:54:48 drh Exp $ +# $Id: lock.test,v 1.28 2004/11/16 15:50:21 danielk1977 Exp $ set testdir [file dirname $argv0] @@ -98,16 +98,17 @@ do_test lock-1.17 { set x } {8 9} -# You cannot UPDATE a table from within the callback of a SELECT -# on that same table because the SELECT has the table locked. +# Previously, this test ensured that you cannot UPDATE a table from within the +# callback of a SELECT on that same table because the SELECT has the table +# locked. But as of 3.10 you can do this, so the test is removed. # -do_test lock-1.18 { - db eval {SELECT * FROM t1} qv { - set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg] - lappend r $msg - } - set r -} {1 {database table is locked}} +#do_test lock-1.18 { +# db eval {SELECT * FROM t1} qv { +# set r [catch {db eval {UPDATE t1 SET a=b, b=a}} msg] +# lappend r $msg +# } +# set r +#} {1 {database table is locked}} # But you can UPDATE a different table from the one that is used in # the SELECT. diff --git a/test/misc2.test b/test/misc2.test index 9a2c9dba51..c705c48f11 100644 --- a/test/misc2.test +++ b/test/misc2.test @@ -13,7 +13,7 @@ # This file implements tests for miscellanous features that were # left out of other test files. # -# $Id: misc2.test,v 1.13 2004/11/04 04:42:28 drh Exp $ +# $Id: misc2.test,v 1.14 2004/11/16 15:50:21 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -131,57 +131,6 @@ do_test misc2-6.1 { } } {1 2} -# Make sure we get an error message (not a segfault) on an attempt to -# update a table from within the callback of a select on that same -# table. -# -do_test misc2-7.1 { - db close - file delete -force test.db - sqlite3 db test.db - execsql { - CREATE TABLE t1(x); - INSERT INTO t1 VALUES(1); - } - set rc [catch { - db eval {SELECT rowid FROM t1} {} { - db eval "DELETE FROM t1 WHERE rowid=$rowid" - } - } msg] - lappend rc $msg -} {1 {database table is locked}} -do_test misc2-7.2 { - set rc [catch { - db eval {SELECT rowid FROM t1} {} { - db eval "INSERT INTO t1 VALUES(3)" - } - } msg] - lappend rc $msg -} {1 {database table is locked}} -do_test misc2-7.3 { - db close - file delete -force test.db - sqlite3 db :memory: - execsql { - CREATE TABLE t1(x); - INSERT INTO t1 VALUES(1); - } - set rc [catch { - db eval {SELECT rowid FROM t1} {} { - db eval "DELETE FROM t1 WHERE rowid=$rowid" - } - } msg] - lappend rc $msg -} {1 {database table is locked}} -do_test misc2-7.4 { - set rc [catch { - db eval {SELECT rowid FROM t1} {} { - db eval "INSERT INTO t1 VALUES(3)" - } - } msg] - lappend rc $msg -} {1 {database table is locked}} - # Ticket #453. If the SQL ended with "-", the tokenizer was calling that # an incomplete token, which caused problem. The solution was to just call # it a minus sign.