Merge updates from trunk.
FossilOrigin-Name: 5f7fc79aa06ca9b79664c50c3c277c98a74ff9a0
This commit is contained in:
commit
063d57039e
106
ext/rbu/rbucrash2.test
Normal file
106
ext/rbu/rbucrash2.test
Normal file
@ -0,0 +1,106 @@
|
||||
# 2017 March 02
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
if {![info exists testdir]} {
|
||||
set testdir [file join [file dirname [info script]] .. .. test]
|
||||
}
|
||||
source $testdir/tester.tcl
|
||||
set ::testprefix rbucrash2
|
||||
|
||||
db close
|
||||
forcedelete test.db-oal rbu.db
|
||||
sqlite3_shutdown
|
||||
sqlite3_config_uri 1
|
||||
reset_db
|
||||
|
||||
# Set up a target database and an rbu update database. The target
|
||||
# db is the usual "test.db", the rbu db is "test.db2".
|
||||
#
|
||||
forcedelete test.db2
|
||||
do_execsql_test 1.0 {
|
||||
CREATE TABLE t1(a, b, c, PRIMARY KEY(a), UNIQUE(b));
|
||||
INSERT INTO t1 VALUES(1, 2, 3);
|
||||
INSERT INTO t1 VALUES(4, 5, 6);
|
||||
INSERT INTO t1 VALUES(7, 8, 9);
|
||||
|
||||
ATTACH 'test.db2' AS rbu;
|
||||
CREATE TABLE rbu.data_t1(a, b, c, rbu_control);
|
||||
INSERT INTO data_t1 VALUES('one', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('two', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('three', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('four', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('five', randomblob(3500), NULL, 0);
|
||||
INSERT INTO data_t1 VALUES('six', randomblob(3500), NULL, 0);
|
||||
}
|
||||
db_save_and_close
|
||||
|
||||
proc do_rbu_crash_test2 {tn script} {
|
||||
|
||||
foreach {f blksz} {
|
||||
test.db 512
|
||||
test.db2 512
|
||||
test.db 4096
|
||||
test.db2 4096
|
||||
} {
|
||||
set bDone 0
|
||||
for {set iDelay 1} {$bDone==0} {incr iDelay} {
|
||||
forcedelete test.db2 test.db2-journal test.db test.db-oal test.db-wal
|
||||
db_restore
|
||||
|
||||
set res [
|
||||
crashsql -file $f -delay $iDelay -tclbody $script -dflt 1 -opendb {} \
|
||||
-blocksize $blksz {}
|
||||
]
|
||||
|
||||
set bDone 1
|
||||
if {$res == "1 {child process exited abnormally}"} {
|
||||
set bDone 0
|
||||
} elseif {$res != "0 {}"} {
|
||||
error "unexected catchsql result: $res"
|
||||
}
|
||||
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {}
|
||||
rbu close
|
||||
|
||||
sqlite3 db test.db
|
||||
do_execsql_test $tn.delay=$iDelay.f=$f.blksz=$blksz {
|
||||
PRAGMA integrity_check;
|
||||
} {ok}
|
||||
db close
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for {set x 1} {$x < 10} {incr x} {
|
||||
do_rbu_crash_test2 1.$x {
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {
|
||||
rbu savestate
|
||||
}
|
||||
rbu close
|
||||
}
|
||||
}
|
||||
|
||||
for {set x 1} {$x < 2} {incr x} {
|
||||
do_rbu_crash_test2 2.$x {
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
while {[rbu step]=="SQLITE_OK"} {
|
||||
rbu close
|
||||
sqlite3rbu rbu test.db test.db2
|
||||
}
|
||||
rbu close
|
||||
}
|
||||
}
|
||||
|
||||
finish_test
|
||||
|
@ -40,6 +40,7 @@ proc create_rbu1 {filename} {
|
||||
|
||||
|
||||
do_execsql_test 1.0 {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
|
||||
}
|
||||
|
||||
@ -266,6 +267,7 @@ foreach bReopen {0 1} {
|
||||
do_test 3.$bReopen.1.0 {
|
||||
reset_db
|
||||
execsql {
|
||||
PRAGMA page_size = 4096;
|
||||
CREATE TABLE t1(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t2(a INTEGER PRIMARY KEY, b);
|
||||
CREATE TABLE t3(a INTEGER PRIMARY KEY, b);
|
||||
|
@ -356,6 +356,7 @@ struct sqlite3rbu {
|
||||
RbuObjIter objiter; /* Iterator for skipping through tbl/idx */
|
||||
const char *zVfsName; /* Name of automatically created rbu vfs */
|
||||
rbu_file *pTargetFd; /* File handle open on target db */
|
||||
int nPagePerSector; /* Pages per sector for pTargetFd */
|
||||
i64 iOalSz;
|
||||
i64 nPhaseOneStep;
|
||||
|
||||
@ -2620,6 +2621,23 @@ static void rbuSetupCheckpoint(sqlite3rbu *p, RbuState *pState){
|
||||
if( p->nFrame==0 || (pState && pState->iWalCksum!=p->iWalCksum) ){
|
||||
p->rc = SQLITE_DONE;
|
||||
p->eStage = RBU_STAGE_DONE;
|
||||
}else{
|
||||
int nSectorSize;
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
sqlite3_file *pWal = p->pTargetFd->pWalFd->pReal;
|
||||
assert( p->nPagePerSector==0 );
|
||||
nSectorSize = pDb->pMethods->xSectorSize(pDb);
|
||||
if( nSectorSize>p->pgsz ){
|
||||
p->nPagePerSector = nSectorSize / p->pgsz;
|
||||
}else{
|
||||
p->nPagePerSector = 1;
|
||||
}
|
||||
|
||||
/* Call xSync() on the wal file. This causes SQLite to sync the
|
||||
** directory in which the target database and the wal file reside, in
|
||||
** case it has not been synced since the rename() call in
|
||||
** rbuMoveOalFile(). */
|
||||
p->rc = pWal->pMethods->xSync(pWal, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -3275,9 +3293,26 @@ int sqlite3rbu_step(sqlite3rbu *p){
|
||||
p->rc = SQLITE_DONE;
|
||||
}
|
||||
}else{
|
||||
RbuFrame *pFrame = &p->aFrame[p->nStep];
|
||||
rbuCheckpointFrame(p, pFrame);
|
||||
p->nStep++;
|
||||
/* At one point the following block copied a single frame from the
|
||||
** wal file to the database file. So that one call to sqlite3rbu_step()
|
||||
** checkpointed a single frame.
|
||||
**
|
||||
** However, if the sector-size is larger than the page-size, and the
|
||||
** application calls sqlite3rbu_savestate() or close() immediately
|
||||
** after this step, then rbu_step() again, then a power failure occurs,
|
||||
** then the database page written here may be damaged. Work around
|
||||
** this by checkpointing frames until the next page in the aFrame[]
|
||||
** lies on a different disk sector to the current one. */
|
||||
u32 iSector;
|
||||
do{
|
||||
RbuFrame *pFrame = &p->aFrame[p->nStep];
|
||||
iSector = (pFrame->iDbPage-1) / p->nPagePerSector;
|
||||
rbuCheckpointFrame(p, pFrame);
|
||||
p->nStep++;
|
||||
}while( p->nStep<p->nFrame
|
||||
&& iSector==((p->aFrame[p->nStep].iDbPage-1) / p->nPagePerSector)
|
||||
&& p->rc==SQLITE_OK
|
||||
);
|
||||
}
|
||||
p->nProgress++;
|
||||
}
|
||||
@ -3718,6 +3753,12 @@ int sqlite3rbu_close(sqlite3rbu *p, char **pzErrmsg){
|
||||
p->rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, &p->zErrmsg);
|
||||
}
|
||||
|
||||
/* Sync the db file if currently doing an incremental checkpoint */
|
||||
if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
p->rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
|
||||
rbuSaveState(p, p->eStage);
|
||||
|
||||
if( p->rc==SQLITE_OK && p->eStage==RBU_STAGE_OAL ){
|
||||
@ -3842,6 +3883,12 @@ int sqlite3rbu_savestate(sqlite3rbu *p){
|
||||
if( rc==SQLITE_OK ) rc = sqlite3_exec(p->dbMain, "COMMIT", 0, 0, 0);
|
||||
}
|
||||
|
||||
/* Sync the db file */
|
||||
if( rc==SQLITE_OK && p->eStage==RBU_STAGE_CKPT ){
|
||||
sqlite3_file *pDb = p->pTargetFd->pReal;
|
||||
rc = pDb->pMethods->xSync(pDb, SQLITE_SYNC_NORMAL);
|
||||
}
|
||||
|
||||
p->rc = rc;
|
||||
rbuSaveState(p, p->eStage);
|
||||
rc = p->rc;
|
||||
|
30
manifest
30
manifest
@ -1,5 +1,5 @@
|
||||
C Add\san\soptional\sbitmask\sof\sallowed\soptimizations\son\sthe\s"PRAGMA\soptimize"\ncommand.\s\sThe\s0x01\sbit\sis\sDebug\sMode.
|
||||
D 2017-03-02T14:17:21.291
|
||||
C Merge\supdates\sfrom\strunk.
|
||||
D 2017-03-06T11:39:34.004
|
||||
F Makefile.in edb6bcdd37748d2b1c3422ff727c748df7ffe918
|
||||
F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434
|
||||
F Makefile.msc a89ea37ab5928026001569f056973b9059492fe2
|
||||
@ -250,6 +250,7 @@ F ext/rbu/rbuB.test c25bc325b8072a766e56bb76c001866b405925c2
|
||||
F ext/rbu/rbuC.test efe47db508a0269b683cb2a1913a425ffd39a831
|
||||
F ext/rbu/rbu_common.tcl a38e8e2d4a50fd6aaf151633714c1b1d2fae3ead
|
||||
F ext/rbu/rbucrash.test 8d2ed5d4b05fef6c00c2a6b5f7ead71fa172a695
|
||||
F ext/rbu/rbucrash2.test b2ecbdd7bb72c88bd217c65bd00dafa07f7f2d4d
|
||||
F ext/rbu/rbudiff.test 3e605cf624d00d04d0fb1316a3acec4fbe3b3ac5
|
||||
F ext/rbu/rbudor.test 99b05cc0df613e962c2c8085cfb05686a09cf315
|
||||
F ext/rbu/rbufault.test cc0be8d5d392d98b0c2d6a51be377ea989250a89
|
||||
@ -257,12 +258,12 @@ F ext/rbu/rbufault2.test 9a7f19edd6ea35c4c9f807d8a3db0a03a5670c06
|
||||
F ext/rbu/rbufault3.test 54a399888ac4af44c68f9f58afbed23149428bca
|
||||
F ext/rbu/rbufault4.test 34e70701cbec51571ffbd9fbf9d4e0f2ec495ca7
|
||||
F ext/rbu/rbufts.test 828cd689da825f0a7b7c53ffc1f6f7fdb6fa5bda
|
||||
F ext/rbu/rbuprogress.test e3e25fb7622641b8f2df7c6b7a7eb6fddfc46a4b
|
||||
F ext/rbu/rbuprogress.test 1849d4e0e50616edf5ce75ce7db86622e656b5cf
|
||||
F ext/rbu/rburesume.test 8acb77f4a422ff55acfcfc9cc15a5cb210b1de83
|
||||
F ext/rbu/rbusave.test 0f43b6686084f426ddd040b878426452fd2c2f48
|
||||
F ext/rbu/rbuvacuum.test 4a977447c15c2581ab668781d9ef4294382530e0
|
||||
F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa
|
||||
F ext/rbu/sqlite3rbu.c bb0de6cdbdb14a7d55a097238a434b7e99caf318
|
||||
F ext/rbu/sqlite3rbu.c 2a89efba9eeba8e6c89a498dc195e8efbdde2694
|
||||
F ext/rbu/sqlite3rbu.h 6fb6294c34a9ca93b5894a33bca530c6f08decba
|
||||
F ext/rbu/test_rbu.c 5aa22616afac6f71ebd3d9bc9bf1006cfabcca88
|
||||
F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761
|
||||
@ -339,14 +340,14 @@ F src/auth.c 930b376a9c56998557367e6f7f8aaeac82a2a792
|
||||
F src/backup.c faf17e60b43233c214aae6a8179d24503a61e83b
|
||||
F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33
|
||||
F src/btmutex.c 0e9ce2d56159b89b9bc8e197e023ee11e39ff8ca
|
||||
F src/btree.c 83e2bc48be6e09eb88e312eb791f4bbd96986d93
|
||||
F src/btree.c e2bae0a03f73d119910fb35c9550987564065137
|
||||
F src/btree.h bf64dfeeddeebdb775a5eba0098bbc00d073290d
|
||||
F src/btreeInt.h cd55d39d9916270837a88c12e701047cba0729b0
|
||||
F src/build.c 43f903c9082040ced2b421543cb0300c2973647d
|
||||
F src/callback.c 2e76147783386374bf01b227f752c81ec872d730
|
||||
F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e
|
||||
F src/ctime.c a9984df73898c042a5cfc8f9d8e7723d02bc35c9
|
||||
F src/date.c dc3f1391d9297f8c748132813aaffcb117090d6e
|
||||
F src/date.c ee676e7694dfadbdd2fde1a258a71be8360ba5ae
|
||||
F src/dbstat.c 19ee7a4e89979d4df8e44cfac7a8f905ec89b77d
|
||||
F src/delete.c 0d9d5549d42e79ce4d82ff1db1e6c81e36d2f67c
|
||||
F src/expr.c 8a29e9b72d4b642189999c41782cd6c5bc43512f
|
||||
@ -411,7 +412,7 @@ F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5
|
||||
F src/test3.c d03f5b5da9a2410b7a91c64b0d3306ed28ab6fee
|
||||
F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6
|
||||
F src/test5.c 328aae2c010c57a9829d255dc099d6899311672d
|
||||
F src/test6.c 121060d2e79a4f5047eb12b5135b23a6a7a5af01
|
||||
F src/test6.c 004ad42f121f693b8cbe060d1a330678abc61620
|
||||
F src/test7.c 5612e9aecf934d6df7bba6ce861fdf5ba5456010
|
||||
F src/test8.c 4f4904721167b32f7a4fa8c7b32a07a673d6cc86
|
||||
F src/test9.c 12e5ba554d2d1cbe0158f6ab3f7ffcd7a86ee4e5
|
||||
@ -466,8 +467,8 @@ F src/vacuum.c 1fe4555cd8c9b263afb85b5b4ee3a4a4181ad569
|
||||
F src/vdbe.c f520378e510fd36bbf289921798dbc8f2b3dc30d
|
||||
F src/vdbe.h 59998ffd71d7caa8886bc78dafaf8caeccd4c13c
|
||||
F src/vdbeInt.h 4e4b15b2e1330e1636e4e01974eab2b0b985092f
|
||||
F src/vdbeapi.c 70aabe108c411e529a59d8800445513965334062
|
||||
F src/vdbeaux.c b632f9151a296c5eb22a2cc955c487ebc2347cb6
|
||||
F src/vdbeapi.c 5b08d82592bcff4470601fe78aaabebd50837860
|
||||
F src/vdbeaux.c 57361f2e761d92a254638bdbfc03fc68ae6aebc6
|
||||
F src/vdbeblob.c 359891617358deefc85bef7bcf787fa6b77facb9
|
||||
F src/vdbemem.c 3b5a9a5b375458d3e12a50ae1aaa41eeec2175fd
|
||||
F src/vdbesort.c eda25cb2d1727efca6f7862fea32b8aa33c0face
|
||||
@ -618,6 +619,7 @@ F test/corruptG.test adf79b669cbfd19e28c8191a610d083ae53a6d51
|
||||
F test/corruptH.test 79801d97ec5c2f9f3c87739aa1ec2eb786f96454
|
||||
F test/corruptI.test 075fe1d75aa1d84e2949be56b6264376c41502e4
|
||||
F test/corruptJ.test 4d5ccc4bf959464229a836d60142831ef76a5aa4
|
||||
F test/corruptK.test 814a59ec699d8546b4e29005fba3d16e933ef2fe
|
||||
F test/cost.test 1eedbfd868f806f3fa08ff072b04cf270dcf61c8
|
||||
F test/count.test cb2e0f934c6eb33670044520748d2ecccd46259c
|
||||
F test/coveridxscan.test b629e896b14df2f000a99b8d170d80589c46562c
|
||||
@ -637,7 +639,7 @@ F test/csv01.test e0ba3caaa57e4c667a0b45977689fb8082f14348
|
||||
F test/ctime.test ff6c38e822459d6ca743c34901caf57740b08b54
|
||||
F test/cursorhint.test 7bc346788390475e77a345da2b92270d04d35856
|
||||
F test/cursorhint2.test 8457e93d97f665f23f97cdbc8477d16e3480331b
|
||||
F test/date.test a6a5a48b90907bca9fbcc79a30be5a715c1ab2fc
|
||||
F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373
|
||||
F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e
|
||||
F test/dbselftest.c b2e6cfac59066dbcb7334b66304bb15a5508dd42
|
||||
F test/dbstatus.test 73149851b3aff14fc6db478e58f9083a66422cf5
|
||||
@ -1174,7 +1176,7 @@ F test/temptable.test d2c9b87a54147161bcd1822e30c1d1cd891e5b30
|
||||
F test/temptable2.test cd396beb41117a5302fff61767c35fa4270a0d5e
|
||||
F test/temptable3.test d11a0974e52b347e45ee54ef1923c91ed91e4637
|
||||
F test/temptrigger.test 38f0ca479b1822d3117069e014daabcaacefffcc
|
||||
F test/tester.tcl 67835ac17e90055f24a9cf52e5c5bce0dd511c74
|
||||
F test/tester.tcl 581f0185434daf7026ccede4c07e8d1479186ec5
|
||||
F test/thread001.test 9f22fd3525a307ff42a326b6bc7b0465be1745a5
|
||||
F test/thread002.test e630504f8a06c00bf8bbe68528774dd96aeb2e58
|
||||
F test/thread003.test ee4c9efc3b86a6a2767516a37bd64251272560a7
|
||||
@ -1560,7 +1562,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
|
||||
F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
|
||||
F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
|
||||
F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
|
||||
P c60cdb47612c05c252613e50a8ac10635469fdfe
|
||||
R dbee345c7724a1e9049a9032bbb0a60b
|
||||
P a35388eef4096c1856b025dbd90143409d4a72d3 45797feefe90cb7da53256b0c42fdaa1221d0a27
|
||||
R d076238fa06701bd917c02e95912d525
|
||||
U drh
|
||||
Z f9893159b19aa2a55c1ddc2fbced30b3
|
||||
Z 38cdac8e2d46c01757b80b6fff7491bd
|
||||
|
@ -1 +1 @@
|
||||
a35388eef4096c1856b025dbd90143409d4a72d3
|
||||
5f7fc79aa06ca9b79664c50c3c277c98a74ff9a0
|
17
src/btree.c
17
src/btree.c
@ -1355,6 +1355,7 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
nCell = pPage->nCell;
|
||||
assert( nCell==get2byte(&data[hdr+3]) );
|
||||
iCellFirst = cellOffset + 2*nCell;
|
||||
usableSize = pPage->pBt->usableSize;
|
||||
|
||||
/* This block handles pages with two or fewer free blocks and nMaxFrag
|
||||
** or fewer fragmented bytes. In this case it is faster to move the
|
||||
@ -1365,6 +1366,17 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int iFree = get2byte(&data[hdr+1]);
|
||||
if( iFree ){
|
||||
int iFree2 = get2byte(&data[iFree]);
|
||||
|
||||
/* pageFindSlot() has already verified that free blocks are sorted
|
||||
** in order of offset within the page, and that no block extends
|
||||
** past the end of the page. Provided the two free slots do not
|
||||
** overlap, this guarantees that the memmove() calls below will not
|
||||
** overwrite the usableSize byte buffer, even if the database page
|
||||
** is corrupt. */
|
||||
assert( iFree2==0 || iFree2>iFree );
|
||||
assert( iFree+get2byte(&data[iFree+2]) <= usableSize );
|
||||
assert( iFree2==0 || iFree2+get2byte(&data[iFree2+2]) <= usableSize );
|
||||
|
||||
if( 0==iFree2 || (data[iFree2]==0 && data[iFree2+1]==0) ){
|
||||
u8 *pEnd = &data[cellOffset + nCell*2];
|
||||
u8 *pAddr;
|
||||
@ -1372,11 +1384,14 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
int sz = get2byte(&data[iFree+2]);
|
||||
int top = get2byte(&data[hdr+5]);
|
||||
if( iFree2 ){
|
||||
if( iFree+sz>iFree2 ) return SQLITE_CORRUPT_BKPT;
|
||||
sz2 = get2byte(&data[iFree2+2]);
|
||||
assert( iFree+sz+sz2+iFree2-(iFree+sz) <= usableSize );
|
||||
memmove(&data[iFree+sz+sz2], &data[iFree+sz], iFree2-(iFree+sz));
|
||||
sz += sz2;
|
||||
}
|
||||
cbrk = top+sz;
|
||||
assert( cbrk+(iFree-top) <= usableSize );
|
||||
memmove(&data[cbrk], &data[top], iFree-top);
|
||||
for(pAddr=&data[cellOffset]; pAddr<pEnd; pAddr+=2){
|
||||
pc = get2byte(pAddr);
|
||||
@ -1388,10 +1403,8 @@ static int defragmentPage(MemPage *pPage, int nMaxFrag){
|
||||
}
|
||||
}
|
||||
|
||||
usableSize = pPage->pBt->usableSize;
|
||||
cbrk = usableSize;
|
||||
iCellLast = usableSize - 4;
|
||||
|
||||
for(i=0; i<nCell; i++){
|
||||
u8 *pAddr; /* The i-th cell pointer */
|
||||
pAddr = &data[cellOffset + i*2];
|
||||
|
@ -743,18 +743,19 @@ static int parseModifier(
|
||||
** or month or year.
|
||||
*/
|
||||
if( sqlite3_strnicmp(z, "start of ", 9)!=0 ) break;
|
||||
if( !p->validJD && !p->validYMD && !p->validHMS ) break;
|
||||
z += 9;
|
||||
computeYMD(p);
|
||||
p->validHMS = 1;
|
||||
p->h = p->m = 0;
|
||||
p->s = 0.0;
|
||||
p->rawS = 0;
|
||||
p->validTZ = 0;
|
||||
p->validJD = 0;
|
||||
if( sqlite3_stricmp(z,"month")==0 ){
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
}else if( sqlite3_stricmp(z,"year")==0 ){
|
||||
computeYMD(p);
|
||||
p->M = 1;
|
||||
p->D = 1;
|
||||
rc = 0;
|
||||
|
17
src/test6.c
17
src/test6.c
@ -315,8 +315,9 @@ static int writeListSync(CrashFile *pFile, int isCrash){
|
||||
assert(pWrite->zBuf);
|
||||
|
||||
#ifdef TRACE_CRASHTEST
|
||||
printf("Trashing %d sectors @ %lld (sector %d) (%s)\n",
|
||||
1+iLast-iFirst, pWrite->iOffset, iFirst, pWrite->pFile->zName
|
||||
printf("Trashing %d sectors (%d bytes) @ %lld (sector %d) (%s)\n",
|
||||
1+iLast-iFirst, (1+iLast-iFirst)*g.iSectorSize,
|
||||
pWrite->iOffset, iFirst, pWrite->pFile->zName
|
||||
);
|
||||
#endif
|
||||
|
||||
@ -827,7 +828,7 @@ static int SQLITE_TCLAPI crashNowCmd(
|
||||
}
|
||||
|
||||
/*
|
||||
** tclcmd: sqlite_crash_enable ENABLE
|
||||
** tclcmd: sqlite_crash_enable ENABLE ?DEFAULT?
|
||||
**
|
||||
** Parameter ENABLE must be a boolean value. If true, then the "crash"
|
||||
** vfs is added to the system. If false, it is removed.
|
||||
@ -839,6 +840,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
Tcl_Obj *CONST objv[]
|
||||
){
|
||||
int isEnable;
|
||||
int isDefault = 0;
|
||||
static sqlite3_vfs crashVfs = {
|
||||
2, /* iVersion */
|
||||
0, /* szOsFile */
|
||||
@ -862,14 +864,17 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
0, /* xCurrentTimeInt64 */
|
||||
};
|
||||
|
||||
if( objc!=2 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "ENABLE");
|
||||
if( objc!=2 && objc!=3 ){
|
||||
Tcl_WrongNumArgs(interp, 1, objv, "ENABLE ?DEFAULT?");
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( Tcl_GetBooleanFromObj(interp, objv[1], &isEnable) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
if( objc==3 && Tcl_GetBooleanFromObj(interp, objv[2], &isDefault) ){
|
||||
return TCL_ERROR;
|
||||
}
|
||||
|
||||
if( (isEnable && crashVfs.pAppData) || (!isEnable && !crashVfs.pAppData) ){
|
||||
return TCL_OK;
|
||||
@ -880,7 +885,7 @@ static int SQLITE_TCLAPI crashEnableCmd(
|
||||
crashVfs.mxPathname = pOriginalVfs->mxPathname;
|
||||
crashVfs.pAppData = (void *)pOriginalVfs;
|
||||
crashVfs.szOsFile = sizeof(CrashFile) + pOriginalVfs->szOsFile;
|
||||
sqlite3_vfs_register(&crashVfs, 0);
|
||||
sqlite3_vfs_register(&crashVfs, isDefault);
|
||||
}else{
|
||||
crashVfs.pAppData = 0;
|
||||
sqlite3_vfs_unregister(&crashVfs);
|
||||
|
@ -1260,7 +1260,7 @@ static int vdbeUnbind(Vdbe *p, int i){
|
||||
** following any change to the bindings of that parameter.
|
||||
*/
|
||||
assert( p->isPrepareV2 || p->expmask==0 );
|
||||
if( p->expmask & ((u32)1 << (i&0x001F)) && (i<32 || p->expmask==0xffffffff) ){
|
||||
if( p->expmask!=0 && (p->expmask & (i>=31 ? 0x80000000 : (u32)1<<i))!=0 ){
|
||||
p->expired = 1;
|
||||
}
|
||||
return SQLITE_OK;
|
||||
|
@ -4552,8 +4552,8 @@ sqlite3_value *sqlite3VdbeGetBoundValue(Vdbe *v, int iVar, u8 aff){
|
||||
*/
|
||||
void sqlite3VdbeSetVarmask(Vdbe *v, int iVar){
|
||||
assert( iVar>0 );
|
||||
if( iVar>32 ){
|
||||
v->expmask = 0xffffffff;
|
||||
if( iVar>=32 ){
|
||||
v->expmask |= 0x80000000;
|
||||
}else{
|
||||
v->expmask |= ((u32)1 << (iVar-1));
|
||||
}
|
||||
|
113
test/corruptK.test
Normal file
113
test/corruptK.test
Normal file
@ -0,0 +1,113 @@
|
||||
# 2017-03-03
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#***********************************************************************
|
||||
#
|
||||
|
||||
set testdir [file dirname $argv0]
|
||||
source $testdir/tester.tcl
|
||||
set testprefix corruptK
|
||||
|
||||
if {[permutation]=="mmap"} {
|
||||
finish_test
|
||||
return
|
||||
}
|
||||
|
||||
# This module uses hard-coded offsets which do not work if the reserved_bytes
|
||||
# value is nonzero.
|
||||
if {[nonzero_reserved_bytes]} {finish_test; return;}
|
||||
database_may_be_corrupt
|
||||
|
||||
# Initialize the database.
|
||||
#
|
||||
do_execsql_test 1.1 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(x);
|
||||
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(100)); -- make this into a free slot
|
||||
INSERT INTO t1 VALUES(randomblob(27)); -- this one will be corrupt
|
||||
INSERT INTO t1 VALUES(randomblob(800));
|
||||
|
||||
DELETE FROM t1 WHERE rowid=2; -- free the 100 byte slot
|
||||
PRAGMA page_count
|
||||
} {2}
|
||||
|
||||
|
||||
# Corrupt the database so that the blob stored immediately before
|
||||
# the free slot (rowid==3) has an overlarge length field. So that
|
||||
# we can use sqlite3_blob_write() to manipulate the size field of
|
||||
# the free slot.
|
||||
#
|
||||
# Then use sqlite3_blob_write() to set the size of said free slot
|
||||
# to 24 bytes (instead of the actual 100).
|
||||
#
|
||||
# Then use the new 24 byte slot. Leaving the in-memory version of
|
||||
# the page with zero free slots and a large nFree value. Then try
|
||||
# to allocate another slot to get to defragmentPage().
|
||||
#
|
||||
do_test 1.2 {
|
||||
db close
|
||||
hexio_write test.db [expr 1024 + 0x360] 21
|
||||
hexio_write test.db [expr 1024 + 0x363] [format %x [expr 31*2 + 12]]
|
||||
sqlite3 db test.db
|
||||
|
||||
set fd [db incrblob t1 x 3]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
seek $fd 30
|
||||
puts -nonewline $fd "\x18"
|
||||
close $fd
|
||||
} {}
|
||||
do_execsql_test 1.3 {
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
}
|
||||
do_catchsql_test 1.4 {
|
||||
INSERT INTO t1 VALUES(randomblob(90));
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
#-------------------------------------------------------------------------
|
||||
reset_db
|
||||
do_execsql_test 2.1 {
|
||||
PRAGMA page_size=1024;
|
||||
PRAGMA auto_vacuum=0;
|
||||
CREATE TABLE t1(x);
|
||||
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- free this one
|
||||
INSERT INTO t1 VALUES(randomblob(20));
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- and this one
|
||||
INSERT INTO t1 VALUES(randomblob(20)); -- corrupt this one.
|
||||
|
||||
DELETE FROM t1 WHERE rowid IN(2, 4);
|
||||
PRAGMA page_count
|
||||
} {2}
|
||||
|
||||
do_test 2.2 {
|
||||
db close
|
||||
hexio_write test.db [expr 1024 + 0x388] 53
|
||||
hexio_write test.db [expr 1024 + 0x38A] 03812C
|
||||
|
||||
sqlite3 db test.db
|
||||
set fd [db incrblob t1 x 5]
|
||||
fconfigure $fd -translation binary -encoding binary
|
||||
|
||||
seek $fd 22
|
||||
puts -nonewline $fd "\x5d"
|
||||
close $fd
|
||||
} {}
|
||||
|
||||
do_catchsql_test 2.3 {
|
||||
INSERT INTO t1 VALUES(randomblob(900));
|
||||
} {1 {database disk image is malformed}}
|
||||
|
||||
|
||||
|
||||
|
||||
finish_test
|
@ -596,5 +596,17 @@ datetest 16.29 {datetime(5373484,'-176546 months')} NULL
|
||||
datetest 16.30 {datetime(5373484,'-14712 years')} {-4713-12-31 12:00:00}
|
||||
datetest 16.31 {datetime(5373484,'-14713 years')} NULL
|
||||
|
||||
# 2017-03-02: Wrong 'start of day' computation.
|
||||
# https://www.sqlite.org/src/info/6097cb92745327a1
|
||||
#
|
||||
datetest 17.1 {datetime(2457754, 'start of day')} {2016-12-31 00:00:00}
|
||||
datetest 17.2 {datetime(2457828)} {2017-03-15 12:00:00}
|
||||
datetest 17.3 {datetime(2457828,'start of day')} {2017-03-15 00:00:00}
|
||||
datetest 17.4 {datetime(2457828,'start of month')} {2017-03-01 00:00:00}
|
||||
datetest 17.5 {datetime(2457828,'start of year')} {2017-01-01 00:00:00}
|
||||
datetest 17.6 {datetime(37,'start of year')} NULL
|
||||
datetest 17.7 {datetime(38,'start of year')} {-4712-01-01 00:00:00}
|
||||
|
||||
|
||||
|
||||
finish_test
|
||||
|
@ -1533,6 +1533,7 @@ proc crashsql {args} {
|
||||
set tclbody {}
|
||||
set crashfile ""
|
||||
set dc ""
|
||||
set dfltvfs 0
|
||||
set sql [lindex $args end]
|
||||
|
||||
for {set ii 0} {$ii < [llength $args]-1} {incr ii 2} {
|
||||
@ -1546,7 +1547,8 @@ proc crashsql {args} {
|
||||
elseif {$n>1 && [string first $z -file]==0} {set crashfile $z2} \
|
||||
elseif {$n>1 && [string first $z -tclbody]==0} {set tclbody $z2} \
|
||||
elseif {$n>1 && [string first $z -blocksize]==0} {set blocksize "-s $z2" } \
|
||||
elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" } \
|
||||
elseif {$n>1 && [string first $z -characteristics]==0} {set dc "-c {$z2}" }\
|
||||
elseif {$n>1 && [string first $z -dfltvfs]==0} {set dfltvfs $z2 }\
|
||||
else { error "Unrecognized option: $z" }
|
||||
}
|
||||
|
||||
@ -1560,7 +1562,7 @@ proc crashsql {args} {
|
||||
set cfile [string map {\\ \\\\} [file nativename [file join [get_pwd] $crashfile]]]
|
||||
|
||||
set f [open crash.tcl w]
|
||||
puts $f "sqlite3_crash_enable 1"
|
||||
puts $f "sqlite3_crash_enable 1 $dfltvfs"
|
||||
puts $f "sqlite3_crashparams $blocksize $dc $crashdelay $cfile"
|
||||
puts $f "sqlite3_test_control_pending_byte $::sqlite_pending_byte"
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user