Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Perform deletes in a single pass. (CVS 2104) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
a2e1c35b327e33684ab19e5f65727c42 |
User & Date: | danielk1977 2004-11-16 15:50:20.000 |
Context
2004-11-16
| ||
23:21 | Clarify the LIMIT clause in the documentation. Ticket #1002. (CVS 2105) (check-in: e05f52d907 user: drh tags: trunk) | |
15:50 | Perform deletes in a single pass. (CVS 2104) (check-in: a2e1c35b32 user: danielk1977 tags: trunk) | |
04:57 | Allow btree cursors to persist through BtreeDelete() calls. (CVS 2103) (check-in: 6ad5fc8e1a user: danielk1977 tags: trunk) | |
Changes
Changes to src/btree.c.
1 2 3 4 5 6 7 8 9 10 11 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | /* ** 2004 April 6 ** ** 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. ** ************************************************************************* ** $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 ** ** Donald E. Knuth, THE ART OF COMPUTER PROGRAMMING, Volume 3: ** "Sorting And Searching", pages 473-480. Addison-Wesley ** Publishing Company, Reading, Massachusetts. |
︙ | ︙ | |||
4303 4304 4305 4306 4307 4308 4309 | ** This routine checks all cursors that point to table pgnoRoot. ** If any of those cursors other than pExclude were opened with ** wrFlag==0 then this routine returns SQLITE_LOCKED. If all ** cursors that point to pgnoRoot were opened with wrFlag==1 ** then this routine returns SQLITE_OK. */ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ | < < < < < | 4303 4304 4305 4306 4307 4308 4309 4310 4311 4312 4313 4314 4315 4316 | ** This routine checks all cursors that point to table pgnoRoot. ** If any of those cursors other than pExclude were opened with ** wrFlag==0 then this routine returns SQLITE_LOCKED. If all ** cursors that point to pgnoRoot were opened with wrFlag==1 ** then this routine returns SQLITE_OK. */ static int checkReadLocks(Btree *pBt, Pgno pgnoRoot, BtCursor *pExclude){ return SQLITE_OK; } /* ** Insert a new record into the BTree. The key is given by (pKey,nKey) ** and the data is given by (pData,nData). The cursor is used only to ** define what table the record should be inserted into. The cursor |
︙ | ︙ | |||
4508 4509 4510 4511 4512 4513 4514 | ** next Cell after the one to be deleted is guaranteed to exist and ** to be a leaf so we can use it. Conveniantly, pCur now points ** at this cell (because it was advanced above). */ BtCursor leafCur; unsigned char *pNext; int szNext; | < | 4503 4504 4505 4506 4507 4508 4509 4510 4511 4512 4513 4514 4515 4516 | ** next Cell after the one to be deleted is guaranteed to exist and ** to be a leaf so we can use it. Conveniantly, pCur now points ** at this cell (because it was advanced above). */ BtCursor leafCur; unsigned char *pNext; int szNext; unsigned char *tempCell; assert( !pPage->leafData ); /* Make a copy of *pCur in leafCur. leafCur now points to the cell ** that will be moved into the space left by the cell being deleted. */ assert( pCur->delShift==1 ); |
︙ | ︙ |
Changes to src/delete.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle DELETE FROM statements. ** ** $Id: delete.c,v 1.89 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Look up every table that is named in pSrc. If any table is not found, ** add an error message to pParse->zErrMsg and return NULL. If all tables ** are found, return a pointer to the last table. |
︙ | ︙ | |||
60 61 62 63 64 65 66 | ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); VdbeComment((v, "# %s", pTab->zName)); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } | < | | 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 | ){ sqlite3VdbeAddOp(v, OP_Integer, pTab->iDb, 0); sqlite3VdbeAddOp(v, OP_OpenRead, iCur, pTab->tnum); VdbeComment((v, "# %s", pTab->zName)); sqlite3VdbeAddOp(v, OP_SetNumColumns, iCur, pTab->nCol); } /* ** Process a DELETE FROM statement. */ void sqlite3DeleteFrom( Parse *pParse, /* The parser context */ SrcList *pTabList, /* The table from which we should delete things */ Expr *pWhere /* The WHERE clause. May be null */ ){ 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 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 */ int iCur; /* VDBE Cursor number for pTab */ sqlite3 *db; /* Main database structure */ AuthContext sContext; /* Authorization context */ int oldIdx = -1; /* Cursor for the OLD table of AFTER triggers */ |
︙ | ︙ | |||
146 147 148 149 150 151 152 | /* Allocate a cursor used to store the old.* data for a trigger. */ if( row_triggers_exist ){ oldIdx = pParse->nTab++; } | | > > > > > | 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 | /* Allocate a cursor used to store the old.* data for a trigger. */ if( row_triggers_exist ){ oldIdx = pParse->nTab++; } /* 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; } /* Start the view context */ if( isView ){ |
︙ | ︙ | |||
223 224 225 226 227 228 229 | /* Ensure all required collation sequences are available. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ goto delete_from_cleanup; } } | < < < < < < < < < < < < < < < < > > > > | | < | > | < > | < < < < < < < < < < > | < < < < < | < | < < < | | | < | | < < | < < < < < < < | < < < | < < | | < < | 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 | /* Ensure all required collation sequences are available. */ for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ if( sqlite3CheckIndexCollSeq(pParse, pIdx) ){ goto delete_from_cleanup; } } /* Open the pseudo-table used to store OLD if there are triggers. */ if( row_triggers_exist ){ sqlite3VdbeAddOp(v, OP_OpenPseudo, oldIdx, 0); sqlite3VdbeAddOp(v, OP_SetNumColumns, oldIdx, pTab->nCol); } /* Open cursors for the table and indices we are deleting from. */ if( !isView ){ sqlite3OpenTableAndIndices(pParse, pTab, iCur, OP_OpenWrite); } /* 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 ){ sqlite3VdbeAddOp(v, OP_Recno, iCur, 0); sqlite3VdbeAddOp(v, OP_RowData, iCur, 0); sqlite3VdbeAddOp(v, OP_PutIntKey, oldIdx, 0); (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_BEFORE, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } /* 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 ){ (void)sqlite3CodeRowTrigger(pParse, TK_DELETE, 0, TK_AFTER, pTab, -1, oldIdx, (pParse->trigStack)?pParse->trigStack->orconf:OE_Default, addr); } /* 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); } } /* ** Return the number of rows that were deleted. If this routine is ** generating code because of a call to sqlite3NestedParse(), do not ** invoke the callback function. |
︙ | ︙ |
Changes to src/select.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle SELECT statements in SQLite. ** ** $Id: select.c,v 1.214 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Allocate a new Select structure and return a pointer to that ** structure. |
︙ | ︙ | |||
2519 2520 2521 2522 2523 2524 2525 | }else{ distinct = -1; } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, | | | 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 | }else{ distinct = -1; } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 0, pGroupBy ? 0 : &pOrderBy, -1); if( pWInfo==0 ) goto select_end; /* Use the standard inner loop if we are not dealing with ** aggregates */ if( !isAgg ){ if( selectInnerLoop(pParse, p, pEList, 0, 0, pOrderBy, distinct, eDest, |
︙ | ︙ |
Changes to src/sqliteInt.h.
1 2 3 4 5 6 7 8 9 10 11 12 13 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | /* ** 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. ** ************************************************************************* ** Internal interface definitions for SQLite. ** ** @(#) $Id: sqliteInt.h,v 1.340 2004/11/16 15:50:20 danielk1977 Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ /* ** These #defines should enable >2GB file support on Posix if the ** underlying operating system supports it. If the OS lacks |
︙ | ︙ | |||
1309 1310 1311 1312 1313 1314 1315 1316 1317 | Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,int,int); void sqlite3SelectDelete(Select*); void sqlite3SelectUnbind(Select*); Table *sqlite3SrcListLookup(Parse*, SrcList*); int sqlite3IsReadOnly(Parse*, Table*, int); void sqlite3OpenTableForReading(Vdbe*, int iCur, Table*); void sqlite3DeleteFrom(Parse*, SrcList*, Expr*); void sqlite3Update(Parse*, SrcList*, ExprList*, Expr*, int); | > | | 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 | Select *sqlite3SelectNew(ExprList*,SrcList*,Expr*,ExprList*,Expr*,ExprList*, int,int,int); void sqlite3SelectDelete(Select*); 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**, int); void sqlite3WhereEnd(WhereInfo*); void sqlite3ExprCode(Parse*, Expr*); int sqlite3ExprCodeExprList(Parse*, ExprList*); void sqlite3ExprIfTrue(Parse*, Expr*, int, int); void sqlite3ExprIfFalse(Parse*, Expr*, int, int); void sqlite3NextedParse(Parse*, const char*, ...); Table *sqlite3FindTable(sqlite3*,const char*, const char*); |
︙ | ︙ |
Changes to src/update.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This file contains C code routines that are called by the parser ** to handle UPDATE statements. ** ** $Id: update.c,v 1.95 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** Process an UPDATE statement. ** ** UPDATE OR IGNORE table_wxyz SET a=b, c=d WHERE e<5 AND f NOT NULL; |
︙ | ︙ | |||
231 232 233 234 235 236 237 | pView = sqlite3SelectDup(pTab->pSelect); sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Begin the database scan */ | | | 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 | pView = sqlite3SelectDup(pTab->pSelect); sqlite3Select(pParse, pView, SRT_TempTable, iCur, 0, 0, 0, 0); sqlite3SelectDelete(pView); } /* Begin the database scan */ pWInfo = sqlite3WhereBegin(pParse, pTabList, pWhere, 1, 0, -1); if( pWInfo==0 ) goto update_cleanup; /* Remember the index of every item to be updated. */ sqlite3VdbeAddOp(v, OP_ListWrite, 0, 0); /* End the database scan loop. |
︙ | ︙ |
Changes to src/where.c.
︙ | ︙ | |||
8 9 10 11 12 13 14 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** | | | 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | ** May you find forgiveness for yourself and forgive others. ** May you share freely, never taking more than you give. ** ************************************************************************* ** This module contains C code that generates VDBE code used to process ** the WHERE clause of SQL statements. ** ** $Id: where.c,v 1.117 2004/11/16 15:50:20 danielk1977 Exp $ */ #include "sqliteInt.h" /* ** The query generator uses an array of instances of this structure to ** help it analyze the subexpressions of the WHERE clause. Each WHERE ** clause subexpression is separated from the others by an AND operator. |
︙ | ︙ | |||
467 468 469 470 471 472 473 474 475 | ** scan is correct for the ORDER BY clause, then that index is used and ** *ppOrderBy is set to NULL. This is an optimization that prevents an ** unnecessary sort of the result set if an index appropriate for the ** ORDER BY clause already exists. ** ** If the where clause loops cannot be arranged to provide the correct ** output order, then the *ppOrderBy is unchanged. */ WhereInfo *sqlite3WhereBegin( | > > > > | | | | | > | 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 | ** scan is correct for the ORDER BY clause, then that index is used and ** *ppOrderBy is set to NULL. This is an optimization that prevents an ** unnecessary sort of the result set if an index appropriate for the ** ORDER BY clause already exists. ** ** 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 */ int iTabCur /* Cursor for pTabList->aSrc[0] */ ){ int i; /* Loop counter */ WhereInfo *pWInfo; /* Will become the return value of this function */ Vdbe *v = pParse->pVdbe; /* The virtual database engine */ int brk, cont = 0; /* Addresses used during code generation */ int nExpr; /* Number of subexpressions in the WHERE clause */ int loopMask; /* One bit set for each outer loop */ |
︙ | ︙ | |||
769 770 771 772 773 774 775 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ for(i=0; i<pTabList->nSrc; i++){ Table *pTab; Index *pIx; pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; | > | > | 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 | sqlite3CodeVerifySchema(pParse, -1); /* Insert the cookie verifier Goto */ for(i=0; i<pTabList->nSrc; i++){ Table *pTab; Index *pIx; pTab = pTabList->a[i].pTab; if( pTab->isTransient || pTab->pSelect ) continue; 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); sqlite3VdbeOp3(v, OP_OpenRead, pWInfo->a[i].iCur, pIx->tnum, (char*)&pIx->keyInfo, P3_KEYINFO); } } |
︙ | ︙ |
Changes to test/btree8.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend. Specifically, # this file tests that existing cursors are correctly repositioned # when entries are inserted into or deleted from btrees. # | | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | > > > > > > > > > > | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 | # #*********************************************************************** # This file implements regression tests for SQLite library. The # focus of this script is btree database backend. Specifically, # this file tests that existing cursors are correctly repositioned # when entries are inserted into or deleted from btrees. # # $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-0.0 { execsql { CREATE TABLE t1(a INTEGER PRIMARY KEY, b); CREATE INDEX i1 ON t1(b); } } {} 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] btree_begin_transaction $::bt expr 0 } {0} |
︙ | ︙ | |||
74 75 76 77 78 79 80 81 82 83 84 85 86 87 | foreach csr $csr_list key $keys { incr testnum do_test btree8-1.$i.$testnum { btree_key $::csr } $key } } # Now delete entries from the table. btree_first $::write_csr for {set i $first_entry} {$i < 5000 && $nErr==0 } {incr i} { do_test btree8-2.$i.1 { btree_key $::write_csr | > > > > > > > > | 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | foreach csr $csr_list key $keys { incr testnum do_test btree8-1.$i.$testnum { btree_key $::csr } $key } } #------------------------------------------------------------------------- # 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} { do_test btree8-2.$i.1 { btree_key $::write_csr |
︙ | ︙ | |||
99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 | } do_test btree8-2.$i.$testnum { btree_key $::csr } $key } } btree_close_cursor $::write_csr btree_commit $::bt if {$::nErr>0} { puts $::csr_list ; exit } foreach csr $csr_list { btree_close_cursor $csr } set csr_list [list] | > | | | | | < < < < | 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | } do_test btree8-2.$i.$testnum { btree_key $::csr } $key } } # Close all existing cursors and conclude the open transaction. btree_close_cursor $::write_csr btree_commit $::bt if {$::nErr>0} { puts $::csr_list ; exit } foreach csr $csr_list { btree_close_cursor $csr } set csr_list [list] #------------------------------------------------------------------------- # 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). # foreach key $keys { lappend skeys [num_to_string $key 20] } # For each element in the list $skeys, insert an entry into the SQL index # with the corresponding key value. Check that the cursor used to insert |
︙ | ︙ | |||
140 141 142 143 144 145 146 | btree_insert $csr $key "" lappend csr_list $csr btree_key $csr } $key } btree_commit $::bt | < < | 205 206 207 208 209 210 211 212 213 214 215 216 217 218 | btree_insert $csr $key "" lappend csr_list $csr btree_key $csr } $key } btree_commit $::bt # 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. btree_begin_transaction $::bt set ::write_csr [btree_cursor $::bt $::inum 1] set first_entry $testnum for {set i $testnum} {$i < 5000 && $nErr==0 } {incr i} { |
︙ | ︙ | |||
166 167 168 169 170 171 172 | btree_key $::csr } $key } } btree_commit $::bt btree_begin_transaction $::bt | < > | | < > | | < < < < < < < < < > < | 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | btree_key $::csr } $key } } btree_commit $::bt btree_begin_transaction $::bt #------------------------------------------------------------------------- # 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. for {set i $first_entry} {$i < 5000} {incr i} { lappend delete_order $i } set delete_order [lshuffle $delete_order] btree_first $::write_csr foreach i $delete_order { do_test btree8-4.$i.1 { btree_move_to $::write_csr [num_to_string $i 20] btree_key $::write_csr } [num_to_string $i 20] 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 { incr testnum if { [lsearch $delete_order $key]==-1 } { set skey "" } else { |
︙ | ︙ |
Changes to test/capi2.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2003 January 29 # # 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 script testing the callback-free C/C++ API. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2003 January 29 # # 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 script testing the callback-free C/C++ API. # # $Id: capi2.test,v 1.21 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # Return the text values from the current row pointed at by STMT as a list. proc get_row_values {STMT} { |
︙ | ︙ | |||
446 447 448 449 450 451 452 453 454 | } {} do_test capi2-6.12 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 5 {x counter}} do_test capi2-6.13 { catchsql {UPDATE t3 SET x=x+1} | > > > > > > > | | | | | | | | | | 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 | } {} do_test capi2-6.12 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [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} } {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 7 {x counter}} do_test capi2-6.15 { execsql {SELECT * FROM t1} } {1 2 3} do_test capi2-6.16 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 8 {x counter}} do_test capi2-6.17 { catchsql {UPDATE t1 SET b=b+1} } {0 {}} do_test capi2-6.18 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 9 {x counter}} do_test capi2-6.19 { execsql {SELECT * FROM t1} } {1 3 3} do_test capi2-6.20 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 10 {x counter}} #do_test capi2-6.21 { # execsql {ROLLBACK; SELECT * FROM t1} #} {1 2 3} do_test capi2-6.22 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 11 {x counter}} #do_test capi2-6.23 { # execsql {BEGIN TRANSACTION;} #} {} do_test capi2-6.24 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 12 {x counter}} do_test capi2-6.25 { execsql { INSERT INTO t1 VALUES(2,3,4); SELECT * FROM t1; } } {1 3 3 2 3 4} do_test capi2-6.26 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 13 {x counter}} do_test capi2-6.27 { catchsql { INSERT INTO t1 VALUES(2,4,5); SELECT * FROM t1; } } {1 {column a is not unique}} do_test capi2-6.28 { list [sqlite3_step $VM1] \ [sqlite3_column_count $VM1] \ [get_row_values $VM1] \ [get_column_names $VM1] } {SQLITE_ROW 1 14 {x counter}} do_test capi2-6.99 { sqlite3_finalize $VM1 } {SQLITE_OK} catchsql {ROLLBACK} do_test capi2-7.1 { stepsql $DB { |
︙ | ︙ |
Changes to test/capi3.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 2003 January 29 # # 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 script testing the callback-free C/C++ API. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 2003 January 29 # # 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 script testing the callback-free C/C++ API. # # $Id: capi3.test,v 1.24 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # Return the UTF-16 representation of the supplied UTF-8 string $str. # If $nt is true, append two 0x00 bytes as a nul terminator. |
︙ | ︙ | |||
755 756 757 758 759 760 761 762 763 764 765 | sqlite3_step $STMT } {SQLITE_ROW} do_test capi3-12.2 { catchsql { INSERT INTO t1 VALUES(3, NULL); } } {0 {}} do_test capi3-12.3 { catchsql { INSERT INTO t2 VALUES(4); } | > > > > > | > > > | | < | 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 | sqlite3_step $STMT } {SQLITE_ROW} do_test capi3-12.2 { catchsql { 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); } } {0 {}} do_test capi3-12.4 { catchsql { BEGIN; INSERT INTO t1 VALUES(4, NULL); } } {0 {}} do_test capi3-12.5 { sqlite3_step $STMT } {SQLITE_ROW} do_test capi3-12.6 { sqlite3_step $STMT } {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.9 { execsql { COMMIT; SELECT a FROM t1; } } {1 2 3 4} finish_test |
Changes to test/delete2.test.
︙ | ︙ | |||
25 26 27 28 29 30 31 | # index entry was deleted first, before the table entry. And the index # delete worked. Thus an entry was deleted from the index but not from # the table. # # The solution to the problem was to detect that the table is locked # before the index entry is deleted. # | | | 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | # index entry was deleted first, before the table entry. And the index # delete worked. Thus an entry was deleted from the index but not from # the table. # # The solution to the problem was to detect that the table is locked # before the index entry is deleted. # # $Id: delete2.test,v 1.3 2004/11/16 15:50:21 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # Create a table that has an index. # |
︙ | ︙ | |||
62 63 64 65 66 67 68 | # do_test delete2-1.4 { set STMT [sqlite3_prepare $DB {SELECT * FROM q} -1 TAIL] sqlite3_step $STMT } SQLITE_ROW integrity_check delete2-1.5 | | > > | | < < < | | | 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 | # do_test delete2-1.4 { set STMT [sqlite3_prepare $DB {SELECT * FROM q} -1 TAIL] sqlite3_step $STMT } SQLITE_ROW integrity_check delete2-1.5 # 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 } } {0 {}} integrity_check delete2-1.7 do_test delete2-1.8 { execsql { SELECT * FROM q; } } {goodbye id.2 again id.3} do_test delete2-1.9 { sqlite3_finalize $STMT catchsql { DELETE FROM q WHERE rowid=2 } } {0 {}} integrity_check delete2-1.10 do_test delete2-1.11 { execsql { SELECT * FROM q; } } {again id.3} finish_test |
Changes to test/lock.test.
1 2 3 4 5 6 7 8 9 10 11 12 13 | # 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 script is database locks. # | | | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | # 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 script is database locks. # # $Id: lock.test,v 1.28 2004/11/16 15:50:21 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl # Create an alternative connection to the database # |
︙ | ︙ | |||
94 95 96 97 98 99 100 | do_test lock-1.17 { db eval {SELECT * FROM t1} qv { set x [db eval {SELECT * FROM t2}] } set x } {8 9} | | | > | | | | < > | | | 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 | do_test lock-1.17 { db eval {SELECT * FROM t1} qv { set x [db eval {SELECT * FROM t2}] } set x } {8 9} # 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}} # But you can UPDATE a different table from the one that is used in # the SELECT. # do_test lock-1.19 { db eval {SELECT * FROM t1} qv { set r [catch {db eval {UPDATE t2 SET x=y, y=x}} msg] |
︙ | ︙ |
Changes to test/misc2.test.
︙ | ︙ | |||
9 10 11 12 13 14 15 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for miscellanous features that were # left out of other test files. # | | | 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | # #*********************************************************************** # This file implements regression tests for SQLite library. # # This file implements tests for miscellanous features that were # left out of other test files. # # $Id: misc2.test,v 1.14 2004/11/16 15:50:21 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl ifcapable {trigger} { # Test for ticket #360 # |
︙ | ︙ | |||
127 128 129 130 131 132 133 | execsql { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); SELECT * FROM t1; } } {1 2} | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 127 128 129 130 131 132 133 134 135 136 137 138 139 140 | execsql { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2); SELECT * FROM t1; } } {1 2} # 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. # do_test misc2-8.1 { catchsql {-} } {1 {near "-": syntax error}} |
︙ | ︙ |