]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Perform deletes in a single pass. (CVS 2104)
authordanielk1977 <danielk1977@noemail.net>
Tue, 16 Nov 2004 15:50:19 +0000 (15:50 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Tue, 16 Nov 2004 15:50:19 +0000 (15:50 +0000)
FossilOrigin-Name: a2e1c35b327e33684ab19e5f65727c42c7b2949c

14 files changed:
manifest
manifest.uuid
src/btree.c
src/delete.c
src/select.c
src/sqliteInt.h
src/update.c
src/where.c
test/btree8.test
test/capi2.test
test/capi3.test
test/delete2.test
test/lock.test
test/misc2.test

index 26acdd9abfaca363abffe7b9f9fec3852bc14c13..8ffa882cd6b65d347a9960961e5da52add18afd6 100644 (file)
--- 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
index d6372e52c2a1ad78b93e500497ff46cd08750506..6de650482ca905f9db82884711005153f6c04eb5 100644 (file)
@@ -1 +1 @@
-6ad5fc8e1a119b750a82fc1426704164a2042d57
\ No newline at end of file
+a2e1c35b327e33684ab19e5f65727c42c7b2949c
\ No newline at end of file
index daaf397069127a2053cb6d0d444daa66eca9d29d..4aa6538a44a2535ca888795db4ab89f582ff28de 100644 (file)
@@ -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 );
 
index 0ed2a7d175c21ae0ebaba9ae61dbd13b87be414f..43ee228424ab0cdc3f0ddbf25a86219d4d41c7e3 100644 (file)
@@ -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.
+    /* Open cursors for the table and indices we are deleting from. */
+    if( !isView ){
+      sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite);
+    }
+
+    /* Begin the database scan
     */
-    sqlite3VdbeAddOp(v, OP_ListRewind, 0, 0);
-    end = sqlite3VdbeMakeLabel(v);
+    pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, 0, isView?0:iCur);
+    if( pWInfo==0 ) goto delete_from_cleanup;
+    addr = pWInfo->iContinue;
 
-    /* This is the beginning of the delete loop when there are
-    ** row triggers.
+    /* 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);
+    /* 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);
 
-    /* If there are row triggers, close all cursors then invoke
-    ** the AFTER triggers
-    */
+    /* 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);
     }
   }
 
index 155ae9c0a248e24018f1ad0f3a2f6b9e106423a5..00ffa4060736e09d3b91d51445addbfb072bf018 100644 (file)
@@ -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
index 4f4e1b294ccebb4d256e7d3ddc673e2f76387a82..810aa622a0cd980b3a01cd635d5116899572a035 100644 (file)
@@ -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*);
index d53d86f77aca61c2ac971463926285981387100c..b56574cb6c1260485ef1c423f5d262d0b4d7a57b 100644 (file)
@@ -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.
index eb51bdfac8fb3f2cb925275584dace6ab164a4c6..f1a9a0c0b237fd54e94296a84a95156a5f0f2e21 100644 (file)
@@ -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);
index e45569a5b42090fc51e3c9d56a6aabfde352973e..2e5b0529ba963504345f372998c89247bbc6bd14 100644 (file)
 # 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:
-#
-# [num_to_string 456 10] -> "456.456.45"
+#-------------------------------------------------------------------------
+# 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).
 #
-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 {
index 0d7176fd1d5cb549f821c9e4835a0c5f87c4ca79..9ac8d724e86e978b77aaa0f700f2befb4ee67aa4 100644 (file)
@@ -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}
index 0e29d9a59a8d8ee9d47818d4c9869ae6666629cb..515577f74f5d45d86b271aceffcde8b6676a20e2 100644 (file)
@@ -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
index 064da17f77c107bf186b256fc9ad55a7fe370cbf..eb0d57928f8267841fe3c05a5de417935ad4ac2f 100644 (file)
@@ -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
index a89fa5639d96783ae4b3f489b92bda70bb358705..d004252b7090eef73db7f50ece919674b9a6aba3 100644 (file)
@@ -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.
index 9a2c9dba512a813bc1092c93e767af42f7e80770..c705c48f11c20959638572ded5e7bf20ab9bb630 100644 (file)
@@ -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.