mirror of
https://github.com/sqlite/sqlite.git
synced 2025-07-29 08:01:23 +03:00
When the final connection disconnects from a wal mode database, check that the
database file has not been moved or unlinked before deleting the wal and shm files. FossilOrigin-Name: 4761db83b6d3d57f281370899403c102e39ad0021d315dd6a6912d250436782a
This commit is contained in:
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
|||||||
C Adjust\sthe\sprevious\scheck-in,\swhich\smodified\sthe\sWin32\sVFS,\sso\sthat\sit\sworks\swith\sSQLITE_OMIT_WAL.
|
C When\sthe\sfinal\sconnection\sdisconnects\sfrom\sa\swal\smode\sdatabase,\scheck\sthat\sthe\ndatabase\sfile\shas\snot\sbeen\smoved\sor\sunlinked\sbefore\sdeleting\sthe\swal\sand\sshm\nfiles.
|
||||||
D 2018-02-05T21:02:47.090
|
D 2018-02-07T16:14:41.573
|
||||||
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
|
||||||
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
|
||||||
F Makefile.in 7a3f714b4fcf793108042b7b0a5c720b0b310ec84314d61ba7f3f49f27e550ea
|
F Makefile.in 7a3f714b4fcf793108042b7b0a5c720b0b310ec84314d61ba7f3f49f27e550ea
|
||||||
@ -474,7 +474,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586
|
|||||||
F src/os_unix.c ce491421b3a54b63094a155eeac668a3bc8e5b86a5a58551d906e5b5affb443f
|
F src/os_unix.c ce491421b3a54b63094a155eeac668a3bc8e5b86a5a58551d906e5b5affb443f
|
||||||
F src/os_win.c eb03c6d52f893bcd7fdd4c6006674c13c1b5e49543fec98d605201af2997171c
|
F src/os_win.c eb03c6d52f893bcd7fdd4c6006674c13c1b5e49543fec98d605201af2997171c
|
||||||
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a
|
||||||
F src/pager.c cd194a8793ce061e184ddc369fadbc1020c6f431014d22093f6c5e55c9234033
|
F src/pager.c a3834a40acc2f3ab247d846f850d8c9313587d9c99c57a4dc194f2d4d7bf9d15
|
||||||
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
F src/pager.h 581698f2177e8bd4008fe4760898ce20b6133d1df22139b9101b5155f900df7a
|
||||||
F src/parse.y 4e750e1b261ff9f1d0b6b5d40a829c66d691899f48953fde839d8b52d41aa148
|
F src/parse.y 4e750e1b261ff9f1d0b6b5d40a829c66d691899f48953fde839d8b52d41aa148
|
||||||
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
|
F src/pcache.c 7ae91a4557a43d77d449accbfdc68846e6516f8e2eda46e8bbe4536fb669b201
|
||||||
@ -1094,7 +1094,7 @@ F test/multiplex4.test e8ae4c4bd70606a5727743241f13b5701990abe4
|
|||||||
F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
|
F test/mutex1.test ea2cc74d97f077b9e74c84cbd024f14d79a8126f
|
||||||
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660
|
||||||
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
|
F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1
|
||||||
F test/nockpt.test 9a436a7213ba5ef7a32304998d386d3ea3f76c9d
|
F test/nockpt.test d291d618c934a453683cb2eff95f633d406f7147fa0403e10055db19dcc3842a
|
||||||
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e
|
||||||
F test/normalize.test 501630ab49b0b26b65c74124bf03e3374c1b57fa97aae750f84803609141d167
|
F test/normalize.test 501630ab49b0b26b65c74124bf03e3374c1b57fa97aae750f84803609141d167
|
||||||
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf
|
||||||
@ -1704,7 +1704,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
|||||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||||
P 535ed0ac5e8728ec91fc0a4cb54b820923d161cfd4e0e6aed6df6cdae365bc7d
|
P 36c2e67e82626f8d0a187c6c286c133ed659889e3b577469261b9dcd3b3ab75b
|
||||||
R 610345e12e18345d79d861c16dfe01d9
|
R ed31a2562d55c76884009a210d222cf0
|
||||||
U mistachkin
|
U dan
|
||||||
Z 7a54a037e46133481e56c9143fb3122e
|
Z 0e612251c296ff4ce7a47fbd872de74d
|
||||||
|
@ -1 +1 @@
|
|||||||
36c2e67e82626f8d0a187c6c286c133ed659889e3b577469261b9dcd3b3ab75b
|
4761db83b6d3d57f281370899403c102e39ad0021d315dd6a6912d250436782a
|
67
src/pager.c
67
src/pager.c
@ -4102,6 +4102,30 @@ static void pagerFreeMapHdrs(Pager *pPager){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Verify that the database file has not be deleted or renamed out from
|
||||||
|
** under the pager. Return SQLITE_OK if the database is still were it ought
|
||||||
|
** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
|
||||||
|
** code from sqlite3OsAccess()) if the database has gone missing.
|
||||||
|
*/
|
||||||
|
static int databaseIsUnmoved(Pager *pPager){
|
||||||
|
int bHasMoved = 0;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
if( pPager->tempFile ) return SQLITE_OK;
|
||||||
|
if( pPager->dbSize==0 ) return SQLITE_OK;
|
||||||
|
assert( pPager->zFilename && pPager->zFilename[0] );
|
||||||
|
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
|
||||||
|
if( rc==SQLITE_NOTFOUND ){
|
||||||
|
/* If the HAS_MOVED file-control is unimplemented, assume that the file
|
||||||
|
** has not been moved. That is the historical behavior of SQLite: prior to
|
||||||
|
** version 3.8.3, it never checked */
|
||||||
|
rc = SQLITE_OK;
|
||||||
|
}else if( rc==SQLITE_OK && bHasMoved ){
|
||||||
|
rc = SQLITE_READONLY_DBMOVED;
|
||||||
|
}
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** Shutdown the page cache. Free all memory and close all files.
|
** Shutdown the page cache. Free all memory and close all files.
|
||||||
@ -4118,8 +4142,7 @@ static void pagerFreeMapHdrs(Pager *pPager){
|
|||||||
** to the caller.
|
** to the caller.
|
||||||
*/
|
*/
|
||||||
int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
||||||
u8 *pTmp = (u8 *)pPager->pTmpSpace;
|
u8 *pTmp = (u8*)pPager->pTmpSpace;
|
||||||
|
|
||||||
assert( db || pagerUseWal(pPager)==0 );
|
assert( db || pagerUseWal(pPager)==0 );
|
||||||
assert( assert_pager_state(pPager) );
|
assert( assert_pager_state(pPager) );
|
||||||
disable_simulated_io_errors();
|
disable_simulated_io_errors();
|
||||||
@ -4128,11 +4151,17 @@ int sqlite3PagerClose(Pager *pPager, sqlite3 *db){
|
|||||||
/* pPager->errCode = 0; */
|
/* pPager->errCode = 0; */
|
||||||
pPager->exclusiveMode = 0;
|
pPager->exclusiveMode = 0;
|
||||||
#ifndef SQLITE_OMIT_WAL
|
#ifndef SQLITE_OMIT_WAL
|
||||||
assert( db || pPager->pWal==0 );
|
{
|
||||||
sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,
|
u8 *a = 0;
|
||||||
(db && (db->flags & SQLITE_NoCkptOnClose) ? 0 : pTmp)
|
assert( db || pPager->pWal==0 );
|
||||||
);
|
if( db && 0==(db->flags & SQLITE_NoCkptOnClose)
|
||||||
pPager->pWal = 0;
|
&& SQLITE_OK==databaseIsUnmoved(pPager)
|
||||||
|
){
|
||||||
|
a = pTmp;
|
||||||
|
}
|
||||||
|
sqlite3WalClose(pPager->pWal, db, pPager->walSyncFlags, pPager->pageSize,a);
|
||||||
|
pPager->pWal = 0;
|
||||||
|
}
|
||||||
#endif
|
#endif
|
||||||
pager_reset(pPager);
|
pager_reset(pPager);
|
||||||
if( MEMDB ){
|
if( MEMDB ){
|
||||||
@ -4967,30 +4996,6 @@ act_like_temp_file:
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/* Verify that the database file has not be deleted or renamed out from
|
|
||||||
** under the pager. Return SQLITE_OK if the database is still were it ought
|
|
||||||
** to be on disk. Return non-zero (SQLITE_READONLY_DBMOVED or some other error
|
|
||||||
** code from sqlite3OsAccess()) if the database has gone missing.
|
|
||||||
*/
|
|
||||||
static int databaseIsUnmoved(Pager *pPager){
|
|
||||||
int bHasMoved = 0;
|
|
||||||
int rc;
|
|
||||||
|
|
||||||
if( pPager->tempFile ) return SQLITE_OK;
|
|
||||||
if( pPager->dbSize==0 ) return SQLITE_OK;
|
|
||||||
assert( pPager->zFilename && pPager->zFilename[0] );
|
|
||||||
rc = sqlite3OsFileControl(pPager->fd, SQLITE_FCNTL_HAS_MOVED, &bHasMoved);
|
|
||||||
if( rc==SQLITE_NOTFOUND ){
|
|
||||||
/* If the HAS_MOVED file-control is unimplemented, assume that the file
|
|
||||||
** has not been moved. That is the historical behavior of SQLite: prior to
|
|
||||||
** version 3.8.3, it never checked */
|
|
||||||
rc = SQLITE_OK;
|
|
||||||
}else if( rc==SQLITE_OK && bHasMoved ){
|
|
||||||
rc = SQLITE_READONLY_DBMOVED;
|
|
||||||
}
|
|
||||||
return rc;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
** This function is called after transitioning from PAGER_UNLOCK to
|
** This function is called after transitioning from PAGER_UNLOCK to
|
||||||
|
@ -61,6 +61,84 @@ do_test 1.14 { sqlite3_db_config db NO_CKPT_ON_CLOSE 1 } {1}
|
|||||||
do_execsql_test 1.14 { PRAGMA main.journal_mode = delete } {delete}
|
do_execsql_test 1.14 { PRAGMA main.journal_mode = delete } {delete}
|
||||||
do_test 1.15 { file exists test.db-wal } {0}
|
do_test 1.15 { file exists test.db-wal } {0}
|
||||||
|
|
||||||
|
#-------------------------------------------------------------------------
|
||||||
|
# Test an unusual scenario:
|
||||||
|
#
|
||||||
|
# 1. A wal mode db is opened and written. Then sqlite3_close_v2() used
|
||||||
|
# to close the db handle while there is still an unfinalized
|
||||||
|
# statement (so the db handle stays open).
|
||||||
|
#
|
||||||
|
# 2. The db, wal and *-shm files are deleted from the file system.
|
||||||
|
#
|
||||||
|
# 3. Another connection creates a new wal mode db at the same file-system
|
||||||
|
# location as the previous one.
|
||||||
|
#
|
||||||
|
# 4. The statement left unfinalized in (1) is finalized.
|
||||||
|
#
|
||||||
|
# The test is to ensure that the connection left open in step (1) does
|
||||||
|
# not try to delete the wal file from the file-system as part of step
|
||||||
|
# 4.
|
||||||
|
#
|
||||||
|
reset_db
|
||||||
|
db close
|
||||||
|
|
||||||
|
# Open a connection on a wal database. Write to it a bit. Then prepare
|
||||||
|
# a statement and call sqlite3_close_v2() (so that the statement handle
|
||||||
|
# holds the db connection open).
|
||||||
|
#
|
||||||
|
set ::db1 [sqlite3_open_v2 test.db SQLITE_OPEN_READWRITE ""]
|
||||||
|
do_test 2.0 {
|
||||||
|
lindex [
|
||||||
|
sqlite3_exec $::db1 {
|
||||||
|
PRAGMA journal_mode = wal;
|
||||||
|
CREATE TABLE t1(x PRIMARY KEY, y UNIQUE, z);
|
||||||
|
INSERT INTO t1 VALUES(1, 2, 3);
|
||||||
|
PRAGMA wal_checkpoint;
|
||||||
|
}] 0
|
||||||
|
} {0}
|
||||||
|
set ::stmt [sqlite3_prepare $::db1 "SELECT * FROM t1" -1 dummy]
|
||||||
|
sqlite3_close_v2 $::db1
|
||||||
|
|
||||||
|
# Delete the database, wal and shm files.
|
||||||
|
#
|
||||||
|
forcedelete test.db test.db-wal test.db-shm
|
||||||
|
|
||||||
|
# Open and populate a new database file at the same file-system location
|
||||||
|
# as the one just deleted. Contrive a partial checkpoint on it.
|
||||||
|
#
|
||||||
|
sqlite3 db test.db
|
||||||
|
sqlite3 db2 test.db
|
||||||
|
do_execsql_test 2.1 {
|
||||||
|
PRAGMA journal_mode = wal;
|
||||||
|
CREATE TABLE y1(a PRIMARY KEY, b UNIQUE, c);
|
||||||
|
INSERT INTO y1 VALUES('a', 'b', 'c');
|
||||||
|
INSERT INTO y1 VALUES('d', 'e', 'f');
|
||||||
|
} {wal}
|
||||||
|
do_execsql_test -db db2 2.2 {
|
||||||
|
BEGIN;
|
||||||
|
SELECT * FROM y1;
|
||||||
|
} {a b c d e f}
|
||||||
|
do_execsql_test 2.3 {
|
||||||
|
UPDATE y1 SET c='g' WHERE a='d';
|
||||||
|
PRAGMA wal_checkpoint;
|
||||||
|
} {0 11 10}
|
||||||
|
do_execsql_test -db db2 2.4 {
|
||||||
|
COMMIT
|
||||||
|
}
|
||||||
|
|
||||||
|
# Finalize the statement handle, causing the first connection to be
|
||||||
|
# closed. Test that this has not corrupted the database file by
|
||||||
|
# deleting the new wal file from the file-system. If it has, this
|
||||||
|
# test should fail with an IO or corruption error.
|
||||||
|
#
|
||||||
|
do_test 2.5 {
|
||||||
|
sqlite3_finalize $::stmt
|
||||||
|
sqlite3 db3 test.db
|
||||||
|
execsql {
|
||||||
|
PRAGMA integrity_check;
|
||||||
|
SELECT * FROM y1;
|
||||||
|
} db3
|
||||||
|
} {ok a b c d e g}
|
||||||
|
|
||||||
|
|
||||||
finish_test
|
finish_test
|
||||||
|
Reference in New Issue
Block a user