SQLite

Check-in [95c69dfbdd]
Login

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

Overview
Comment:If you delete a database file but not its *-wal file, then open the database (thus creating a new empty database file) the *-wal file is automatically deleted.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 95c69dfbddaf4367cd699dfe8fcf8e06030c1f53
User & Date: drh 2010-07-01 19:45:35.000
Context
2010-07-02
01:18
Add a NEVER to sqlite3PagerCommitPhaseTwo() because it is now no longer possible to invoke that function without holding a RESERVED lock. (check-in: 6ae7617298 user: drh tags: trunk)
2010-07-01
19:45
If you delete a database file but not its *-wal file, then open the database (thus creating a new empty database file) the *-wal file is automatically deleted. (check-in: 95c69dfbdd user: drh tags: trunk)
19:01
Add tests to pager1.test and pagerfault.test. (check-in: c6e7595092 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/pager.c.
2410
2411
2412
2413
2414
2415
2416

2417

2418





2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430

2431



2432
2433
2434
2435
2436
2437
2438



2439

2440


2441
2442
2443
2444
2445
2446
2447
2448

2449
2450
2451
2452
2453








2454

2455
2456
2457
2458
2459
2460
2461
  }
  pPager->state = PAGER_SHARED;

  return rc;
}

/*

** Check if the *-wal file that corresponds to the database opened by pPager

** exists. Assuming no error occurs, set *pExists to 1 if the file exists,





** or 0 otherwise and return SQLITE_OK. If an IO or OOM error occurs, return
** an SQLite error code.
*/
static int pagerHasWAL(Pager *pPager, int *pExists){
  int rc;                         /* Return code */
  char *zWal;                     /* Name of the WAL file */

  assert( !pPager->tempFile );
  zWal = sqlite3_mprintf("%s-wal", pPager->zFilename);
  if( !zWal ){
    rc = SQLITE_NOMEM;
  }else{

    rc = sqlite3OsAccess(pPager->pVfs, zWal, SQLITE_ACCESS_EXISTS, pExists);



    sqlite3_free(zWal);
  }
  return rc;
}

/*
** Check if the *-wal file that corresponds to the database opened by pPager



** exists. If it does, open the pager in WAL mode. Otherwise, if no error

** occurs, make sure Pager.journalMode is not set to PAGER_JOURNALMODE_WAL.


** If an IO or OOM error occurs, return an SQLite error code.
**
** If the WAL file is opened, also open a snapshot (read transaction).
**
** The caller must hold a SHARED lock on the database file to call this
** function. Because an EXCLUSIVE lock on the db file is required to delete 
** a WAL, this ensures there is no race condition between the xAccess() 
** below and an xDelete() being executed by some other connection.

*/
static int pagerOpenWalIfPresent(Pager *pPager){
  int rc = SQLITE_OK;
  if( !pPager->tempFile ){
    int isWal;                    /* True if WAL file exists */








    rc = pagerHasWAL(pPager, &isWal);

    if( rc==SQLITE_OK ){
      if( isWal ){
        pager_reset(pPager);
        rc = sqlite3PagerOpenWal(pPager, 0);
        if( rc==SQLITE_OK ){
          rc = pagerBeginReadTransaction(pPager);
        }







>
|
>
|
>
>
>
>
>
|


|








>
|
>
>
>







>
>
>
|
>
|
>
>
|





|
|
>





>
>
>
>
>
>
>
>
|
>







2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
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
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
  }
  pPager->state = PAGER_SHARED;

  return rc;
}

/*
** Check for the existence of or delete the *-wal file that corresponds to
** the database opened by pPager.
**
** When pExists!=NULL, set *pExists to 1 if the *-wal file exists, or 0
** if the *-wal file does not exist.
**
** When pExists==NULL, delete the *-wal file if it exists, or the do
** nothing if the *-wal file does not exist.
**
** Return SQLITE_OK on success. If on an IO or OOM error occurs, return
** an SQLite error code.
*/
static int pagerCheckForOrDeleteWAL(Pager *pPager, int *pExists){
  int rc;                         /* Return code */
  char *zWal;                     /* Name of the WAL file */

  assert( !pPager->tempFile );
  zWal = sqlite3_mprintf("%s-wal", pPager->zFilename);
  if( !zWal ){
    rc = SQLITE_NOMEM;
  }else{
    if( pExists ){
      rc = sqlite3OsAccess(pPager->pVfs, zWal, SQLITE_ACCESS_EXISTS, pExists);
    }else{
      rc = sqlite3OsDelete(pPager->pVfs, zWal, 0);
    }
    sqlite3_free(zWal);
  }
  return rc;
}

/*
** Check if the *-wal file that corresponds to the database opened by pPager
** exists if the database is not empy, or verify that the *-wal file does
** not exist (by deleting it) if the database file is empty.
**
** If the database is not empty and the *-wal file exists, open the pager
** in WAL mode.  If the database is empty or if no *-wal file exists and
** if no error occurs, make sure Pager.journalMode is not set to
** PAGER_JOURNALMODE_WAL.
**
** Return SQLITE_OK or an error code.
**
** If the WAL file is opened, also open a snapshot (read transaction).
**
** The caller must hold a SHARED lock on the database file to call this
** function. Because an EXCLUSIVE lock on the db file is required to delete 
** a WAL on a none-empty database, this ensures there is no race condition 
** between the xAccess() below and an xDelete() being executed by some 
** other connection.
*/
static int pagerOpenWalIfPresent(Pager *pPager){
  int rc = SQLITE_OK;
  if( !pPager->tempFile ){
    int isWal;                    /* True if WAL file exists */
    int nPage;                    /* Size of the database file */
    assert( pPager->state>=SHARED_LOCK );
    rc = sqlite3PagerPagecount(pPager, &nPage);
    if( rc ) return rc;
    if( nPage==0 ){
      rc = pagerCheckForOrDeleteWAL(pPager, 0);
      isWal = 0;
    }else{
      rc = pagerCheckForOrDeleteWAL(pPager, &isWal);
    }
    if( rc==SQLITE_OK ){
      if( isWal ){
        pager_reset(pPager);
        rc = sqlite3PagerOpenWal(pPager, 0);
        if( rc==SQLITE_OK ){
          rc = pagerBeginReadTransaction(pPager);
        }
6067
6068
6069
6070
6071
6072
6073
6074
6075
6076
6077
6078
6079
6080
6081
  ** it may need to be checkpointed before the connection can switch to
  ** rollback mode. Open it now so this can happen.
  */
  if( !pPager->pWal ){
    int logexists = 0;
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = pagerHasWAL(pPager, &logexists);
    }
    if( rc==SQLITE_OK && logexists ){
      rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
                          pPager->zFilename, &pPager->pWal);
    }
  }
    







|







6094
6095
6096
6097
6098
6099
6100
6101
6102
6103
6104
6105
6106
6107
6108
  ** it may need to be checkpointed before the connection can switch to
  ** rollback mode. Open it now so this can happen.
  */
  if( !pPager->pWal ){
    int logexists = 0;
    rc = sqlite3OsLock(pPager->fd, SQLITE_LOCK_SHARED);
    if( rc==SQLITE_OK ){
      rc = pagerCheckForOrDeleteWAL(pPager, &logexists);
    }
    if( rc==SQLITE_OK && logexists ){
      rc = sqlite3WalOpen(pPager->pVfs, pPager->fd,
                          pPager->zFilename, &pPager->pWal);
    }
  }
    
Added test/wal4.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
# 2010 July 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.
#
#***********************************************************************
# Verify that an empty database and a non-empty WAL file do not
# result in database corruption
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
source $testdir/malloc_common.tcl
ifcapable !wal {finish_test ; return }

do_test wal4-1.1 {
  db close
  file delete -force wal4.db wal4.db-journal wal4.db-wal wal4.db-shm
  file delete -force test.db test.db-journal test.db-wal test.db-shm
  sqlite3 db2 wal4.db
  db2 eval {
    PRAGMA journal_mode=WAL;
    CREATE TABLE t1(x);
    INSERT INTO t1 VALUES(1);
    INSERT INTO t1 VALUES(2);
    SELECT x FROM t1 ORDER BY x;
  }
} {wal 1 2}
do_test wal4-1.2 {
  file delete -force test.db test.db-journal test.db-wal
  file copy wal4.db-wal test.db-wal
  sqlite3 db test.db
  catchsql {
    SELECT * FROM t1;
  }
} {1 {no such table: t1}}

do_malloc_test wal4-2.0 -tclprep {
  db close
  file delete -force test.db test.db-journal test.db-wal
  file copy wal4.db-wal test.db-wal
  sqlite3 db test.db
} -sqlbody {
  SELECT name FROM sqlite_master
}  


finish_test