/ Check-in [361c2296]
Login

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

Overview
Comment:Add extended error code SQLITE_BUSY_SNAPSHOT - returned in WAL mode when a read-transaction cannot be upgraded to a write-transaction because it is reading from a snapshot other than the most recently committed.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 361c22969aa75340ed696e00e3dc5d17d5493bee
User & Date: dan 2013-06-27 11:46:27
Context
2013-06-27
13:01
The undocumented and unsupported ".selftest" command in the command-line shell utility is now only available if compiled with SQLITE_DEBUG. Also fix a windows compiler warning in that command. check-in: e88fd5b2 user: drh tags: trunk
11:46
Add extended error code SQLITE_BUSY_SNAPSHOT - returned in WAL mode when a read-transaction cannot be upgraded to a write-transaction because it is reading from a snapshot other than the most recently committed. check-in: 361c2296 user: dan tags: trunk
2013-06-26
22:46
Update the ".import" command of the command-line shell so that it can accept field values that span multiple lines and so that it issues error messages if the input text does not strictly conform to RFC4180. check-in: 93f63215 user: drh tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/main.c.

  1059   1059         case SQLITE_ERROR:              zName = "SQLITE_ERROR";             break;
  1060   1060         case SQLITE_INTERNAL:           zName = "SQLITE_INTERNAL";          break;
  1061   1061         case SQLITE_PERM:               zName = "SQLITE_PERM";              break;
  1062   1062         case SQLITE_ABORT:              zName = "SQLITE_ABORT";             break;
  1063   1063         case SQLITE_ABORT_ROLLBACK:     zName = "SQLITE_ABORT_ROLLBACK";    break;
  1064   1064         case SQLITE_BUSY:               zName = "SQLITE_BUSY";              break;
  1065   1065         case SQLITE_BUSY_RECOVERY:      zName = "SQLITE_BUSY_RECOVERY";     break;
         1066  +      case SQLITE_BUSY_SNAPSHOT:      zName = "SQLITE_BUSY_SNAPSHOT";     break;
  1066   1067         case SQLITE_LOCKED:             zName = "SQLITE_LOCKED";            break;
  1067   1068         case SQLITE_LOCKED_SHAREDCACHE: zName = "SQLITE_LOCKED_SHAREDCACHE";break;
  1068   1069         case SQLITE_NOMEM:              zName = "SQLITE_NOMEM";             break;
  1069   1070         case SQLITE_READONLY:           zName = "SQLITE_READONLY";          break;
  1070   1071         case SQLITE_READONLY_RECOVERY:  zName = "SQLITE_READONLY_RECOVERY"; break;
  1071   1072         case SQLITE_READONLY_CANTLOCK:  zName = "SQLITE_READONLY_CANTLOCK"; break;
  1072   1073         case SQLITE_READONLY_ROLLBACK:  zName = "SQLITE_READONLY_ROLLBACK"; break;

Changes to src/sqlite.h.in.

   471    471   #define SQLITE_IOERR_SHMLOCK           (SQLITE_IOERR | (20<<8))
   472    472   #define SQLITE_IOERR_SHMMAP            (SQLITE_IOERR | (21<<8))
   473    473   #define SQLITE_IOERR_SEEK              (SQLITE_IOERR | (22<<8))
   474    474   #define SQLITE_IOERR_DELETE_NOENT      (SQLITE_IOERR | (23<<8))
   475    475   #define SQLITE_IOERR_MMAP              (SQLITE_IOERR | (24<<8))
   476    476   #define SQLITE_LOCKED_SHAREDCACHE      (SQLITE_LOCKED |  (1<<8))
   477    477   #define SQLITE_BUSY_RECOVERY           (SQLITE_BUSY   |  (1<<8))
          478  +#define SQLITE_BUSY_SNAPSHOT           (SQLITE_BUSY   |  (2<<8))
   478    479   #define SQLITE_CANTOPEN_NOTEMPDIR      (SQLITE_CANTOPEN | (1<<8))
   479    480   #define SQLITE_CANTOPEN_ISDIR          (SQLITE_CANTOPEN | (2<<8))
   480    481   #define SQLITE_CANTOPEN_FULLPATH       (SQLITE_CANTOPEN | (3<<8))
   481    482   #define SQLITE_CORRUPT_VTAB            (SQLITE_CORRUPT | (1<<8))
   482    483   #define SQLITE_READONLY_RECOVERY       (SQLITE_READONLY | (1<<8))
   483    484   #define SQLITE_READONLY_CANTLOCK       (SQLITE_READONLY | (2<<8))
   484    485   #define SQLITE_READONLY_ROLLBACK       (SQLITE_READONLY | (3<<8))

Changes to src/wal.c.

  2459   2459     /* If another connection has written to the database file since the
  2460   2460     ** time the read transaction on this connection was started, then
  2461   2461     ** the write is disallowed.
  2462   2462     */
  2463   2463     if( memcmp(&pWal->hdr, (void *)walIndexHdr(pWal), sizeof(WalIndexHdr))!=0 ){
  2464   2464       walUnlockExclusive(pWal, WAL_WRITE_LOCK, 1);
  2465   2465       pWal->writeLock = 0;
  2466         -    rc = SQLITE_BUSY;
         2466  +    rc = SQLITE_BUSY_SNAPSHOT;
  2467   2467     }
  2468   2468   
  2469   2469     return rc;
  2470   2470   }
  2471   2471   
  2472   2472   /*
  2473   2473   ** End a write transaction.  The commit has already been done.  This

Changes to test/wal6.test.

    10     10   #***********************************************************************
    11     11   # This file implements regression tests for SQLite library.  The
    12     12   # focus of this file is testing the operation of the library in
    13     13   # "PRAGMA journal_mode=WAL" mode.
    14     14   #
    15     15   
    16     16   set testdir [file dirname $argv0]
           17  +set testprefix wal6
    17     18   source $testdir/tester.tcl
    18     19   source $testdir/lock_common.tcl
    19     20   source $testdir/wal_common.tcl
    20     21   source $testdir/malloc_common.tcl
    21     22   ifcapable !wal {finish_test ; return }
    22     23   
    23     24   #-------------------------------------------------------------------------
................................................................................
    25     26   #
    26     27   db close
    27     28   forcedelete test.db
    28     29   
    29     30   set all_journal_modes {delete persist truncate memory off}
    30     31   foreach jmode $all_journal_modes {
    31     32   
    32         -	do_test wal6-1.0.$jmode {
           33  +  do_test wal6-1.0.$jmode {
    33     34       sqlite3 db test.db
    34     35       execsql "PRAGMA journal_mode = $jmode;"
    35         -	} $jmode
           36  +  } $jmode
    36     37   
    37         -	do_test wal6-1.1.$jmode {
    38         -	  execsql {
    39         -	    CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
    40         -	    INSERT INTO t1 VALUES(1,2);
    41         -	    SELECT * FROM t1;
    42         -	  }
    43         -	} {1 2}
           38  +  do_test wal6-1.1.$jmode {
           39  +    execsql {
           40  +      CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
           41  +      INSERT INTO t1 VALUES(1,2);
           42  +      SELECT * FROM t1;
           43  +    }
           44  +  } {1 2}
    44     45   
    45     46   # Under Windows, you'll get an error trying to delete
    46     47   # a file this is already opened.  Close the first connection
    47     48   # so the other tests work.
    48     49   if {$tcl_platform(platform)=="windows"} {
    49     50     if {$jmode=="persist" || $jmode=="truncate"} {
    50     51       db close
    51     52     }
    52     53   }
    53     54   
    54         -	do_test wal6-1.2.$jmode {
    55         -	  sqlite3 db2 test.db
    56         -	  execsql {
    57         -		PRAGMA journal_mode=WAL;
    58         -		INSERT INTO t1 VALUES(3,4);
    59         -		SELECT * FROM t1 ORDER BY a;
    60         -	  } db2
    61         -	} {wal 1 2 3 4}
           55  +  do_test wal6-1.2.$jmode {
           56  +    sqlite3 db2 test.db
           57  +    execsql {
           58  +    PRAGMA journal_mode=WAL;
           59  +    INSERT INTO t1 VALUES(3,4);
           60  +    SELECT * FROM t1 ORDER BY a;
           61  +    } db2
           62  +  } {wal 1 2 3 4}
    62     63   
    63     64   if {$tcl_platform(platform)=="windows"} {
    64     65     if {$jmode=="persist" || $jmode=="truncate"} {
    65         -	  sqlite3 db test.db
           66  +    sqlite3 db test.db
    66     67     }
    67     68   }
    68     69   
    69         -	do_test wal6-1.3.$jmode {
    70         -	  execsql {
    71         -		  SELECT * FROM t1 ORDER BY a;
    72         -	  }
    73         -	} {1 2 3 4}
           70  +  do_test wal6-1.3.$jmode {
           71  +    execsql {
           72  +      SELECT * FROM t1 ORDER BY a;
           73  +    }
           74  +  } {1 2 3 4}
    74     75   
    75         -	db close
    76         -	db2 close
           76  +  db close
           77  +  db2 close
    77     78     forcedelete test.db
    78     79   
    79     80   }
           81  +
           82  +#-------------------------------------------------------------------------
           83  +# Test that SQLITE_BUSY_SNAPSHOT is returned as expected.
           84  +#
           85  +reset_db
           86  +sqlite3 db2 test.db
           87  +
           88  +do_execsql_test 2.1 {
           89  +  PRAGMA journal_mode = WAL;
           90  +  CREATE TABLE t1(a PRIMARY KEY, b TEXT);
           91  +  INSERT INTO t1 VALUES(1, 'one');
           92  +  INSERT INTO t1 VALUES(2, 'two');
           93  +  BEGIN;
           94  +    SELECT * FROM t1;
           95  +} {wal 1 one 2 two}
           96  +
           97  +do_test 2.2 {
           98  +  execsql {
           99  +    SELECT * FROM t1;
          100  +    INSERT INTO t1 VALUES(3, 'three');
          101  +  } db2
          102  +} {1 one 2 two}
          103  +
          104  +do_catchsql_test 2.3 { 
          105  +  INSERT INTO t1 VALUES('x', 'x') 
          106  +} {1 {database is locked}}
          107  +
          108  +do_test 2.4 { 
          109  +  list [sqlite3_errcode db] [sqlite3_extended_errcode db]
          110  +} {SQLITE_BUSY SQLITE_BUSY_SNAPSHOT}
          111  +
          112  +do_execsql_test 2.5 {
          113  +  SELECT * FROM t1;
          114  +  COMMIT;
          115  +  INSERT INTO t1 VALUES('x', 'x') 
          116  +} {1 one 2 two}
          117  +
          118  +if 0 {
          119  +proc test3 {prefix} {
          120  +  do_test $prefix.1 {
          121  +    execsql { SELECT count(*) FROM t1 } 
          122  +  } {0}
          123  +  do_test $prefix.2 {
          124  +    execsql { INSERT INTO t1 VALUES('x', 'x') } db2
          125  +  } {}
          126  +  do_test $prefix.3 {
          127  +    execsql { INSERT INTO t1 VALUES('y', 'y') }
          128  +  } {}
          129  +  do_test $prefix.4 {
          130  +    execsql { SELECT count(*) FROM t1 } 
          131  +  } {2}
          132  +}
          133  +
          134  +do_execsql_test 2.6.1 { DELETE FROM t1 }
          135  +test3 2.6.2
          136  +
          137  +db func test3 test3
          138  +do_execsql_test 2.6.3 { DELETE FROM t1 }
          139  +db eval {SELECT test3('2.6.4')}
          140  +}
          141  +
          142  +do_test 2.x {
          143  +  db2 close
          144  +} {}
    80    145   
    81    146   finish_test
          147  +