-C Remove\sleftover\s"breakpoint"\sfrom\sthe\sfuzz.test\sscript.\s(CVS\s6115)
-D 2009-01-06T00:11:26
+C Add\ssome\ssavepoint\srelated\stest\scases\sand\sfix\sa\sfew\sproblems.\s(CVS\s6116)
+D 2009-01-06T13:40:08
F Makefile.arm-wince-mingw32ce-gcc fcd5e9cd67fe88836360bb4f9ef4cb7f8e2fb5a0
F Makefile.in 05461a9b5803d5ad10c79f989801e9fd2cc3e592
F Makefile.linux-gcc d53183f4aa6a9192d249731c90dbdffbd2c68654
F src/os_os2.c bed77dc26e3a95ce4a204936b9a1ca6fe612fcc5
F src/os_unix.c e6eacc7ec735ded605fefcbaf250058baa8feb12
F src/os_win.c 496e3ceb499aedc63622a89ef76f7af2dd902709
-F src/pager.c b12dbe7e6c561d1675ddcc9c50b997c0692212e0
+F src/pager.c 9c9bc48765cb8d6c4445d3628bed52a0e0af762c
F src/pager.h 75396879910768a0af03a4af8413e798d84c096f
F src/parse.y 4d0e33a702dc3ea7b69d8ae1914b3fbd32e46057
F src/pcache.c 16dc8da6e6ba6250f8dfd9ee46036db1cbceedc6
F test/pagesize.test 0d9ff3fedfce6e5ffe8fa7aca9b6d3433a2e843b
F test/pcache.test 515b4c26e9f57660357dfff5b6b697acac1abc5f
F test/pcache2.test 46efd980a89f737847b99327bda19e08fe11e402
-F test/permutations.test dccfc24254ab8d9cb9098e790c12fae52865f65f
+F test/permutations.test 9e667c6b027856fc9b1d3d82cb51f0744885d010
F test/pragma.test 325aa0833d483b8e0c98e8196f1cc49fa5d8c336
F test/pragma2.test 5364893491b9231dd170e3459bfc2e2342658b47
F test/printf.test 262a5acd3158f788e9bdf7f18d718f3af32ff6ef
F test/rowid.test 1c8fc43c60d273e6ea44dfb992db587f3164312c
F test/rtree.test b85fd4f0861a40ca366ac195e363be2528dcfadf
F test/safety.test b69e2b2dd5d52a3f78e216967086884bbc1a09c6
-F test/savepoint.test 154001ac2863714eadd9c79865fa07faeda3d3a4
+F test/savepoint.test 7c743ac26268b042f8e16797c755644240c724e5
F test/savepoint2.test 18f6c75d5c133b93838019df8988b8cdf379d3de
F test/savepoint3.test 1a0b1c0f59c6ae4402bfbca7cec29d4b1b272ff0
F test/savepoint4.test fd8850063e3c40565545f5c291e7f79a30591670
F test/savepoint5.test 0735db177e0ebbaedc39812c8d065075d563c4fd
-F test/savepoint6.test 4808a41d2426d96d2fd742573c374f1d3ba90c61
+F test/savepoint6.test 7d584a665cb6e4f0c24d7a8ae7f8985461c683b1
F test/schema.test a8b000723375fd42c68d310091bdbd744fde647c
F test/schema2.test 35e1c9696443d6694c8980c411497c2b5190d32e
F test/select1.test d0a4cad954fd41c030ec16ffbd2d08a4c0548742
F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
-P a7015625610624be1645e918d0a62cf85bec86ce
-R f82e1e4aa3ea5aea66445267a01cdb30
-U drh
-Z b753d108e96492fb67c6923669f55766
+P c2482d8877a5f9e387b288377e410ae1b8267f3c
+R 99d979f1a5afc6b0e70e7af446024426
+U danielk1977
+Z 76e17593f6a27ee09beef4dfa4478a92
-c2482d8877a5f9e387b288377e410ae1b8267f3c
\ No newline at end of file
+8c62ea4fded2251e9daf16f2a050f94359299d76
\ No newline at end of file
** file simultaneously, or one process from reading the database while
** another is writing.
**
-** @(#) $Id: pager.c,v 1.529 2009/01/03 12:55:18 drh Exp $
+** @(#) $Id: pager.c,v 1.530 2009/01/06 13:40:08 danielk1977 Exp $
*/
#ifndef SQLITE_OMIT_DISKIO
#include "sqliteInt.h"
** Macros for troubleshooting. Normally turned off
*/
#if 0
+int sqlite3PagerTrace=1; /* True to enable tracing */
#define sqlite3DebugPrintf printf
-#define PAGERTRACE1(X) sqlite3DebugPrintf(X)
-#define PAGERTRACE2(X,Y) sqlite3DebugPrintf(X,Y)
-#define PAGERTRACE3(X,Y,Z) sqlite3DebugPrintf(X,Y,Z)
-#define PAGERTRACE4(X,Y,Z,W) sqlite3DebugPrintf(X,Y,Z,W)
-#define PAGERTRACE5(X,Y,Z,W,V) sqlite3DebugPrintf(X,Y,Z,W,V)
+#define PAGERTRACE1(X) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X)
+#define PAGERTRACE2(X,Y) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y)
+#define PAGERTRACE3(X,Y,Z) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z)
+#define PAGERTRACE4(X,Y,Z,W) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W)
+#define PAGERTRACE5(X,Y,Z,W,V) if( sqlite3PagerTrace ) sqlite3DebugPrintf(X,Y,Z,W,V)
#else
#define PAGERTRACE1(X)
#define PAGERTRACE2(X,Y)
if( rc!=SQLITE_OK ) return rc;
rc = sqlite3OsRead(jfd, aData, pPager->pageSize, offset+4);
if( rc!=SQLITE_OK ) return rc;
- pPager->journalOff += pPager->pageSize + 4;
+ pPager->journalOff += pPager->pageSize + 4 + (isMainJrnl?4:0);
/* Sanity checking on the page. This is more important that I originally
** thought. If a power failure occurs while the journal is being written,
if( isMainJrnl ){
rc = read32bits(jfd, offset+pPager->pageSize+4, &cksum);
if( rc ) return rc;
- pPager->journalOff += 4;
if( !isSavepnt && pager_cksum(pPager, aData)!=cksum ){
return SQLITE_DONE;
}
if( pgno>pPager->dbFileSize ){
pPager->dbFileSize = pgno;
}
+ }else if( !isMainJrnl && pPg==0 ){
+ /* If this is a rollback of a savepoint and data was not written to
+ ** the database and the page is not in-memory, there is a potential
+ ** problem. When the page is next fetched by the b-tree layer, it
+ ** will be read from the database file, which may or may not be
+ ** current.
+ **
+ ** There are a couple of different ways this can happen. All are quite
+ ** obscure. When not running in synchronous mode, this can only happen
+ ** if the page is on the free-list at the start of the transaction, then
+ ** populated, then moved using sqlite3PagerMovepage().
+ **
+ ** The solution is to add an in-memory page to the cache containing
+ ** the data just read from the sub-journal. Mark the page as dirty
+ ** and if the pager requires a journal-sync, then mark the page as
+ ** requiring a journal-sync before it is written.
+ */
+ assert( isSavepnt );
+ if( (rc = sqlite3PagerAcquire(pPager, pgno, &pPg, 1)) ){
+ return rc;
+ }
+ pPg->flags &= ~PGHDR_NEED_READ;
+ sqlite3PcacheMakeDirty(pPg);
}
if( pPg ){
/* No page should ever be explicitly rolled back that is in use, except
i64 szJ; /* Size of the full journal */
i64 iHdrOff; /* End of first segment of main-journal records */
Pgno ii; /* Loop counter */
- int rc; /* Return code */
+ int rc = SQLITE_OK; /* Return code */
Bitvec *pDone = 0; /* Bitvec to ensure pages played back only once */
/* Allocate a bitvec to use to store the set of pages rolled back */
/* Truncate the database back to the size it was before the
** savepoint being reverted was opened.
*/
- rc = pager_truncate(pPager, pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize);
+ pPager->dbSize = pSavepoint?pSavepoint->nOrig:pPager->dbOrigSize;
assert( pPager->state>=PAGER_SHARED );
/* Now roll back all main journal file records that occur after byte
pPager->exclusiveMode = 0;
pager_reset(pPager);
if( !MEMDB ){
+ /* Set Pager.journalHdr to -1 for the benefit of the pager_playback()
+ ** call which may be made from within pagerUnlockAndRollback(). If it
+ ** is not -1, then the unsynced portion of an open journal file may
+ ** be played back into the database. If a power failure occurs while
+ ** this is happening, the database may become corrupt.
+ */
+ pPager->journalHdr = -1;
pagerUnlockAndRollback(pPager);
}
enable_simulated_io_errors();
return SQLITE_OK;
}
+/*
+** Add the page to the sub-journal. It is the callers responsibility to
+** use subjRequiresPage() to check that it is really required before
+** calling this function.
+*/
+static int subjournalPage(PgHdr *pPg){
+ int rc;
+ void *pData = pPg->pData;
+ Pager *pPager = pPg->pPager;
+ i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
+ char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
+
+ PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno);
+
+ assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
+ rc = write32bits(pPager->sjfd, offset, pPg->pgno);
+ if( rc==SQLITE_OK ){
+ rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
+ }
+ if( rc==SQLITE_OK ){
+ pPager->stmtNRec++;
+ assert( pPager->nSavepoint>0 );
+ rc = addToSavepointBitvecs(pPager, pPg->pgno);
+ }
+ return rc;
+}
+
+
/*
** This function is called by the pcache layer when it has reached some
** soft memory limit. The argument is a pointer to a purgeable Pager
}
if( rc==SQLITE_OK ){
pPg->pDirty = 0;
- rc = pager_write_pagelist(pPg);
+ if( pPg->pgno>pPager->dbSize && subjRequiresPage(pPg) ){
+ rc = subjournalPage(pPg);
+ }
+ if( rc==SQLITE_OK ){
+ rc = pager_write_pagelist(pPg);
+ }
}
if( rc!=SQLITE_OK ){
pager_error(pPager, rc);
}
if( rc==SQLITE_OK ){
+ PAGERTRACE3("STRESS %d page %d\n", PAGERID(pPager), pPg->pgno);
sqlite3PcacheMakeClean(pPg);
}
return rc;
** in that it omits the checksums and the header.
*/
if( subjRequiresPage(pPg) ){
- i64 offset = pPager->stmtNRec*(4+pPager->pageSize);
- char *pData2 = CODEC2(pPager, pData, pPg->pgno, 7);
- assert( pageInJournal(pPg) || pPg->pgno>pPager->dbOrigSize );
- rc = write32bits(pPager->sjfd, offset, pPg->pgno);
- if( rc==SQLITE_OK ){
- rc = sqlite3OsWrite(pPager->sjfd, pData2, pPager->pageSize, offset+4);
- }
- PAGERTRACE3("STMT-JOURNAL %d page %d @ %d\n", PAGERID(pPager), pPg->pgno);
- if( rc!=SQLITE_OK ){
- return rc;
- }
- pPager->stmtNRec++;
- assert( pPager->nSavepoint>0 );
- rc = addToSavepointBitvecs(pPager, pPg->pgno);
- if( rc!=SQLITE_OK ){
- assert( rc==SQLITE_NOMEM );
- return rc;
- }
+ rc = subjournalPage(pPg);
}
}
#
#***********************************************************************
#
-# $Id: permutations.test,v 1.42 2009/01/03 15:06:38 danielk1977 Exp $
+# $Id: permutations.test,v 1.43 2009/01/06 13:40:08 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
set ISQUICK 1
catch {db close}
register_jt_vfs -default ""
+ #sqlite3_instvfs binarylog -default binarylog ostrace.bin
} -shutdown {
+ #sqlite3_instvfs destroy binarylog
unregister_jt_vfs
} -include [concat $::ALLTESTS savepoint6.test
] -exclude {
#
#***********************************************************************
#
-# $Id: savepoint.test,v 1.7 2009/01/03 15:06:38 danielk1977 Exp $
+# $Id: savepoint.test,v 1.8 2009/01/06 13:40:08 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
execsql { PRAGMA integrity_check }
} {ok}
+do_test savepoint-7.5.1 {
+ execsql {
+ PRAGMA incremental_vacuum;
+ CREATE TABLE t5(x, y);
+ INSERT INTO t5 VALUES(1, randstr(1000,1000));
+ INSERT INTO t5 VALUES(2, randstr(1000,1000));
+ INSERT INTO t5 VALUES(3, randstr(1000,1000));
+
+ BEGIN;
+ INSERT INTO t5 VALUES(4, randstr(1000,1000));
+ INSERT INTO t5 VALUES(5, randstr(1000,1000));
+ DELETE FROM t5 WHERE x=1 OR x=2;
+ SAVEPOINT one;
+ PRAGMA incremental_vacuum;
+ SAVEPOINT two;
+ INSERT INTO t5 VALUES(1, randstr(1000,1000));
+ INSERT INTO t5 VALUES(2, randstr(1000,1000));
+ ROLLBACK TO two;
+ ROLLBACK TO one;
+ COMMIT;
+ PRAGMA integrity_check;
+ }
+} {ok}
+do_test savepoint-7.5.2 {
+ execsql {
+ DROP TABLE t5;
+ }
+} {}
+
# Test oddly named and quoted savepoints.
#
do_test savepoint-8-1 {
#
#***********************************************************************
#
-# $Id: savepoint6.test,v 1.1 2009/01/03 10:41:29 danielk1977 Exp $
+# $Id: savepoint6.test,v 1.2 2009/01/06 13:40:08 danielk1977 Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
-do_test savepoint6-1.1 {
- execsql {
+proc sql {zSql} {
+ uplevel db eval [list $zSql]
+ #puts stderr "$zSql ;"
+}
+
+set DATABASE_SCHEMA {
PRAGMA auto_vacuum = incremental;
CREATE TABLE t1(x, y);
CREATE UNIQUE INDEX i1 ON t1(x);
CREATE INDEX i2 ON t1(y);
- }
-} {}
+}
#--------------------------------------------------------------------------
# In memory database state.
# delete_rows XVALUES
#
proc savepoint {zName} {
- catch { db eval "SAVEPOINT $zName" }
+ catch { sql "SAVEPOINT $zName" }
lappend ::lSavepoint [list $zName [array get ::aEntry]]
}
proc rollback {zName} {
- catch { db eval "ROLLBACK TO $zName" }
+ catch { sql "ROLLBACK TO $zName" }
for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
set zSavepoint [lindex $::lSavepoint $i 0]
if {$zSavepoint eq $zName} {
}
proc release {zName} {
- catch { db eval "RELEASE $zName" }
+ catch { sql "RELEASE $zName" }
for {set i [expr {[llength $::lSavepoint]-1}]} {$i>=0} {incr i -1} {
set zSavepoint [lindex $::lSavepoint $i 0]
if {$zSavepoint eq $zName} {
break
}
}
+
+ if {[llength $::lSavepoint] == 0} {
+ #puts stderr "-- End of transaction!!!!!!!!!!!!!"
+ }
}
proc insert_rows {lX} {
set y [x_to_y $x]
# Update database [db]
- db eval {INSERT OR REPLACE INTO t1 VALUES($x, $y)}
+ sql "INSERT OR REPLACE INTO t1 VALUES($x, '$y')"
# Update the Tcl database.
set ::aEntry($x) $y
proc delete_rows {lX} {
foreach x $lX {
# Update database [db]
- db eval {DELETE FROM t1 WHERE x = $x}
+ sql "DELETE FROM t1 WHERE x = $x"
# Update the Tcl database.
unset -nocomplain ::aEntry($x)
}
#-------------------------------------------------------------------------
-db eval { PRAGMA cache_size = 10 }
-expr srand(0)
-
proc database_op {} {
set i [expr int(rand()*2)]
if {$i==0} {
delete_rows [random_integers 100 1000]
set i [expr int(rand()*3)]
if {$i==0} {
- db eval {PRAGMA incremental_vacuum}
+ sql {PRAGMA incremental_vacuum}
}
}
}
set C [lindex $cmds [expr int(rand()*6)]]
set N [lindex $names [expr int(rand()*5)]]
+ #puts stderr " $C $N ; "
+ #flush stderr
+
$C $N
return ok
}
-do_test savepoint6-2.1 {
+expr srand(0)
+
+############################################################################
+############################################################################
+# Start of test cases.
+
+do_test savepoint6-1.1 {
+ sql $DATABASE_SCHEMA
+} {}
+do_test savepoint6-1.2 {
+ insert_rows {
+ 497 166 230 355 779 588 394 317 290 475 362 193 805 851 564
+ 763 44 930 389 819 765 760 966 280 538 414 500 18 25 287 320
+ 30 382 751 87 283 981 429 630 974 421 270 810 405
+ }
+
savepoint one
- insert_rows [random_integers 100 1000]
+ insert_rows 858
+ delete_rows 930
+ savepoint two
+ execsql {PRAGMA incremental_vacuum}
+ savepoint three
+ insert_rows 144
+ rollback three
+ rollback two
release one
- checkdb
-} {ok}
-for {set i 0} {$i < 1000} {incr i} {
- do_test savepoint6-3.$i.1 {
- savepoint_op
- } {ok}
+ execsql {SELECT count(*) FROM t1}
+} {44}
+
+foreach zSetup [list {
+ set testname normal
+ sqlite3 db test.db
+} {
+ set testname tempdb
+ sqlite3 db ""
+} {
+ set testname smallcache
+ sqlite3 db test.db
+ sql { PRAGMA cache_size = 10 }
+}] {
+
+ unset -nocomplain ::lSavepoint
+ unset -nocomplain ::aEntry
- do_test savepoint6-3.$i.2 {
- database_op
- database_op
+ db close
+ file delete -force test.db
+ eval $zSetup
+ sql $DATABASE_SCHEMA
+
+ do_test savepoint6-$testname.setup {
+ savepoint one
+ insert_rows [random_integers 100 1000]
+ release one
checkdb
} {ok}
+
+ for {set i 0} {$i < 1000} {incr i} {
+ do_test savepoint6-$testname.$i.1 {
+ savepoint_op
+ checkdb
+ } {ok}
+
+ do_test savepoint6-$testname.$i.2 {
+ database_op
+ database_op
+ checkdb
+ } {ok}
+ }
}
unset -nocomplain ::lSavepoint