SQLite

Check-in [2fa05d01b6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve coverage of pager.c.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 2fa05d01b6b11788a5b73d203fcac9d4a4ba9fd8
User & Date: dan 2010-08-11 18:56:46.000
Context
2010-08-12
02:41
Increase the maximum page size from 32k to 64k. (check-in: 45362437d4 user: drh tags: trunk)
2010-08-11
18:56
Improve coverage of pager.c. (check-in: 2fa05d01b6 user: dan tags: trunk)
12:26
Update an r-tree extension test case to account for recent changes to the query planner. Also fix a comment in rtree.c. (check-in: eaaca669a4 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
269
270
271
272
273
274
275
276
277
278
279



280
281
282
283
284
285
286
**    * All writing and syncing of journal and database data has finished.
**      If no error occured, all that remains is to finalize the journal to
**      commit the transaction. If an error did occur, the caller will need
**      to rollback the transaction. 
**
**  ERROR:
**
**    The ERROR state is entered when an IO, OOM or disk-full error 
**    occurs at a point in the code that makes it difficult to be sure
**    that the in-memory pager state (cache contents, db size etc.) are
**    consistent with the contents of the file-system.



**
**    For example, if an IO error occurs while performing a rollback, 
**    the contents of the page-cache may be left in an inconsistent state.
**    At this point it would be dangerous to change back to READER state
**    (as usually happens after a rollback). Any subsequent readers might
**    report database corruption (due to the inconsistent cache), and if
**    they upgrade to writers, they may inadvertently corrupt the database







|
|
|
|
>
>
>







269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
**    * All writing and syncing of journal and database data has finished.
**      If no error occured, all that remains is to finalize the journal to
**      commit the transaction. If an error did occur, the caller will need
**      to rollback the transaction. 
**
**  ERROR:
**
**    The ERROR state is entered when an IO or disk-full error (including
**    SQLITE_IOERR_NOMEM) occurs at a point in the code that makes it 
**    difficult to be sure that the in-memory pager state (cache contents, 
**    db size etc.) are consistent with the contents of the file-system.
**
**    Temporary pager files may enter the ERROR state, but in-memory pagers
**    cannot.
**
**    For example, if an IO error occurs while performing a rollback, 
**    the contents of the page-cache may be left in an inconsistent state.
**    At this point it would be dangerous to change back to READER state
**    (as usually happens after a rollback). Any subsequent readers might
**    report database corruption (due to the inconsistent cache), and if
**    they upgrade to writers, they may inadvertently corrupt the database
319
320
321
322
323
324
325

326
327
328
329
330
331
332
**    automatically attempt a rollback, as it assumes that an error in a
**    read-only statement cannot leave the pager in an internally inconsistent 
**    state.
**
**    * The Pager.errCode variable is set to something other than SQLITE_OK.
**    * There are one or more outstanding references to pages (after the
**      last reference is dropped the pager should move back to OPEN state).

**    
**
** Notes:
**
**   * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the
**     connection is open in WAL mode. A WAL connection is always in one
**     of the first four states.







>







322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
**    automatically attempt a rollback, as it assumes that an error in a
**    read-only statement cannot leave the pager in an internally inconsistent 
**    state.
**
**    * The Pager.errCode variable is set to something other than SQLITE_OK.
**    * There are one or more outstanding references to pages (after the
**      last reference is dropped the pager should move back to OPEN state).
**    * The pager is not an in-memory pager.
**    
**
** Notes:
**
**   * A pager is never in WRITER_DBMOD or WRITER_FINISHED state if the
**     connection is open in WAL mode. A WAL connection is always in one
**     of the first four states.
821
822
823
824
825
826
827
828








829






830
831
832
833
834
835
836

  /* If the useJournal flag is clear, the journal-mode must be "OFF". 
  ** And if the journal-mode is "OFF", the journal file must not be open.
  */
  assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
  assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );

  /* Check that MEMDB implies noSync. */








  assert( !MEMDB || p->noSync );







  /* If changeCountDone is set, a RESERVED lock or greater must be held
  ** on the file.
  */
  assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
  assert( p->eLock!=PENDING_LOCK );








|
>
>
>
>
>
>
>
>
|
>
>
>
>
>
>







825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854

  /* If the useJournal flag is clear, the journal-mode must be "OFF". 
  ** And if the journal-mode is "OFF", the journal file must not be open.
  */
  assert( p->journalMode==PAGER_JOURNALMODE_OFF || p->useJournal );
  assert( p->journalMode!=PAGER_JOURNALMODE_OFF || !isOpen(p->jfd) );

  /* Check that MEMDB implies noSync. And an in-memory journal. Since 
  ** this means an in-memory pager performs no IO at all, it cannot encounter 
  ** either SQLITE_IOERR or SQLITE_FULL during rollback or while finalizing 
  ** a journal file. (although the in-memory journal implementation may 
  ** return SQLITE_IOERR_NOMEM while the journal file is being written). It 
  ** is therefore not possible for an in-memory pager to enter the ERROR 
  ** state.
  */
  if( MEMDB ){
    assert( p->noSync );
    assert( p->journalMode==PAGER_JOURNALMODE_OFF 
         || p->journalMode==PAGER_JOURNALMODE_MEMORY 
    );
    assert( p->eState!=PAGER_ERROR && p->eState!=PAGER_OPEN );
    assert( pagerUseWal(p)==0 );
  }

  /* If changeCountDone is set, a RESERVED lock or greater must be held
  ** on the file.
  */
  assert( pPager->changeCountDone==0 || pPager->eLock>=RESERVED_LOCK );
  assert( p->eLock!=PENDING_LOCK );

1755
1756
1757
1758
1759
1760
1761
1762

1763
1764
1765
1766
1767
1768
1769
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.
  */
  if( pPager->errCode && !MEMDB ){

    pager_reset(pPager);
    pPager->changeCountDone = pPager->tempFile;
    pPager->eState = PAGER_OPEN;
    pPager->errCode = SQLITE_OK;
  }

  pPager->journalOff = 0;







|
>







1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
  }

  /* If Pager.errCode is set, the contents of the pager cache cannot be
  ** trusted. Now that there are no outstanding references to the pager,
  ** it can safely move back to PAGER_OPEN state. This happens in both
  ** normal and exclusive-locking mode.
  */
  if( pPager->errCode ){
    assert( !MEMDB );
    pager_reset(pPager);
    pPager->changeCountDone = pPager->tempFile;
    pPager->eState = PAGER_OPEN;
    pPager->errCode = SQLITE_OK;
  }

  pPager->journalOff = 0;
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576

2577
2578
2579
2580
2581
2582
2583
  u32 u;                   /* Unsigned loop counter */
  Pgno mxPg = 0;           /* Size of the original file in pages */
  int rc;                  /* Result code of a subroutine */
  int res = 1;             /* Value returned by sqlite3OsAccess() */
  char *zMaster = 0;       /* Name of master journal file if any */
  int needPagerReset;      /* True to reset page prior to first page rollback */

  if( !isOpen(pPager->jfd) ){
    return SQLITE_OK;
  }

  /* Figure out how many records are in the journal.  Abort early if
  ** the journal is empty.
  */

  rc = sqlite3OsFileSize(pPager->jfd, &szJ);
  if( rc!=SQLITE_OK || szJ==0 ){
    goto end_playback;
  }

  /* Read the master journal name from the journal, if it is present.
  ** If a master journal file name is specified, but the file is not







<
<
<
<



>







2582
2583
2584
2585
2586
2587
2588




2589
2590
2591
2592
2593
2594
2595
2596
2597
2598
2599
  u32 u;                   /* Unsigned loop counter */
  Pgno mxPg = 0;           /* Size of the original file in pages */
  int rc;                  /* Result code of a subroutine */
  int res = 1;             /* Value returned by sqlite3OsAccess() */
  char *zMaster = 0;       /* Name of master journal file if any */
  int needPagerReset;      /* True to reset page prior to first page rollback */





  /* Figure out how many records are in the journal.  Abort early if
  ** the journal is empty.
  */
  assert( isOpen(pPager->jfd) );
  rc = sqlite3OsFileSize(pPager->jfd, &szJ);
  if( rc!=SQLITE_OK || szJ==0 ){
    goto end_playback;
  }

  /* Read the master journal name from the journal, if it is present.
  ** If a master journal file name is specified, but the file is not
3337
3338
3339
3340
3341
3342
3343
3344
3345
3346
3347
3348





3349
3350
3351
3352
3353
3354
3355
3356
3357
3358
3359
3360
3361
3362
3363
3364
3365
3366
3367
3368
3369
3370
3371
3372
3373
3374
3375
3376

3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
**
** If the page size is not changed, either because one of the enumerated
** conditions above is not true, the pager was in error state when this
** function was called, or because the memory allocation attempt failed, 
** then *pPageSize is set to the old, retained page size before returning.
*/
int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){
  int rc = pPager->errCode;

  /* It is not possible to do a full assert_pager_state() here, as this
  ** function may be called from within PagerOpen(), before the state
  ** of the Pager object is internally consistent.





  */
  assert( rc==SQLITE_OK || pPager->eState==PAGER_ERROR );

  if( rc==SQLITE_OK ){
    u16 pageSize = *pPageSize;
    assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
    if( (pPager->memDb==0 || pPager->dbSize==0)
     && sqlite3PcacheRefCount(pPager->pPCache)==0 
     && pageSize && pageSize!=pPager->pageSize 
    ){
      char *pNew;                 /* New temp space */
      i64 nByte = 0;
      if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
        rc = sqlite3OsFileSize(pPager->fd, &nByte);
        if( rc!=SQLITE_OK ) return rc;
      }
      pNew = (char *)sqlite3PageMalloc(pageSize);
      if( !pNew ){
        rc = SQLITE_NOMEM;
      }else{
        pager_reset(pPager);
        pPager->dbSize = nByte/pageSize;
        pPager->pageSize = pageSize;
        sqlite3PageFree(pPager->pTmpSpace);
        pPager->pTmpSpace = pNew;
        sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
      }
    }

    *pPageSize = (u16)pPager->pageSize;
    if( nReserve<0 ) nReserve = pPager->nReserve;
    assert( nReserve>=0 && nReserve<1000 );
    pPager->nReserve = (i16)nReserve;
    pagerReportSize(pPager);
  }
  return rc;
}

/*
** Return a pointer to the "temporary page" buffer held internally
** by the pager.  This is a buffer that is big enough to hold the
** entire content of a database page.  This buffer is used internally
** during rollback and will be overwritten whenever a rollback







<
<



>
>
>
>
>

<

<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
<
|







3353
3354
3355
3356
3357
3358
3359


3360
3361
3362
3363
3364
3365
3366
3367
3368

3369

3370
3371
3372
3373
3374
3375
3376
3377
3378
3379
3380
3381
3382
3383
3384
3385
3386
3387
3388
3389
3390
3391
3392
3393
3394
3395
3396
3397
3398
3399

3400
3401
3402
3403
3404
3405
3406
3407
**
** If the page size is not changed, either because one of the enumerated
** conditions above is not true, the pager was in error state when this
** function was called, or because the memory allocation attempt failed, 
** then *pPageSize is set to the old, retained page size before returning.
*/
int sqlite3PagerSetPagesize(Pager *pPager, u16 *pPageSize, int nReserve){


  /* It is not possible to do a full assert_pager_state() here, as this
  ** function may be called from within PagerOpen(), before the state
  ** of the Pager object is internally consistent.
  **
  ** At one point this function returned an error if the pager was in 
  ** PAGER_ERROR state. But since PAGER_ERROR state guarantees that
  ** there is at least one outstanding page reference, this function
  ** is a no-op for that case anyhow.
  */



  u16 pageSize = *pPageSize;
  assert( pageSize==0 || (pageSize>=512 && pageSize<=SQLITE_MAX_PAGE_SIZE) );
  if( (pPager->memDb==0 || pPager->dbSize==0)
   && sqlite3PcacheRefCount(pPager->pPCache)==0 
   && pageSize && pageSize!=pPager->pageSize 
  ){
    char *pNew;                 /* New temp space */
    i64 nByte = 0;
    if( pPager->eState>PAGER_OPEN && isOpen(pPager->fd) ){
      int rc = sqlite3OsFileSize(pPager->fd, &nByte);
      if( rc!=SQLITE_OK ) return rc;
    }
    pNew = (char *)sqlite3PageMalloc(pageSize);
    if( !pNew ){
      return SQLITE_NOMEM;
    }else{
      pager_reset(pPager);
      pPager->dbSize = nByte/pageSize;
      pPager->pageSize = pageSize;
      sqlite3PageFree(pPager->pTmpSpace);
      pPager->pTmpSpace = pNew;
      sqlite3PcacheSetPageSize(pPager->pPCache, pageSize);
    }
  }

  *pPageSize = (u16)pPager->pageSize;
  if( nReserve<0 ) nReserve = pPager->nReserve;
  assert( nReserve>=0 && nReserve<1000 );
  pPager->nReserve = (i16)nReserve;
  pagerReportSize(pPager);

  return SQLITE_OK;
}

/*
** Return a pointer to the "temporary page" buffer held internally
** by the pager.  This is a buffer that is big enough to hold the
** entire content of a database page.  This buffer is used internally
** during rollback and will be overwritten whenever a rollback
4739
4740
4741
4742
4743
4744
4745

4746
4747
4748

4749
4750
4751
4752
4753
4754
4755
4756
4757

4758
4759
4760
4761
4762
4763
4764
      }
    }

    /* If there is a WAL file in the file-system, open this database in WAL
    ** mode. Otherwise, the following function call is a no-op.
    */
    rc = pagerOpenWalIfPresent(pPager);

  }

  if( pagerUseWal(pPager) && rc==SQLITE_OK ){

    rc = pagerBeginReadTransaction(pPager);
  }

  if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    rc = pagerPagecount(pPager, &pPager->dbSize);
  }

 failed:
  if( rc!=SQLITE_OK ){

    pager_unlock(pPager);
    assert( pPager->eState==PAGER_OPEN );
  }else{
    pPager->eState = PAGER_READER;
  }
  return rc;
}







>


|
>









>







4756
4757
4758
4759
4760
4761
4762
4763
4764
4765
4766
4767
4768
4769
4770
4771
4772
4773
4774
4775
4776
4777
4778
4779
4780
4781
4782
4783
4784
      }
    }

    /* If there is a WAL file in the file-system, open this database in WAL
    ** mode. Otherwise, the following function call is a no-op.
    */
    rc = pagerOpenWalIfPresent(pPager);
    assert( pPager->pWal==0 || rc==SQLITE_OK );
  }

  if( pagerUseWal(pPager) ){
    assert( rc==SQLITE_OK );
    rc = pagerBeginReadTransaction(pPager);
  }

  if( pPager->eState==PAGER_OPEN && rc==SQLITE_OK ){
    rc = pagerPagecount(pPager, &pPager->dbSize);
  }

 failed:
  if( rc!=SQLITE_OK ){
    assert( !MEMDB );
    pager_unlock(pPager);
    assert( pPager->eState==PAGER_OPEN );
  }else{
    pPager->eState = PAGER_READER;
  }
  return rc;
}
5076
5077
5078
5079
5080
5081
5082
5083
5084
5085
5086
5087
5088
5089
5090
** or using a temporary file otherwise.
*/
int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
  int rc = SQLITE_OK;
  assert( pPager->eState>=PAGER_READER );
  pPager->subjInMemory = (u8)subjInMemory;

  if( pPager->eState==PAGER_READER ){
    assert( pPager->pInJournal==0 );

    if( pagerUseWal(pPager) ){
      /* If the pager is configured to use locking_mode=exclusive, and an
      ** exclusive lock on the database is not already held, obtain it now.
      */
      if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){







|







5096
5097
5098
5099
5100
5101
5102
5103
5104
5105
5106
5107
5108
5109
5110
** or using a temporary file otherwise.
*/
int sqlite3PagerBegin(Pager *pPager, int exFlag, int subjInMemory){
  int rc = SQLITE_OK;
  assert( pPager->eState>=PAGER_READER );
  pPager->subjInMemory = (u8)subjInMemory;

  if( ALWAYS(pPager->eState==PAGER_READER) ){
    assert( pPager->pInJournal==0 );

    if( pagerUseWal(pPager) ){
      /* If the pager is configured to use locking_mode=exclusive, and an
      ** exclusive lock on the database is not already held, obtain it now.
      */
      if( pPager->exclusiveMode && sqlite3WalExclusiveMode(pPager->pWal, -1) ){
Changes to test/pager1.test.
1058
1059
1060
1061
1062
1063
1064




1065
1066
1067
1068
1069
1070
1071
} {13}
do_execsql_test pager1-6.8 {
    INSERT INTO t11 VALUES(3, 4);
    PRAGMA max_page_count = 10;
} {11}
do_execsql_test pager1-6.9 { COMMIT } {}






#-------------------------------------------------------------------------
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
# "PRAGMA locking_mode=EXCLUSIVE".
#
# Each test is specified with 5 variables. As follows:
#







>
>
>
>







1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
} {13}
do_execsql_test pager1-6.8 {
    INSERT INTO t11 VALUES(3, 4);
    PRAGMA max_page_count = 10;
} {11}
do_execsql_test pager1-6.9 { COMMIT } {}

do_execsql_test pager1-6.10 { PRAGMA max_page_count = 10 } {10}
do_execsql_test pager1-6.11 { SELECT * FROM t11 }          {1 2 3 4}
do_execsql_test pager1-6.12 { PRAGMA max_page_count }      {11}


#-------------------------------------------------------------------------
# The following tests work with "PRAGMA journal_mode=TRUNCATE" and
# "PRAGMA locking_mode=EXCLUSIVE".
#
# Each test is specified with 5 variables. As follows:
#
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
      PRAGMA omit_readlock = 1;
      ATTACH 'test.db' AS two;
      BEGIN;
      SELECT * FROM t1;
    }
  } {1 2 3 4 5 6}
  do_test pager1-17.$tn.3.2 {
    csql1 { INSERT INTO t1 VALUES(3, 4) }
  } {1 {database is locked}}
  do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
}

#-------------------------------------------------------------------------
# Test the pagers response to the b-tree layer requesting illegal page 
# numbers:







|







1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
      PRAGMA omit_readlock = 1;
      ATTACH 'test.db' AS two;
      BEGIN;
      SELECT * FROM t1;
    }
  } {1 2 3 4 5 6}
  do_test pager1-17.$tn.3.2 {
  csql1 { INSERT INTO t1 VALUES(3, 4) }
  } {1 {database is locked}}
  do_test pager1-17.$tn.3.3 { sql2 COMMIT } {}
}

#-------------------------------------------------------------------------
# Test the pagers response to the b-tree layer requesting illegal page 
# numbers:
2228
2229
2230
2231
2232
2233
2234

2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245

























2246
do_execsql_test pager1-26.1 {
  UPDATE tbl SET b = a_string(550);
} {}
db close
tv delete

#-------------------------------------------------------------------------

do_test pager1.27.1 {
  faultsim_delete_and_reopen
  sqlite3_pager_refcounts db
  execsql {
    BEGIN;
      CREATE TABLE t1(a, b);
  }
  sqlite3_pager_refcounts db
  execsql COMMIT
} {}


























finish_test







>











>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
do_execsql_test pager1-26.1 {
  UPDATE tbl SET b = a_string(550);
} {}
db close
tv delete

#-------------------------------------------------------------------------
#
do_test pager1.27.1 {
  faultsim_delete_and_reopen
  sqlite3_pager_refcounts db
  execsql {
    BEGIN;
      CREATE TABLE t1(a, b);
  }
  sqlite3_pager_refcounts db
  execsql COMMIT
} {}

#-------------------------------------------------------------------------
# Test that attempting to open a write-transaction with 
# locking_mode=exclusive in WAL mode fails if there are other clients on 
# the same database.
#
catch { db close }
do_multiclient_test tn {
  do_test pager1-28.$tn.1 {
    sql1 { 
      PRAGMA journal_mode = WAL;
      CREATE TABLE t1(a, b);
      INSERT INTO t1 VALUES('a', 'b');
    }
  } {wal}
  do_test pager1-28.$tn.2 { sql2 { SELECT * FROM t1 } } {a b}

  do_test pager1-28.$tn.3 { sql1 { PRAGMA locking_mode=exclusive } } {exclusive}
  do_test pager1-28.$tn.4 { 
    csql1 { BEGIN; INSERT INTO t1 VALUES('c', 'd'); }
  } {1 {database is locked}}
  code2 { db2 close ; sqlite3 db2 test.db }
  do_test pager1-28.$tn.4 { 
    sql1 { INSERT INTO t1 VALUES('c', 'd'); COMMIT }
  } {}
}
finish_test
Changes to test/pager2.test.
112
113
114
115
116
117
118

















119
      } [list $x ok]
    }
  }
}
db close
tv delete


















finish_test







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

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
      } [list $x ok]
    }
  }
}
db close
tv delete


#-------------------------------------------------------------------------
# Test a ROLLBACK with journal_mode=off.
#
breakpoint
do_test pager2-2.1 {
  faultsim_delete_and_reopen
  execsql {
    CREATE TABLE t1(a, b);
    PRAGMA journal_mode = off;
    BEGIN;
      INSERT INTO t1 VALUES(1, 2);
    ROLLBACK;
    SELECT * FROM t1;
  }
} {off 1 2}

finish_test
Changes to test/pagerfault.test.
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  faultsim_save_and_close
} {}
do_faultsim_test pagerfault-1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { SELECT count(*) FROM t1 }
} -test {
  faultsim_test_result {0 4}
  faultsim_integrity_check
  if {[db one { SELECT count(*) FROM t1 }] != 4} {
    error "Database content appears incorrect"
  }
}

#-------------------------------------------------------------------------







|







48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
  faultsim_save_and_close
} {}
do_faultsim_test pagerfault-1 -prep {
  faultsim_restore_and_reopen
} -body {
  execsql { SELECT count(*) FROM t1 }
} -test {
  faultsim_test_result {0 4} 
  faultsim_integrity_check
  if {[db one { SELECT count(*) FROM t1 }] != 4} {
    error "Database content appears incorrect"
  }
}

#-------------------------------------------------------------------------
1073
1074
1075
1076
1077
1078
1079
1080














































1081
} -body {
  execsql { INSERT INTO t2 VALUES(2) }
  execsql { SELECT * FROM t2 }
} -test {
  faultsim_test_result {0 {1 2}}
  faultsim_integrity_check
}















































finish_test








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
} -body {
  execsql { INSERT INTO t2 VALUES(2) }
  execsql { SELECT * FROM t2 }
} -test {
  faultsim_test_result {0 {1 2}}
  faultsim_integrity_check
}

#-------------------------------------------------------------------------
# Provoke an OOM error during a commit of multi-file transaction. One of
# the databases written during the transaction is an in-memory database.
# This test causes rollback of the in-memory database after CommitPhaseOne()
# has successfully returned. i.e. the series of calls for the aborted commit 
# is:
#
#   PagerCommitPhaseOne(<in-memory-db>)   ->   SQLITE_OK
#   PagerCommitPhaseOne(<file-db>)        ->   SQLITE_IOERR
#   PagerRollback(<in-memory-db>)
#   PagerRollback(<file-db>)
#
do_faultsim_test pagerfault-23 -prep {
  foreach f [glob -nocomplain test.db*] { file delete -force $f }
  sqlite3 db :memory:
  db eval { 
    ATTACH 'test.db2' AS aux;
    CREATE TABLE t1(a, b);
    CREATE TABLE aux.t2(a, b);
  }
} -body {
  execsql { 
    BEGIN;
      INSERT INTO t1 VALUES(1,2);
      INSERT INTO t2 VALUES(3,4); 
    COMMIT;
  }
} -test {
  faultsim_test_result {0 {}}
  faultsim_integrity_check
}

do_faultsim_test pagerfault-24 -prep {
  faultsim_delete_and_reopen
  db eval { PRAGMA temp_store = file }
  execsql { CREATE TABLE x(a, b) }
} -body {
  execsql { CREATE TEMP TABLE t1(a, b) }
} -test {
  faultsim_test_result {0 {}} {1 {unable to open a temporary database file for storing temporary tables}}
  set ic [db eval { PRAGMA temp.integrity_check }]
  if {$ic != "ok"} { error "Integrity check: $ic" }
}



finish_test