Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Require that the database handle be in autocommit mode for sqlite3_snapshot_get() to succeed. This is because it may open a read transaction on the database file. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | serializable-snapshot |
Files: | files | file ages | folders |
SHA1: |
83b658dad091211ade3594d1e8d00ce5 |
User & Date: | dan 2016-11-18 18:43:39.100 |
Context
2016-11-18
| ||
20:49 | Add experimental sqlite3_snapshot_recover() API. (check-in: 174a6076a8 user: dan tags: serializable-snapshot) | |
18:43 | Require that the database handle be in autocommit mode for sqlite3_snapshot_get() to succeed. This is because it may open a read transaction on the database file. (check-in: 83b658dad0 user: dan tags: serializable-snapshot) | |
18:22 | Add tests for snapshot interfaces. (check-in: 1f7ee7af7b user: dan tags: serializable-snapshot) | |
Changes
Changes to src/main.c.
︙ | ︙ | |||
3977 3978 3979 3980 3981 3982 3983 | int sqlite3_snapshot_get( sqlite3 *db, const char *zDb, sqlite3_snapshot **ppSnapshot ){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL | < > | | | | | | | > | 3977 3978 3979 3980 3981 3982 3983 3984 3985 3986 3987 3988 3989 3990 3991 3992 3993 3994 3995 3996 3997 3998 3999 4000 4001 4002 4003 4004 4005 4006 4007 | int sqlite3_snapshot_get( sqlite3 *db, const char *zDb, sqlite3_snapshot **ppSnapshot ){ int rc = SQLITE_ERROR; #ifndef SQLITE_OMIT_WAL #ifdef SQLITE_ENABLE_API_ARMOR if( !sqlite3SafetyCheckOk(db) ){ return SQLITE_MISUSE_BKPT; } #endif sqlite3_mutex_enter(db->mutex); if( db->autoCommit==0 ){ int iDb = sqlite3FindDbName(db, zDb); if( iDb==0 || iDb>1 ){ Btree *pBt = db->aDb[iDb].pBt; if( 0==sqlite3BtreeIsInTrans(pBt) ){ rc = sqlite3BtreeBeginTrans(pBt, 0); if( rc==SQLITE_OK ){ rc = sqlite3PagerSnapshotGet(sqlite3BtreePager(pBt), ppSnapshot); } } } } sqlite3_mutex_leave(db->mutex); #endif /* SQLITE_OMIT_WAL */ return rc; |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
8292 8293 8294 8295 8296 8297 8298 | ** EXPERIMENTAL ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. | > > > > > > > > > > > | > > > > > > > > > > > > > | < | 8292 8293 8294 8295 8296 8297 8298 8299 8300 8301 8302 8303 8304 8305 8306 8307 8308 8309 8310 8311 8312 8313 8314 8315 8316 8317 8318 8319 8320 8321 8322 8323 8324 8325 8326 8327 8328 8329 8330 8331 | ** EXPERIMENTAL ** ** ^The [sqlite3_snapshot_get(D,S,P)] interface attempts to make a ** new [sqlite3_snapshot] object that records the current state of ** schema S in database connection D. ^On success, the ** [sqlite3_snapshot_get(D,S,P)] interface writes a pointer to the newly ** created [sqlite3_snapshot] object into *P and returns SQLITE_OK. ** If there is not already a read-transaction open on schema S when ** this function is called, one is opened automatically. ** ** The following must be true for this function to succeed. If any of ** the following statements are false when sqlite3_snapshot_get() is ** called, SQLITE_ERROR is returned. The final value of *P is undefined ** in this case. ** ** <ul> ** <li> The database handle must be in [autocommit mode]. ** ** <li> Schema S of [database connection] D must be a [WAL mode] database. ** ** <li> There must not be a write transaction open on schema S of database ** connection D. ** ** <li> One or more transactions must have been written to the current wal ** file since it was created on disk (by any connection). This means ** that a snapshot cannot be taken on a wal mode database with no wal ** file immediately after it is first opened. At least one transaction ** must be written to it first. ** </ul> ** ** This function may also return SQLITE_NOMEM. If it is called with the ** database handle in autocommit mode but fails for some other reason, ** whether or not a read transaction is opened on schema S is undefined. ** ** The [sqlite3_snapshot] object returned from a successful call to ** [sqlite3_snapshot_get()] must be freed using [sqlite3_snapshot_free()] ** to avoid a memory leak. ** ** The [sqlite3_snapshot_get()] interface is only available when the ** SQLITE_ENABLE_SNAPSHOT compile-time option is used. |
︙ | ︙ |
Changes to test/snapshot.test.
︙ | ︙ | |||
61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 | eval $tcl #------------------------------------------------------------------------- # Check some error conditions in snapshot_get(). It is an error if: # # 1) snapshot_get() is called on a non-WAL database, or # 2) there is an open write transaction on the database. # do_execsql_test $tn.1.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } do_test $tn.1.1.1 { execsql { BEGIN; SELECT * FROM t1; } list [catch { snapshot_get db main } msg] $msg } {1 SQLITE_ERROR} | > | | > > > > > > > > | 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 | eval $tcl #------------------------------------------------------------------------- # Check some error conditions in snapshot_get(). It is an error if: # # 1) snapshot_get() is called on a non-WAL database, or # 2) there is an open write transaction on the database. # 3) the database handle is in auto-commit mode # do_execsql_test $tn.1.0 { CREATE TABLE t1(a, b); INSERT INTO t1 VALUES(1, 2); INSERT INTO t1 VALUES(3, 4); } do_test $tn.1.1.1 { execsql { BEGIN; SELECT * FROM t1; } list [catch { snapshot_get db main } msg] $msg } {1 SQLITE_ERROR} do_execsql_test $tn.1.1.2 COMMIT do_test $tn.1.2.1 { execsql { PRAGMA journal_mode = WAL; BEGIN; INSERT INTO t1 VALUES(5, 6); INSERT INTO t1 VALUES(7, 8); } list [catch { snapshot_get db main } msg] $msg } {1 SQLITE_ERROR} do_execsql_test $tn.1.2.2 COMMIT do_test $tn.1.3.1 { list [catch { snapshot_get db main } msg] $msg } {1 SQLITE_ERROR} do_test $tn.1.3.2 { db trans { set snap [snapshot_get db main] } snapshot_free $snap } {} #------------------------------------------------------------------------- # Check that a simple case works. Reuse the database created by the # block of tests above. # do_execsql_test $tn.2.1.0 { BEGIN; |
︙ | ︙ | |||
149 150 151 152 153 154 155 | execsql COMMIT execsql COMMIT db2 db2 close } {} do_test $tn.2.3.1 { execsql { DELETE FROM t1 WHERE a>6 } | | | 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 | execsql COMMIT execsql COMMIT db2 db2 close } {} do_test $tn.2.3.1 { execsql { DELETE FROM t1 WHERE a>6 } db trans { set snapshot [snapshot_get db main] } execsql { INSERT INTO t1 VALUES('a', 'b'); INSERT INTO t1 VALUES('c', 'd'); SELECT * FROM t1; } } {1 2 3 4 5 6 a b c d} do_test $tn.2.3.2 { |
︙ | ︙ | |||
216 217 218 219 220 221 222 | execsql { COMMIT; BEGIN; INSERT INTO t2 VALUES('g', 'h'); } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} | | | 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 | execsql { COMMIT; BEGIN; INSERT INTO t2 VALUES('g', 'h'); } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} do_execsql_test $tn.3.2.4 COMMIT do_test $tn.3.3.1 { execsql { PRAGMA journal_mode = DELETE } execsql { BEGIN } list [catch {snapshot_open db main $snapshot } msg] $msg } {1 SQLITE_ERROR} |
︙ | ︙ |