Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Test cases and corrections to IO and malloc() error handling in incremental blob IO functions. (CVS 3915) |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
641e55284e1ba6070073c83ac6ed78ff |
User & Date: | danielk1977 2007-05-04 12:05:56.000 |
Context
2007-05-04
| ||
13:15 | Eliminate all uses of sprintf() and strcpy(). These were not being misused. But getting rid of them removes a library dependency. And it avoids warnings from the OpenBSD compiler. Ticket #2336. (CVS 3916) (check-in: ba4845b32b user: drh tags: trunk) | |
12:05 | Test cases and corrections to IO and malloc() error handling in incremental blob IO functions. (CVS 3915) (check-in: 641e55284e user: danielk1977 tags: trunk) | |
12:01 | Fix a formatting errror in I/O logging. (CVS 3914) (check-in: 2d37687a08 user: drh 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.372 2007/05/04 12:05:56 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. |
︙ | ︙ | |||
652 653 654 655 656 657 658 659 660 661 662 663 664 665 | } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. */ static int saveCursorPosition(BtCursor *pCur){ int rc; | > > > > > > > > > > > > > > > > > > > > > > > > | 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 | } } } #endif /* SQLITE_OMIT_SHARED_CACHE */ static void releasePage(MemPage *pPage); /* Forward reference */ #ifndef SQLITE_OMIT_INCRBLOB /* ** Invalidate the overflow page-list cache for cursor pCur, if any. */ static void invalidateOverflowCache(BtCursor *pCur){ sqliteFree(pCur->aOverflow); pCur->aOverflow = 0; } /* ** Invalidate the overflow page-list cache for all cursors opened ** on the shared btree structure pBt. */ static void invalidateAllOverflowCache(BtShared *pBt){ BtCursor *p; for(p=pBt->pCursor; p; p=p->pNext){ invalidateOverflowCache(p); } } #else #define invalidateOverflowCache(x) #define invalidateAllOverflowCache(x) #endif /* ** Save the current cursor position in the variables BtCursor.nKey ** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK. */ static int saveCursorPosition(BtCursor *pCur){ int rc; |
︙ | ︙ | |||
691 692 693 694 695 696 697 | if( rc==SQLITE_OK ){ releasePage(pCur->pPage); pCur->pPage = 0; pCur->eState = CURSOR_REQUIRESEEK; } | < < < < < | | 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 | if( rc==SQLITE_OK ){ releasePage(pCur->pPage); pCur->pPage = 0; pCur->eState = CURSOR_REQUIRESEEK; } invalidateOverflowCache(pCur); return rc; } /* ** Save the positions of all cursors except pExcept open on the table ** with root-page iRoot. Usually, this is called just before cursor ** pExcept is used to modify the table (BtreeDelete() or BtreeInsert()). |
︙ | ︙ | |||
2419 2420 2421 2422 2423 2424 2425 | ** ** If the incremental vacuum is finished after this function has run, ** SQLITE_DONE is returned. If it is not finished, but no error occured, ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ BtShared *pBt = p->pBt; | < < < < < < | < < < < < < < < < < | | 2438 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 | ** ** If the incremental vacuum is finished after this function has run, ** SQLITE_DONE is returned. If it is not finished, but no error occured, ** SQLITE_OK is returned. Otherwise an SQLite error code. */ int sqlite3BtreeIncrVacuum(Btree *p){ BtShared *pBt = p->pBt; assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE ); if( !pBt->autoVacuum ){ return SQLITE_DONE; } invalidateAllOverflowCache(pBt); return incrVacuumStep(pBt, 0); } /* ** This routine is called prior to sqlite3PagerCommit when a transaction ** is commited for an auto-vacuum database. ** ** If SQLITE_OK is returned, then *pnTrunc is set to the number of pages ** the database file should be truncated to during the commit process. ** i.e. the database has been reorganized so that only the first *pnTrunc ** pages are in use. */ static int autoVacuumCommit(BtShared *pBt, Pgno *pnTrunc){ int rc = SQLITE_OK; Pager *pPager = pBt->pPager; #ifndef NDEBUG int nRef = sqlite3PagerRefcount(pPager); #endif invalidateAllOverflowCache(pBt); assert(pBt->autoVacuum); if( !pBt->incrVacuum ){ Pgno nFin = 0; if( pBt->nTrunc==0 ){ Pgno nFree; Pgno nPtrmap; |
︙ | ︙ | |||
2955 2956 2957 2958 2959 2960 2961 | pBt->pCursor = pCur->pNext; } if( pCur->pNext ){ pCur->pNext->pPrev = pCur->pPrev; } releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); | < | < | 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 2969 2970 2971 2972 | pBt->pCursor = pCur->pNext; } if( pCur->pNext ){ pCur->pNext->pPrev = pCur->pPrev; } releasePage(pCur->pPage); unlockBtreeIfUnused(pBt); invalidateOverflowCache(pCur); sqliteFree(pCur); return SQLITE_OK; } /* ** Make a temporary cursor by filling in the fields of pTempCur. ** The temporary cursor is not on the cursor list for the Btree. |
︙ | ︙ | |||
5797 5798 5799 5800 5801 5802 5803 | rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); if( rc ) return rc; #else if( pBt->autoVacuum ){ Pgno pgnoMove; /* Move a page here to make room for the root-page */ MemPage *pPageMove; /* The page to move to. */ | < < < < | < < | 5798 5799 5800 5801 5802 5803 5804 5805 5806 5807 5808 5809 5810 5811 5812 5813 5814 5815 5816 5817 | rc = allocateBtreePage(pBt, &pRoot, &pgnoRoot, 1, 0); if( rc ) return rc; #else if( pBt->autoVacuum ){ Pgno pgnoMove; /* Move a page here to make room for the root-page */ MemPage *pPageMove; /* The page to move to. */ /* Creating a new table may probably require moving an existing database ** to make room for the new tables root page. In case this page turns ** out to be an overflow page, delete all overflow page-map caches ** held by open cursors. */ invalidateAllOverflowCache(pBt); /* Read the value of meta[3] from the database to determine where the ** root page of the new table should go. meta[3] is the largest root-page ** created so far, so the new root-page is (meta[3]+1). */ rc = sqlite3BtreeGetMeta(p, 4, &pgnoRoot); if( rc!=SQLITE_OK ) return rc; |
︙ | ︙ |
Changes to src/tclsqlite.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. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of 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. ** ************************************************************************* ** A TCL Interface to SQLite. Append this file to sqlite3.c and ** compile the whole thing to build a TCL-enabled version of SQLite. ** ** $Id: tclsqlite.c,v 1.183 2007/05/04 12:05:56 danielk1977 Exp $ */ #include "tcl.h" #include <errno.h> /* ** Some additional include files are needed if this file is not ** appended to the amalgamation. |
︙ | ︙ | |||
149 150 151 152 153 154 155 | } /* ** Close an incremental blob channel. */ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){ IncrblobChannel *p = (IncrblobChannel *)instanceData; | | > > > > > > > | 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 | } /* ** Close an incremental blob channel. */ static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){ IncrblobChannel *p = (IncrblobChannel *)instanceData; int rc = sqlite3_blob_close(p->pBlob); sqlite3 *db = p->pDb->db; /* Remove the channel from the SqliteDb.pIncrblob list. */ if( p->pNext ){ p->pNext->pPrev = p->pPrev; } if( p->pPrev ){ p->pPrev->pNext = p->pNext; } if( p->pDb->pIncrblob==p ){ p->pDb->pIncrblob = p->pNext; } /* Free the IncrblobChannel structure */ Tcl_Free((char *)p); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } /* ** Read data from an incremental blob channel. */ static int incrblobInput( |
︙ | ︙ |
Changes to src/vdbeaux.c.
︙ | ︙ | |||
460 461 462 463 464 465 466 | } /* ** Change N opcodes starting at addr to No-ops. */ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ | > | | | | | | > | 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 | } /* ** Change N opcodes starting at addr to No-ops. */ void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){ if( p && p->aOp ){ VdbeOp *pOp = &p->aOp[addr]; while( N-- ){ freeP3(pOp->p3type, pOp->p3); memset(pOp, 0, sizeof(pOp[0])); pOp->opcode = OP_Noop; pOp++; } } } /* ** Change the value of the P3 operand for a specific instruction. ** This routine is useful when a large program is loaded from a ** static array using sqlite3VdbeAddOpList but we want to make a |
︙ | ︙ |
Changes to src/vdbeblob.c.
1 2 3 4 5 6 7 8 9 10 11 12 | /* ** 2007 May 1 ** ** 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 20 | /* ** 2007 May 1 ** ** 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: vdbeblob.c,v 1.6 2007/05/04 12:05:56 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" #ifndef SQLITE_OMIT_INCRBLOB |
︙ | ︙ | |||
166 167 168 169 170 171 172 | ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ sqlite3VdbeChangeP2(v, 5, pTab->nCol+1); | > | > | | | 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 | ** think that the table has one more column than it really ** does. An OP_Column to retrieve this imaginary column will ** always return an SQL NULL. This is useful because it means ** we can invoke OP_Column to fill in the vdbe cursors type ** and offset cache without causing any IO. */ sqlite3VdbeChangeP2(v, 5, pTab->nCol+1); if( !sqlite3MallocFailed() ){ sqlite3VdbeMakeReady(v, 1, 0, 1, 0); } } rc = sqlite3SafetyOff(db); if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ goto blob_open_out; } sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow); rc = sqlite3_step((sqlite3_stmt *)v); if( rc!=SQLITE_ROW ){ nAttempt++; rc = sqlite3_finalize((sqlite3_stmt *)v); |
︙ | ︙ | |||
218 219 220 221 222 223 224 225 226 227 | rc = SQLITE_OK; }else if( rc==SQLITE_OK ){ sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow); rc = SQLITE_ERROR; } blob_open_out: if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ sqlite3_finalize((sqlite3_stmt *)v); } | > < | | | > > | < > > | > > | < > > | | 220 221 222 223 224 225 226 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 | rc = SQLITE_OK; }else if( rc==SQLITE_OK ){ sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow); rc = SQLITE_ERROR; } blob_open_out: zErr[sizeof(zErr)-1] = '\0'; if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ sqlite3_finalize((sqlite3_stmt *)v); } sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr)); return sqlite3ApiExit(db, rc); } /* ** Close a blob handle. */ int sqlite3_blob_close(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; sqlite3_stmt *pStmt = p->pStmt; sqliteFree(p); return sqlite3_finalize(pStmt); } /* ** Read data from a blob handle. */ int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){ int rc = SQLITE_ERROR; Incrblob *p = (Incrblob *)pBlob; Vdbe *v = (Vdbe *)(p->pStmt); if( (iOffset+n)<=p->nByte ){ rc = sqlite3BtreeData(p->pCsr, iOffset+p->iOffset, n, z); } v->rc = rc; return sqlite3ApiExit(v->db, v->rc); } /* ** Write data to a blob handle. */ int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){ int rc = SQLITE_ERROR; Incrblob *p = (Incrblob *)pBlob; Vdbe *v = (Vdbe *)(p->pStmt); if( (iOffset+n)<=p->nByte ){ rc = sqlite3BtreePutData(p->pCsr, iOffset+p->iOffset, n, z); } v->rc = rc; return sqlite3ApiExit(v->db, v->rc); } /* ** Query a blob handle for the size of the data. */ int sqlite3_blob_bytes(sqlite3_blob *pBlob){ Incrblob *p = (Incrblob *)pBlob; return p->nByte; } #endif /* #ifndef SQLITE_OMIT_INCRBLOB */ |
Added test/incrblob_err.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 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 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 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 | # 2007 May 1 # # 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: incrblob_err.test,v 1.1 2007/05/04 12:05:56 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl # Usage: do_malloc_test <test number> <options...> # # The first argument, <test number>, is an integer used to name the # tests executed by this proc. Options are as follows: # # -tclprep TCL script to run to prepare test. # -sqlprep SQL script to run to prepare test. # -tclbody TCL script to run with malloc failure simulation. # -sqlbody TCL script to run with malloc failure simulation. # -cleanup TCL script to run after the test. # # This command runs a series of tests to verify SQLite's ability # to handle an out-of-memory condition gracefully. It is assumed # that if this condition occurs a malloc() call will return a # NULL pointer. Linux, for example, doesn't do that by default. See # the "BUGS" section of malloc(3). # # Each iteration of a loop, the TCL commands in any argument passed # to the -tclbody switch, followed by the SQL commands in any argument # passed to the -sqlbody switch are executed. Each iteration the # Nth call to sqliteMalloc() is made to fail, where N is increased # each time the loop runs starting from 1. When all commands execute # successfully, the loop ends. # proc do_malloc_test {tn args} { array unset ::mallocopts array set ::mallocopts $args set ::go 1 for {set ::n 1} {$::go && $::n < 50000} {incr ::n} { do_test incrblob_err-$tn.$::n { # Remove all traces of database files test.db and test2.db from the files # system. Then open (empty database) "test.db" with the handle [db]. # sqlite_malloc_fail 0 catch {db close} catch {file delete -force test.db} catch {file delete -force test.db-journal} catch {file delete -force test2.db} catch {file delete -force test2.db-journal} catch {sqlite3 db test.db} set ::DB [sqlite3_connection_pointer db] # Execute any -tclprep and -sqlprep scripts. # if {[info exists ::mallocopts(-tclprep)]} { eval $::mallocopts(-tclprep) } if {[info exists ::mallocopts(-sqlprep)]} { execsql $::mallocopts(-sqlprep) } # Now set the ${::n}th malloc() to fail and execute the -tclbody and # -sqlbody scripts. # sqlite_malloc_fail $::n set ::mallocbody {} if {[info exists ::mallocopts(-tclbody)]} { append ::mallocbody "$::mallocopts(-tclbody)\n" } if {[info exists ::mallocopts(-sqlbody)]} { append ::mallocbody "db eval {$::mallocopts(-sqlbody)}" } set v [catch $::mallocbody msg] # If the test fails (if $v!=0) and the database connection actually # exists, make sure the failure code is SQLITE_NOMEM. if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)] && [db errorcode]!=7} { set v 999 } set leftover [lindex [sqlite_malloc_stat] 2] if {$leftover>0} { if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} set ::go 0 if {$v} { puts "\nError message returned: $msg" } else { set v {1 1} } } else { set v2 [expr {$msg=="" || $msg=="out of memory"}] if {!$v2} {puts "\nError message returned: $msg"} lappend v $v2 } } {1 1} if {[info exists ::mallocopts(-cleanup)]} { catch [list uplevel #0 $::mallocopts(-cleanup)] msg } } unset ::mallocopts } set ::fd [open [info script]] set ::data [read $::fd] close $::fd do_malloc_test 1 -tclprep { set bytes [file size [info script]] execsql { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, zeroblob($::bytes)); } } -tclbody { set ::blob [db incrblob blobs v 1] set rc [catch {puts -nonewline $::blob $::data}] if {$rc} { error "out of memory" } } do_malloc_test 2 -tclprep { execsql { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, $::data); } } -tclbody { set ::blob [db incrblob blobs v 1] set rc [catch {set ::r [read $::blob]}] if {$rc} { error "out of memory" } elseif {$::r ne $::data} { error "Bad data read..." } } do_malloc_test 3 -tclprep { execsql { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, $::data); } } -tclbody { set ::blob [db incrblob blobs v 1] set rc [catch {set ::r [read $::blob]}] if {$rc} { error "out of memory" } elseif {$::r ne $::data} { error "Bad data read..." } set rc [catch {close $::blob}] if {$rc} { error "out of memory" } } sqlite_malloc_fail 0 do_ioerr_test incrblob_err-4 -cksum 1 -sqlprep { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, $::data); } -tclbody { set ::blob [db incrblob blobs v 1] read $::blob } do_ioerr_test incrblob_err-5 -cksum 1 -sqlprep { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, zeroblob(length(CAST($::data AS BLOB)))); } -tclbody { set ::blob [db incrblob blobs v 1] puts -nonewline $::blob $::data close $::blob } do_ioerr_test incrblob_err-6 -cksum 1 -sqlprep { CREATE TABLE blobs(k, v BLOB); INSERT INTO blobs VALUES(1, $::data || $::data || $::data); } -tclbody { set ::blob [db incrblob blobs v 1] seek $::blob -20 end puts -nonewline $::blob "12345678900987654321" close $::blob } finish_test |
Changes to test/tester.tcl.
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 some common TCL routines used for regression # testing the SQLite library # | | | 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 some common TCL routines used for regression # testing the SQLite library # # $Id: tester.tcl,v 1.81 2007/05/04 12:05:56 danielk1977 Exp $ # Make sure tclsqlite3 was compiled correctly. Abort now with an # error message if not. # if {[sqlite3 -tcl-uses-utf]} { if {"\u1234"=="u1234"} { puts stderr "***** BUILD PROBLEM *****" |
︙ | ︙ | |||
395 396 397 398 399 400 401 | set ::ioerropts(-erc) 0 set ::ioerropts(-count) 100000000 set ::ioerropts(-persist) 1 array set ::ioerropts $args set ::go 1 for {set n $::ioerropts(-start)} {$::go} {incr n} { | | | 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 | set ::ioerropts(-erc) 0 set ::ioerropts(-count) 100000000 set ::ioerropts(-persist) 1 array set ::ioerropts $args set ::go 1 for {set n $::ioerropts(-start)} {$::go} {incr n} { set ::TN $n incr ::ioerropts(-count) -1 if {$::ioerropts(-count)<0} break # Skip this IO error if it was specified with the "-exclude" option. if {[info exists ::ioerropts(-exclude)]} { if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue } |
︙ | ︙ | |||
476 477 478 479 480 481 482 483 484 485 486 487 488 489 | set s [expr $::sqlite_io_error_hit==0] set ::sqlite_io_error_hit 0 # One of two things must have happened. either # 1. We never hit the IO error and the SQL returned OK # 2. An IO error was hit and the SQL failed # expr { ($s && !$r && !$::go) || (!$s && $r && $::go) } } {1} # If an IO error occured, then the checksum of the database should # be the same as before the script that caused the IO error was run. if {$::go && $::ioerropts(-cksum)} { do_test $testname.$n.4 { | > | 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 | set s [expr $::sqlite_io_error_hit==0] set ::sqlite_io_error_hit 0 # One of two things must have happened. either # 1. We never hit the IO error and the SQL returned OK # 2. An IO error was hit and the SQL failed # #puts "$s $r $::go - $msg" expr { ($s && !$r && !$::go) || (!$s && $r && $::go) } } {1} # If an IO error occured, then the checksum of the database should # be the same as before the script that caused the IO error was run. if {$::go && $::ioerropts(-cksum)} { do_test $testname.$n.4 { |
︙ | ︙ |