diff --git a/manifest b/manifest index ca0c8d1cc8..fa99540d0a 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\sthe\sshowdb\stool\sto\sbe\scompiled\swith\sMSVC. -D 2012-10-13T09:31:20.156 +C Ensure\sthat\swhen\sthe\ssource\sof\sa\sbackup\sis\sa\sdatabase\sthat\sis\szero\sbytes\sin\ssize,\sthe\sfinal\sdestination\sdatabase\sconsists\sof\sat\sleast\sone\spage.\sTruncating\sit\sto\szero\sbytes\sis\sequivalent\sto\szeroing\sthe\sschema\scookie\sand\schange\scounter,\swhich\scan\scause\sproblems\sfor\sexisting\sclients. +D 2012-10-13T19:58:11.924 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f F Makefile.in 5f4f26109f9d80829122e0e09f9cda008fa065fb F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23 @@ -118,11 +118,11 @@ F src/alter.c f8db986c03eb0bfb221523fc9bbb9d0b70de3168 F src/analyze.c 7553068d21e32a57fc33ab6b2393fc8c1ba41410 F src/attach.c 34c15ecd686e58f08e5bb1389e28a0b65c2c83db F src/auth.c 523da7fb4979469955d822ff9298352d6b31de34 -F src/backup.c afc067b9a9050ff48b9d46285c53d096c556a73d +F src/backup.c cab40f2c1fe79d6eb93d3b4086c78c41ad2fa5d0 F src/bitvec.c 26675fe8e431dc555e6f2d0e11e651d172234aa1 F src/btmutex.c 976f45a12e37293e32cae0281b15a21d48a8aaa7 -F src/btree.c 14de53ebb334633ee632ab3c5b9262cfe7cbe455 -F src/btree.h 078f76b28c338ab6eb6dd7324d63ee54463aeb6c +F src/btree.c 299377f0793038ad3ea322907fbda7fbea615094 +F src/btree.h 3ad7964d6c5b1c7bff569aab6adfa075f8bf06cd F src/btreeInt.h 4e5c2bd0f9b36b2a815a6d84f771a61a65830621 F src/build.c f35dac52924a6e8e6346a90f0c195a84e28b6f21 F src/callback.c d7e46f40c3cf53c43550b7da7a1d0479910b62cc @@ -289,6 +289,7 @@ F test/avtrans.test 0252654f4295ddda3b2cce0e894812259e655a85 F test/backcompat.test ecd841f3a3bfb81518721879cc56a760670e3198 F test/backup.test c9cdd23a495864b9edf75a9fa66f5cb7e10fcf62 F test/backup2.test 34986ef926ea522911a51dfdb2f8e99b7b75ebcf +F test/backup4.test cd78366929236357d3b36cbec768a67258817830 F test/backup_ioerr.test 40d208bc9224b666ee3ed423f49bc9062a36a9d0 F test/backup_malloc.test 7162d604ec2b4683c4b3799a48657fb8b5e2d450 F test/badutf.test d5360fc31f643d37a973ab0d8b4fb85799c3169f @@ -637,7 +638,7 @@ F test/openv2.test 0d3040974bf402e19b7df4b783e447289d7ab394 F test/orderby1.test ef4f7c40df81b9a4303a718433d34052f07db47d F test/orderby2.test bc11009f7cd99d96b1b11e57b199b00633eb5b04 F test/oserror.test 50417780d0e0d7cd23cf12a8277bb44024765df3 -F test/pager1.test 2163c6ef119f497a71a84137c957c63763e640ab +F test/pager1.test 07116f72a61960b882952e7472cc2846d161d6e2 F test/pager2.test 745b911dde3d1f24ae0870bd433dfa83d7c658c1 F test/pager3.test 3856d9c80839be0668efee1b74811b1b7f7fc95f F test/pagerfault.test 452f2cc23e3bfcfa935f4442aec1da4fe1dc0442 @@ -1019,7 +1020,10 @@ F tool/vdbe-compress.tcl f12c884766bd14277f4fcedcae07078011717381 F tool/warnings-clang.sh f6aa929dc20ef1f856af04a730772f59283631d4 F tool/warnings.sh fbc018d67fd7395f440c28f33ef0f94420226381 F tool/win/sqlite.vsix 67d8a99aceb56384a81b3f30d6c71743146d2cc9 -P de784399ed1f0e27fc875e32719643d19819c8fb -R eae4686c36e29e07358a0f64b1678cc7 -U mistachkin -Z 3d1371a2f131ddfec977348963d5fb7d +P dce391fc6302301e9ac53a5e4fc69f3bd7ba13a7 +R d0a8a8a7a76a5a8279230581af3ba8e0 +T *branch * zero-byte-backup-fix +T *sym-zero-byte-backup-fix * +T -sym-trunk * +U dan +Z 43bd238d77d2ace9bdb6f46c1f518da4 diff --git a/manifest.uuid b/manifest.uuid index 3bf3a77875..b142990ca5 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -dce391fc6302301e9ac53a5e4fc69f3bd7ba13a7 \ No newline at end of file +af5c9ee4a453f71c03f24ad08824ced6c1b97afb \ No newline at end of file diff --git a/src/backup.c b/src/backup.c index 6abc11c20c..b234716d61 100644 --- a/src/backup.c +++ b/src/backup.c @@ -413,7 +413,13 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ ** same schema version. */ if( rc==SQLITE_DONE ){ - rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); + if( nSrcPage==0 ){ + rc = sqlite3BtreeNewDb(p->pDest); + nSrcPage = 1; + } + if( rc==SQLITE_OK || rc==SQLITE_DONE ){ + rc = sqlite3BtreeUpdateMeta(p->pDest,1,p->iDestSchema+1); + } if( rc==SQLITE_OK ){ if( p->pDestDb ){ sqlite3ResetAllSchemasOfConnection(p->pDestDb); @@ -447,6 +453,7 @@ int sqlite3_backup_step(sqlite3_backup *p, int nPage){ }else{ nDestTruncate = nSrcPage * (pgszSrc/pgszDest); } + assert( nDestTruncate>0 ); sqlite3PagerTruncateImage(pDestPager, nDestTruncate); if( pgszSrc= iSize || ( + assert( nDestTruncate==0 + || (i64)nDestTruncate*(i64)pgszDest >= iSize || ( nDestTruncate==(int)(PENDING_BYTE_PAGE(p->pDest->pBt)-1) && iSize>=PENDING_BYTE && iSize<=PENDING_BYTE+pgszDest )); diff --git a/src/btree.c b/src/btree.c index 4ee0c860a7..c0cda1281b 100644 --- a/src/btree.c +++ b/src/btree.c @@ -2531,6 +2531,20 @@ static int newDatabase(BtShared *pBt){ return SQLITE_OK; } +/* +** Initialize the first page of the database file (creating a database +** consisting of a single page and no schema objects). Return SQLITE_OK +** if successful, or an SQLite error code otherwise. +*/ +int sqlite3BtreeNewDb(Btree *p){ + int rc; + sqlite3BtreeEnter(p); + p->pBt->nPage = 0; + rc = newDatabase(p->pBt); + sqlite3BtreeLeave(p); + return rc; +} + /* ** Attempt to start a new transaction. A write-transaction ** is started if the second argument is nonzero, otherwise a read- diff --git a/src/btree.h b/src/btree.h index 0efa0cdcdc..d4c9fe37d7 100644 --- a/src/btree.h +++ b/src/btree.h @@ -117,6 +117,8 @@ void sqlite3BtreeTripAllCursors(Btree*, int); void sqlite3BtreeGetMeta(Btree *pBtree, int idx, u32 *pValue); int sqlite3BtreeUpdateMeta(Btree*, int idx, u32 value); +int sqlite3BtreeNewDb(Btree *p); + /* ** The second parameter to sqlite3BtreeGetMeta or sqlite3BtreeUpdateMeta ** should be one of the following values. The integer values are assigned diff --git a/test/backup4.test b/test/backup4.test new file mode 100644 index 0000000000..1d24e16d57 --- /dev/null +++ b/test/backup4.test @@ -0,0 +1,106 @@ +# 2012 October 13 +# +# 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. +# +#*********************************************************************** +# +# The tests in this file verify that if an empty database (zero bytes in +# size) is used as the source of a backup operation, the final destination +# database is one page in size. +# +# The destination must consist of at least one page as truncating a +# database file to zero bytes is equivalent to resetting the database +# schema cookie and change counter. Doing that could cause other clients +# to become confused and continue using out-of-date cache data. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix backup + +#------------------------------------------------------------------------- +# At one point this test was failing because [db] was using an out of +# date schema in test case 1.2. +# +do_execsql_test 1.0 { + CREATE TABLE t1(x, y, UNIQUE(x, y)); + INSERT INTO t1 VALUES('one', 'two'); + SELECT * FROM t1 WHERE x='one'; + PRAGMA integrity_check; +} {one two ok} + +do_test 1.1 { + sqlite3 db1 :memory: + db1 backup test.db + sqlite3 db1 test.db + db1 eval { + CREATE TABLE t1(x, y); + INSERT INTO t1 VALUES('one', 'two'); + } + db1 close +} {} + +do_execsql_test 1.2 { + SELECT * FROM t1 WHERE x='one'; + PRAGMA integrity_check; +} {one two ok} + +db close +forcedelete test.db +forcedelete test.db2 +sqlite3 db test.db + +#------------------------------------------------------------------------- +# Test that if the source is zero bytes, the destination database +# consists of a single page only. +# +do_execsql_test 2.1 { + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); +} + +do_test 2.2 { file size test.db } 3072 + +do_test 2.3 { + sqlite3 db1 test.db2 + db1 backup test.db + db1 close + file size test.db +} {1024} + +do_test 2.4 { file size test.db2 } 0 + +db close +forcedelete test.db +forcedelete test.db2 +sqlite3 db test.db + +#------------------------------------------------------------------------- +# Test that if the destination has a page-size larger than the implicit +# page-size of the source, the final destination database still consists +# of a single page. +# +do_execsql_test 3.1 { + PRAGMA page_size = 4096; + CREATE TABLE t1(a, b); + CREATE INDEX i1 ON t1(a, b); +} + +do_test 3.2 { file size test.db } 12288 + +do_test 3.3 { + sqlite3 db1 test.db2 + db1 backup test.db + db1 close + file size test.db +} {1024} + +do_test 3.4 { file size test.db2 } 0 + +finish_test + diff --git a/test/pager1.test b/test/pager1.test index 61a0c0ccdb..fac434037e 100644 --- a/test/pager1.test +++ b/test/pager1.test @@ -1365,7 +1365,7 @@ do_test pager1-9.4.1 { } {SQLITE_DONE SQLITE_OK} do_test pager1-9.4.2 { list [file size test.db2] [file size test.db] -} {0 0} +} {1024 0} db2 close #-------------------------------------------------------------------------