Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch cacheflush Excluding Merge-Ins
This is equivalent to a diff from 00185418 to a6695b00
2015-10-30
| ||
16:14 | Add new API function sqlite3_db_cacheflush(). (check-in: ad80d307 user: dan tags: trunk) | |
14:28 | Return immediately if sqlite3PagerWrite() is called when the pager is in PAGER_ERROR state. (Closed-Leaf check-in: a6695b00 user: dan tags: cacheflush) | |
09:13 | Test that calling sqlite3_db_cacheflush() does not interfere with savepoints. (check-in: 0e09e4a2 user: dan tags: cacheflush) | |
2015-10-28
| ||
20:01 | Make the internal sqlite3PExpr() interface responsive to the TKFLG_DONTFOLD flag on the operator parameter. (check-in: b10ab59f user: drh tags: trunk) | |
19:46 | Add experimental API sqlite3_db_cacheflush(). (check-in: 65b86dc1 user: dan tags: cacheflush) | |
16:05 | Factor out adding NOT expression nodes in the parser into a subroutine. (check-in: 00185418 user: drh tags: trunk) | |
2015-10-27
| ||
20:04 | Have contentless and external content fts5 tables ignore "OR REPLACE" conflict handling. (check-in: a85c2a47 user: dan tags: trunk) | |
Changes to src/main.c.
︙ | ︙ | |||
735 736 737 738 739 740 741 742 743 744 745 746 747 748 | sqlite3PagerShrink(pPager); } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Configuration settings for an individual database connection */ int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 | sqlite3PagerShrink(pPager); } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return SQLITE_OK; } /* ** Flush any dirty pages in the pager-cache for any attached database ** to disk. */ int sqlite3_db_cacheflush(sqlite3 *db){ int i; int rc = SQLITE_OK; int bSeenBusy = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ) return SQLITE_MISUSE_BKPT; #endif sqlite3_mutex_enter(db->mutex); sqlite3BtreeEnterAll(db); for(i=0; rc==SQLITE_OK && i<db->nDb; i++){ Btree *pBt = db->aDb[i].pBt; if( pBt && sqlite3BtreeIsInTrans(pBt) ){ Pager *pPager = sqlite3BtreePager(pBt); rc = sqlite3PagerFlush(pPager); if( rc==SQLITE_BUSY ){ bSeenBusy = 1; rc = SQLITE_OK; } } } sqlite3BtreeLeaveAll(db); sqlite3_mutex_leave(db->mutex); return ((rc==SQLITE_OK && bSeenBusy) ? SQLITE_BUSY : rc); } /* ** Configuration settings for an individual database connection */ int sqlite3_db_config(sqlite3 *db, int op, ...){ va_list ap; int rc; |
︙ | ︙ |
Changes to src/pager.c.
︙ | ︙ | |||
4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 | PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno)); sqlite3PcacheMakeClean(pPg); } return pager_error(pPager, rc); } /* ** Allocate and initialize a new Pager object and put a pointer to it ** in *ppPager. The pager should eventually be freed by passing it ** to sqlite3PagerClose(). ** ** The zFilename argument is the path to the database file to open. | > > > > > > > > > > > > > > > > > > > | 4469 4470 4471 4472 4473 4474 4475 4476 4477 4478 4479 4480 4481 4482 4483 4484 4485 4486 4487 4488 4489 4490 4491 4492 4493 4494 4495 4496 4497 4498 4499 4500 4501 | PAGERTRACE(("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno)); sqlite3PcacheMakeClean(pPg); } return pager_error(pPager, rc); } /* ** Flush all unreferenced dirty pages to disk. */ int sqlite3PagerFlush(Pager *pPager){ int rc = pPager->errCode; if( !MEMDB ){ PgHdr *pList = sqlite3PcacheDirtyList(pPager->pPCache); assert( assert_pager_state(pPager) ); while( rc==SQLITE_OK && pList ){ PgHdr *pNext = pList->pDirty; if( pList->nRef==0 ){ rc = pagerStress((void*)pPager, pList); } pList = pNext; } } return rc; } /* ** Allocate and initialize a new Pager object and put a pointer to it ** in *ppPager. The pager should eventually be freed by passing it ** to sqlite3PagerClose(). ** ** The zFilename argument is the path to the database file to open. |
︙ | ︙ | |||
5892 5893 5894 5895 5896 5897 5898 | ** If an error occurs, SQLITE_NOMEM or an IO error code is returned ** as appropriate. Otherwise, SQLITE_OK. */ int sqlite3PagerWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( (pPg->flags & PGHDR_MMAP)==0 ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); | < > > | | 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 5928 | ** If an error occurs, SQLITE_NOMEM or an IO error code is returned ** as appropriate. Otherwise, SQLITE_OK. */ int sqlite3PagerWrite(PgHdr *pPg){ Pager *pPager = pPg->pPager; assert( (pPg->flags & PGHDR_MMAP)==0 ); assert( pPager->eState>=PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( pPager->errCode ){ return pPager->errCode; }else if( (pPg->flags & PGHDR_WRITEABLE)!=0 && pPager->dbSize>=pPg->pgno ){ if( pPager->nSavepoint ) return subjournalPageIfRequired(pPg); return SQLITE_OK; }else if( pPager->sectorSize > (u32)pPager->pageSize ){ return pagerWriteLargeSector(pPg); }else{ return pager_write(pPg); } |
︙ | ︙ | |||
6072 6073 6074 6075 6076 6077 6078 | ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. ** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ int sqlite3PagerExclusiveLock(Pager *pPager){ | > > | | | | | | | | > | 6092 6093 6094 6095 6096 6097 6098 6099 6100 6101 6102 6103 6104 6105 6106 6107 6108 6109 6110 6111 6112 6113 6114 6115 6116 | ** ** If the EXCLUSIVE lock is already held or the attempt to obtain it is ** successful, or the connection is in WAL mode, SQLITE_OK is returned. ** Otherwise, either SQLITE_BUSY or an SQLITE_IOERR_XXX error code is ** returned. */ int sqlite3PagerExclusiveLock(Pager *pPager){ int rc = pPager->errCode; assert( assert_pager_state(pPager) ); if( rc==SQLITE_OK ){ assert( pPager->eState==PAGER_WRITER_CACHEMOD || pPager->eState==PAGER_WRITER_DBMOD || pPager->eState==PAGER_WRITER_LOCKED ); assert( assert_pager_state(pPager) ); if( 0==pagerUseWal(pPager) ){ rc = pager_wait_on_lock(pPager, EXCLUSIVE_LOCK); } } return rc; } /* ** Sync the database file for the pager pPager. zMaster points to the name ** of a master journal file that should be written into the individual |
︙ | ︙ |
Changes to src/pager.h.
︙ | ︙ | |||
128 129 130 131 132 133 134 135 136 137 138 139 140 141 | void sqlite3PagerSetFlags(Pager*,unsigned); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); int sqlite3PagerGetJournalMode(Pager*); int sqlite3PagerOkToChangeJournalMode(Pager*); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); sqlite3_backup **sqlite3PagerBackupPtr(Pager*); /* Functions used to obtain and release page references. */ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); void sqlite3PagerRef(DbPage*); void sqlite3PagerUnref(DbPage*); | > | 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 | void sqlite3PagerSetFlags(Pager*,unsigned); int sqlite3PagerLockingMode(Pager *, int); int sqlite3PagerSetJournalMode(Pager *, int); int sqlite3PagerGetJournalMode(Pager*); int sqlite3PagerOkToChangeJournalMode(Pager*); i64 sqlite3PagerJournalSizeLimit(Pager *, i64); sqlite3_backup **sqlite3PagerBackupPtr(Pager*); int sqlite3PagerFlush(Pager*); /* Functions used to obtain and release page references. */ int sqlite3PagerAcquire(Pager *pPager, Pgno pgno, DbPage **ppPage, int clrFlag); #define sqlite3PagerGet(A,B,C) sqlite3PagerAcquire(A,B,C,0) DbPage *sqlite3PagerLookup(Pager *pPager, Pgno pgno); void sqlite3PagerRef(DbPage*); void sqlite3PagerUnref(DbPage*); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 | ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. ** ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double | > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 7788 7789 7790 7791 7792 7793 7794 7795 7796 7797 7798 7799 7800 7801 7802 7803 7804 7805 7806 7807 7808 7809 7810 7811 7812 7813 7814 7815 7816 7817 7818 7819 7820 7821 7822 7823 7824 7825 7826 7827 7828 7829 7830 | ** ^Zero all [sqlite3_stmt_scanstatus()] related event counters. ** ** This API is only available if the library is built with pre-processor ** symbol [SQLITE_ENABLE_STMT_SCANSTATUS] defined. */ void sqlite3_stmt_scanstatus_reset(sqlite3_stmt*); /* ** CAPI3REF: Flush caches to disk mid-transaction ** ** If a write-transaction is open when this function is called, any dirty ** pages in the pager-cache that are not currently in use are written out ** to disk. A dirty page may be in use if a database cursor created by an ** active SQL statement is reading from it, or if it is page 1 of a database ** file (page 1 is always "in use"). Dirty pages are flushed for all ** databases - "main", "temp" and any attached databases. ** ** If this function needs to obtain extra database locks before dirty pages ** can be flushed to disk, it does so. If said locks cannot be obtained ** immediately and there is a busy-handler callback configured, it is invoked ** in the usual manner. If the required lock still cannot be obtained, then ** the database is skipped and an attempt made to flush any dirty pages ** belonging to the next (if any) database. If any databases are skipped ** because locks cannot be obtained, but no other error occurs, this ** function returns SQLITE_BUSY. ** ** If any other error occurs while flushing dirty pages to disk (for ** example an IO error or out-of-memory condition), then processing is ** abandoned and an SQLite error code returned to the caller immediately. ** ** Otherwise, if no error occurs, SQLITE_OK is returned. ** ** This function does not set the database handle error code or message ** returned by the sqlite3_errcode() and sqlite3_errmsg() functions. */ int sqlite3_db_cacheflush(sqlite3*); /* ** Undo the hack that converts floating point types to integer for ** builds on processors without floating point support. */ #ifdef SQLITE_OMIT_FLOATING_POINT # undef double |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_db_release_memory(db); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_db_filename DB DBNAME ** ** Return the name of a file associated with a database. */ static int test_db_filename( | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 4683 4684 4685 4686 4687 4688 4689 4690 4691 4692 4693 4694 4695 4696 4697 4698 4699 4700 4701 4702 4703 4704 4705 4706 4707 4708 4709 4710 4711 4712 4713 4714 4715 4716 4717 4718 4719 4720 4721 4722 4723 4724 | return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_db_release_memory(db); Tcl_SetObjResult(interp, Tcl_NewIntObj(rc)); return TCL_OK; } /* ** Usage: sqlite3_db_cacheflush DB ** ** Attempt to flush any dirty pages to disk. */ static int test_db_cacheflush( void * clientData, Tcl_Interp *interp, int objc, Tcl_Obj *CONST objv[] ){ sqlite3 *db; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "DB"); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; rc = sqlite3_db_cacheflush(db); if( rc ){ Tcl_SetResult(interp, (char *)sqlite3ErrStr(rc), TCL_STATIC); return TCL_ERROR; } Tcl_ResetResult(interp); return TCL_OK; } /* ** Usage: sqlite3_db_filename DB DBNAME ** ** Return the name of a file associated with a database. */ static int test_db_filename( |
︙ | ︙ | |||
6872 6873 6874 6875 6876 6877 6878 6879 6880 6881 6882 6883 6884 6885 | { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, { "sqlite3_db_filename", test_db_filename, 0}, { "sqlite3_db_readonly", test_db_readonly, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, | > | 6900 6901 6902 6903 6904 6905 6906 6907 6908 6909 6910 6911 6912 6913 6914 | { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, { "uses_stmt_journal", uses_stmt_journal ,0 }, { "sqlite3_release_memory", test_release_memory, 0}, { "sqlite3_db_release_memory", test_db_release_memory, 0}, { "sqlite3_db_cacheflush", test_db_cacheflush, 0}, { "sqlite3_db_filename", test_db_filename, 0}, { "sqlite3_db_readonly", test_db_readonly, 0}, { "sqlite3_soft_heap_limit", test_soft_heap_limit, 0}, { "sqlite3_thread_cleanup", test_thread_cleanup, 0}, { "sqlite3_pager_refcounts", test_pager_refcounts, 0}, { "sqlite3_load_extension", test_load_extension, 0}, |
︙ | ︙ |
Added test/cacheflush.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 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 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 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 | # 2011 November 16 # # 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 contains test cases for sqlite3_db_cacheflush API. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix cacheflush test_set_config_pagecache 0 0 # Run the supplied SQL on a copy of the database currently stored on # disk in file $dbfile. proc diskquery {dbfile sql} { forcecopy $dbfile dq.db sqlite3 dq dq.db set res [execsql $sql dq] dq close set res } # Simplest possible test. # do_execsql_test 1.1.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); BEGIN; INSERT INTO t1 VALUES(3, 4); } do_test 1.1.1 { diskquery test.db { SELECT * FROM t1 } } {1 2} do_test 1.1.2 { sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1 } } {1 2 3 4} # Test that multiple pages may be flushed to disk. # do_execsql_test 1.2.0 { COMMIT; CREATE TABLE t2(a, b); BEGIN; INSERT INTO t1 VALUES(5, 6); INSERT INTO t2 VALUES('a', 'b'); } do_test 1.2.1 { diskquery test.db { SELECT * FROM t1; SELECT * FROM t2; } } {1 2 3 4} do_test 1.2.2 { sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1; SELECT * FROM t2; } } {1 2 3 4 5 6 a b} # Test that pages with nRef!=0 are not flushed to disk. # do_execsql_test 1.3.0 { COMMIT; CREATE TABLE t3(a, b); BEGIN; INSERT INTO t1 VALUES(7, 8); INSERT INTO t2 VALUES('c', 'd'); INSERT INTO t3 VALUES('i', 'ii'); } do_test 1.3.1 { diskquery test.db { SELECT * FROM t1; SELECT * FROM t2; SELECT * FROM t3; } } {1 2 3 4 5 6 a b} do_test 1.3.2 { db eval { SELECT a FROM t1 } { if {$a==3} { sqlite3_db_cacheflush db } } diskquery test.db { SELECT * FROM t1; SELECT * FROM t2; SELECT * FROM t3; } } {1 2 3 4 5 6 a b c d i ii} do_test 1.3.2 { sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1; SELECT * FROM t2; SELECT * FROM t3; } } {1 2 3 4 5 6 7 8 a b c d i ii} # Check that SQLITE_BUSY is returned if pages cannot be flushed due to # conflicting read locks. # do_execsql_test 1.4.0 { COMMIT; BEGIN; INSERT INTO t1 VALUES(9, 10); } do_test 1.4.1 { sqlite3 db2 test.db db2 eval { BEGIN; SELECT * FROM t1; } diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8} do_test 1.4.2 { list [catch { sqlite3_db_cacheflush db } msg] $msg } {1 {database is locked}} do_test 1.4.3 { diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8} do_test 1.4.4 { db2 close sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10} do_execsql_test 1.4.5 { COMMIT } #------------------------------------------------------------------------- # Test that ATTACHed database caches are also flushed. # forcedelete test.db2 do_execsql_test 2.1.0 { ATTACH 'test.db2' AS aux; CREATE TABLE aux.t4(x, y); INSERT INTO t4 VALUES('A', 'B'); BEGIN; INSERT INTO t1 VALUES(11, 12); INSERT INTO t4 VALUES('C', 'D'); } do_test 2.1.1 { diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10} do_test 2.1.2 { diskquery test.db2 { SELECT * FROM t4; } } {A B} do_test 2.1.3 { sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 2.1.4 { sqlite3_db_cacheflush db diskquery test.db2 { SELECT * FROM t4; } } {A B C D} do_execsql_test 2.1.5 { COMMIT } # And that hitting an SQLITE_BUSY when flushing "main" does not stop # SQLite from going on to flush "aux". # do_execsql_test 2.2.0 { BEGIN; INSERT INTO t1 VALUES(13, 14); INSERT INTO t4 VALUES('E', 'F'); } do_test 2.2.1 { diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 2.2.2 { diskquery test.db2 { SELECT * FROM t4; } } {A B C D} do_test 2.2.3 { sqlite3 db2 test.db execsql { BEGIN; SELECT * FROM t1; } db2 list [catch { sqlite3_db_cacheflush db } msg] $msg } {1 {database is locked}} do_test 2.2.4 { diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10 11 12} do_test 2.2.5 { diskquery test.db2 { SELECT * FROM t4; } } {A B C D E F} do_test 2.2.6 { db2 close sqlite3_db_cacheflush db diskquery test.db { SELECT * FROM t1; } } {1 2 3 4 5 6 7 8 9 10 11 12 13 14} do_execsql_test 2.2.7 { COMMIT } #------------------------------------------------------------------------- # Test that nothing terrible happens if sqlite3_db_cacheflush() is # called on an in-memory database. # do_test 3.0 { db close sqlite3 db :memory: db eval { CREATE TABLE t1(x PRIMARY KEY); CREATE TABLE t2(y PRIMARY KEY); BEGIN; INSERT INTO t1 VALUES(randomblob(100)); INSERT INTO t2 VALUES(randomblob(100)); INSERT INTO t1 VALUES(randomblob(100)); INSERT INTO t2 VALUES(randomblob(100)); } sqlite3_db_cacheflush db } {} do_execsql_test 3.1 { PRAGMA integrity_check } ok do_execsql_test 3.2 { COMMIT } do_execsql_test 3.3 { PRAGMA integrity_check } ok do_execsql_test 3.4 { SELECT count(*) FROM t1; SELECT count(*) FROM t2; } {2 2} #------------------------------------------------------------------------- # Test that calling sqlite3_db_cacheflush() does not interfere with # savepoint transactions. # do_test 4.0 { reset_db execsql { CREATE TABLE ta(a, aa); CREATE TABLE tb(b, bb); INSERT INTO ta VALUES('a', randomblob(500)); INSERT INTO tb VALUES('b', randomblob(500)); BEGIN; UPDATE ta SET a = 'A'; SAVEPOINT one; UPDATE tb SET b = 'B'; } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A B} do_test 4.1 { execsql { ROLLBACK TO one; } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A b} do_test 4.2 { execsql { INSERT INTO tb VALUES('c', randomblob(10)); INSERT INTO tb VALUES('d', randomblob(10)); INSERT INTO tb VALUES('e', randomblob(10)); } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A b c d e} do_test 4.3 { execsql { SAVEPOINT two; UPDATE tb SET b = upper(b); } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A B C D E} do_test 4.4 { execsql { ROLLBACK TO two; } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A b c d e} do_test 4.4 { execsql { ROLLBACK TO one; } sqlite3_db_cacheflush db diskquery test.db { SELECT a FROM ta; SELECT b FROM tb; } } {A b} do_test 4.5 { execsql { ROLLBACK; SELECT a FROM ta; SELECT b FROM tb; } } {a b} test_restore_config_pagecache finish_test |
Added test/cffault.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 | # 2011 November 16 # # 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 contains fault-injection test cases for the # sqlite3_db_cacheflush API. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix cacheflush source $testdir/malloc_common.tcl # Run the supplied SQL on a copy of the database currently stored on # disk in file $dbfile. proc diskquery {dbfile sql} { forcecopy $dbfile dq.db sqlite3 dq dq.db set res [execsql $sql dq] dq close set res } do_execsql_test 1.0 { CREATE TABLE t1(a PRIMARY KEY, b); CREATE INDEX i1 ON t1(b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); } faultsim_save_and_close do_faultsim_test 1.1 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b+1; } } -body { sqlite3_db_cacheflush db } -test { if {[sqlite3_get_autocommit db]} { error "Transaction rolled back!" } faultsim_test_result {0 {}} {1 {disk I/O error}} catch { db eval COMMIT } faultsim_integrity_check } do_faultsim_test 1.2 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b+1; } } -body { set result [list] db eval { SELECT * FROM t1 } { if {$a==5} { catch { sqlite3_db_cacheflush db } } lappend result $a $b } set result } -test { faultsim_test_result {0 {1 3 3 5 5 7 7 9}} {1 {disk I/O error}} catch { db eval COMMIT } faultsim_integrity_check } #------------------------------------------------------------------------- reset_db do_execsql_test 2.0 { CREATE TABLE t1(a PRIMARY KEY, b, c); CREATE INDEX i1 ON t1(b); CREATE INDEX i2 ON t1(c, b); INSERT INTO t1 VALUES(1, 2, randomblob(600)); INSERT INTO t1 VALUES(3, 4, randomblob(600)); INSERT INTO t1 VALUES(5, 6, randomblob(600)); INSERT INTO t1 VALUES(7, 8, randomblob(600)); INSERT INTO t1 VALUES(9, 10, randomblob(600)); } faultsim_save_and_close do_faultsim_test 2.1 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b+1; } } -body { set result [list] db eval { SELECT * FROM t1 } { if {$a==5} { catch { sqlite3_db_cacheflush db } } lappend result $a $b } set result } -test { faultsim_test_result {0 {1 3 3 5 5 7 7 9 9 11}} {1 {disk I/O error}} catch { db eval { INSERT INTO t1 VALUES(11, 12, randomblob(600)) } } catch { db eval COMMIT } faultsim_integrity_check } do_faultsim_test 2.2 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b+1; } } -body { sqlite3_db_cacheflush db } -test { if {[sqlite3_get_autocommit db]} { error "Transaction rolled back!" } faultsim_test_result {0 {}} {1 {disk I/O error}} catch { db eval { SELECT * FROM t1 } } catch { db eval COMMIT } faultsim_integrity_check } do_faultsim_test 2.3 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b-1; } } -body { sqlite3_db_cacheflush db } -test { if {[sqlite3_get_autocommit db]} { error "Transaction rolled back!" } faultsim_test_result {0 {}} {1 {disk I/O error}} catch { db eval { INSERT INTO t1 VALUES(11, 12, randomblob(600)) } } catch { db eval COMMIT } faultsim_integrity_check } do_faultsim_test 2.4 -prep { faultsim_restore_and_reopen db eval { BEGIN; UPDATE t1 SET b=b-1; } } -body { catch { sqlite3_db_cacheflush db } catch { sqlite3_db_release_memory db } catch { sqlite3_db_cacheflush db } execsql { SELECT a, b FROM t1 } } -test { faultsim_test_result {0 {1 1 3 3 5 5 7 7 9 9}} {1 {disk I/O error}} catchsql ROLLBACK faultsim_integrity_check } finish_test |