Index: src/backup.c ================================================================== --- src/backup.c +++ src/backup.c @@ -411,11 +411,17 @@ ** is to make sure that the schema-version really does change in ** the case where the source and destination databases have the ** 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); } if( destMode==PAGER_JOURNALMODE_WAL ){ @@ -445,10 +451,11 @@ nDestTruncate--; } }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 )); /* This call ensures that all data required to recreate the original Index: src/btree.c ================================================================== --- src/btree.c +++ src/btree.c @@ -2528,10 +2528,24 @@ #endif pBt->nPage = 1; data[31] = 1; 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- ** transaction. If the second argument is 2 or more and exclusive Index: src/btree.h ================================================================== --- src/btree.h +++ src/btree.h @@ -114,10 +114,12 @@ int sqlite3BtreeClearTable(Btree*, int, int*); 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 ** to constants so that the offset of the corresponding field in an Index: src/pager.c ================================================================== --- src/pager.c +++ src/pager.c @@ -5663,11 +5663,11 @@ UNUSED_PARAMETER(isDirectMode); #else # define DIRECT_MODE isDirectMode #endif - if( !pPager->changeCountDone && pPager->dbSize>0 ){ + if( !pPager->changeCountDone && ALWAYS(pPager->dbSize>0) ){ PgHdr *pPgHdr; /* Reference to page 1 */ assert( !pPager->tempFile && isOpen(pPager->fd) ); /* Open page 1 of the file for writing. */ ADDED test/backup4.test Index: test/backup4.test ================================================================== --- /dev/null +++ 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 backup4 + +#------------------------------------------------------------------------- +# 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 + Index: test/pager1.test ================================================================== --- test/pager1.test +++ test/pager1.test @@ -1363,11 +1363,11 @@ sqlite3_backup B db2 main db main list [B step 10000] [B finish] } {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 #------------------------------------------------------------------------- # Test that regardless of the value returned by xSectorSize(), the # minimum effective sector-size is 512 and the maximum 65536 bytes.