diff --git a/manifest b/manifest index f0a6775b90..4f21e27075 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Tests\sto\simprove\scoverage\sof\svdbemem.c.\s(CVS\s2200) -D 2005-01-12T07:15:05 +C Tests\sto\simprove\scoverage\sof\svdbeaux.c.\s(CVS\s2201) +D 2005-01-12T09:10:40 F Makefile.in ecf441ac5ca1ccfc8748a8a9537706e69893dfa4 F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README a01693e454a00cc117967e3f9fdab2d4d52e9bc1 @@ -76,11 +76,11 @@ F src/update.c 0979397c41ac29c54fe0cc687a356d8629a633af F src/utf.c 9bece2c7b94d9002ab1bb900a7658c6f826b0f74 F src/util.c 4511559caf83e70a036deb5c56f10ddf35a688fb F src/vacuum.c 1a9db113a027461daaf44724c71dd1ebbd064203 -F src/vdbe.c b8e619fbaa59be3e537804469d8cedd4a98d3c2e +F src/vdbe.c a89bb4eefa60226ddfdf8e708ea9352c0a124da3 F src/vdbe.h 067ca8d6750ba4f69a50284765e5883dee860181 -F src/vdbeInt.h 0f74561e629af86172de7cdf0ecaea014c51696c +F src/vdbeInt.h f2b5f54d9881bbc89fff02d95f3f825ade68bce2 F src/vdbeapi.c 0cf3bdc1072616bedc8eec7fc22e3f5a169d33fd -F src/vdbeaux.c 60c24559b458d4da368694c0d322326b22edffd1 +F src/vdbeaux.c 0675db9f7f801b36e2e71504f5380feeadba56bc F src/vdbemem.c 5d9fd8de5d4f5d1f3446c9a90a7b3f8c38557821 F src/where.c 3a0d08505e298242f6f151f019a05129a4f8704c F tclinstaller.tcl 36478c3bbfc5b93ceac42d94e3c736937b808432 @@ -138,7 +138,7 @@ F test/insert.test 56f9c20c9adc8d707490c4ffa5d4daa94826ea03 F test/insert2.test 0bb50ff999e35a21549d8ee5dc44db8ac24d31a7 F test/interrupt.test 5b4d8389e6cf2d01b94f87cfd02d9df1073bfb2d F test/intpkey.test b57cf5236fde1bd8cbc1388fa0c91908f6fd9194 -F test/ioerr.test 01ac547c4a6fc53fcd9fe7ecc9698ab5d827093a +F test/ioerr.test 0563e3eace01d94661899a90e5888b7817fb57e0 F test/join.test ea8c77b9fbc377fe553cdb5ce5f1bd72021dca5d F test/join2.test c97e4c5aa65dea462145529e58212a709b4722b8 F test/join3.test 67dc0d7c8dab3fff25796d0f3c3fd9c999aeded3 @@ -150,7 +150,7 @@ F test/lock.test 32fe28e5030f25f23bcf6beef440675b0d848413 F test/lock2.test 59c3dd7d9b24d1bf7ec91b2d1541c37e97939d5f F test/lock3.test 615111293cf32aa2ed16d01c6611737651c96fb9 F test/main.test a60a1d234b5f5784097973bd395514ca56003ef1 -F test/malloc.test 79c5e0676a8346884b3197c811f2eac60b0521cc +F test/malloc.test c3985c0a5a2f28dbfdb68a4e07886f9090feeda1 F test/memdb.test 532aac7128a3da494cddc4461d76c6e3988f771b F test/memleak.test f1fa233f8295dd1d955a00d5e5ee857850f27f29 F test/minmax.test e7048476940df0af11d0f2cf687572f557cd0b29 @@ -268,7 +268,7 @@ F www/tclsqlite.tcl e73f8f8e5f20e8277619433f7970060ab01088fc F www/vdbe.tcl 095f106d93875c94b47367384ebc870517431618 F www/version3.tcl 092a01f5ef430d2c4acc0ae558d74c4bb89638a0 F www/whentouse.tcl c3b50d3ac31c54be2a1af9b488a89d22f1e6e746 -P 50f1e229652610b386745bb39fed45549cc74aa7 -R bf4878fa2c84d42762e103055cb55fd1 +P 319bb4a9064deb062a888fdc31067619c9b749bb +R eca04ac646dc0adf8b62dade6edd7859 U danielk1977 -Z 3c12901d279d54cf5f64fafd62ec59a5 +Z bac0bd5515f392b48e8053527f28ff2a diff --git a/manifest.uuid b/manifest.uuid index c6e2d79a0d..e9bbbfea7e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -319bb4a9064deb062a888fdc31067619c9b749bb \ No newline at end of file +2b3e21ce2e8126ec2851751546094c3a2c831942 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index e5992d271e..5389557ad3 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.441 2005/01/12 07:15:06 danielk1977 Exp $ +** $Id: vdbe.c,v 1.442 2005/01/12 09:10:40 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -477,9 +477,9 @@ int sqlite3VdbeExec( #endif pOp = &p->aOp[pc]; - /* Only allow tracing if NDEBUG is not defined. + /* Only allow tracing if SQLITE_DEBUG is defined. */ -#ifndef NDEBUG +#ifdef SQLITE_DEBUG if( p->trace ){ if( pc==0 ){ printf("VDBE Execution Trace:\n"); @@ -487,8 +487,6 @@ int sqlite3VdbeExec( } sqlite3VdbePrintOp(p->trace, pc, pOp); } -#endif -#ifdef SQLITE_TEST if( p->trace==0 && pc==0 && sqlite3OsFileExists("vdbe_sqltrace") ){ sqlite3VdbePrintSql(p); } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 86e601f04a..e15a421079 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -362,10 +362,12 @@ int sqlite3VdbeAggReset(sqlite3*, Agg *, KeyInfo *); void sqlite3VdbeKeylistFree(Keylist*); void sqliteVdbePopStack(Vdbe*,int); int sqlite3VdbeCursorMoveto(Cursor*); -#if !defined(NDEBUG) || defined(VDBE_PROFILE) +#if defined(SQLITE_DEBUG) || defined(VDBE_PROFILE) void sqlite3VdbePrintOp(FILE*, int, Op*); #endif +#ifdef SQLITE_DEBUG void sqlite3VdbePrintSql(Vdbe*); +#endif int sqlite3VdbeSerialTypeLen(u32); u32 sqlite3VdbeSerialType(Mem*); int sqlite3VdbeSerialPut(unsigned char*, Mem*); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index fcf503ae11..f06e357ef4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -103,7 +103,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ pOp->p2 = p2; pOp->p3 = 0; pOp->p3type = P3_NOTUSED; -#ifndef NDEBUG +#ifdef SQLITE_DEBUG if( sqlite3_vdbe_addop_trace ) sqlite3VdbePrintOp(0, i, &p->aOp[i]); #endif return i; @@ -212,7 +212,7 @@ int sqlite3VdbeAddOpList(Vdbe *p, int nOp, VdbeOpList const *aOp){ pOut->p2 = p2<0 ? addr + ADDR(p2) : p2; pOut->p3 = pIn->p3; pOut->p3type = pIn->p3 ? P3_STATIC : P3_NOTUSED; -#ifndef NDEBUG +#ifdef SQLITE_DEBUG if( sqlite3_vdbe_addop_trace ){ sqlite3VdbePrintOp(0, i+addr, &p->aOp[i+addr]); } @@ -449,7 +449,7 @@ static char *displayP3(Op *pOp, char *zTemp, int nTemp){ #endif -#if !defined(NDEBUG) || defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) +#if defined(VDBE_PROFILE) || defined(SQLITE_DEBUG) /* ** Print a single opcode. This routine is used for debugging only. */ @@ -689,7 +689,7 @@ void sqlite3VdbeSorterReset(Vdbe *p){ ** Free all resources allociated with AggElem pElem, an element of ** aggregate pAgg. */ -void freeAggElem(AggElem *pElem, Agg *pAgg){ +static void freeAggElem(AggElem *pElem, Agg *pAgg){ int i; for(i=0; inMem; i++){ Mem *pMem = &pElem->aMem[i]; @@ -752,7 +752,7 @@ int sqlite3VdbeAggReset(sqlite3 *db, Agg *pAgg, KeyInfo *pKeyInfo){ while( res==0 && rc==SQLITE_OK ){ AggElem *pElem; rc = sqlite3BtreeData(pCsr, 0, sizeof(AggElem*), (char *)&pElem); - if( res!=SQLITE_OK ){ + if( rc!=SQLITE_OK ){ return rc; } assert( pAgg->apFunc!=0 ); @@ -1058,18 +1058,12 @@ static int vdbeCommit(sqlite3 *db){ */ zMainFile = sqlite3BtreeGetDirname(db->aDb[0].pBt); rc = sqlite3OsOpenDirectory(zMainFile, &master); - if( rc!=SQLITE_OK ){ + if( rc!=SQLITE_OK || (rc = sqlite3OsSync(&master))!=SQLITE_OK ){ sqlite3OsClose(&master); sqlite3OsDelete(zMaster); sqliteFree(zMaster); return rc; } - rc = sqlite3OsSync(&master); - if( rc!=SQLITE_OK ){ - sqlite3OsClose(&master); - sqliteFree(zMaster); - return rc; - } /* Sync all the db files involved in the transaction. The same call ** sets the master journal pointer in each individual journal. If @@ -1111,8 +1105,6 @@ static int vdbeCommit(sqlite3 *db){ ** master journal exists now or if it will exist after the operating ** system crash that may follow the fsync() failure. */ - assert(0); - sqliteFree(zMaster); return rc; } diff --git a/test/ioerr.test b/test/ioerr.test index 75f6806eb0..fe56811d9b 100644 --- a/test/ioerr.test +++ b/test/ioerr.test @@ -15,60 +15,98 @@ # The tests in this file use special facilities that are only # available in the SQLite test fixture. # -# $Id: ioerr.test,v 1.10 2005/01/11 13:02:34 danielk1977 Exp $ +# $Id: ioerr.test,v 1.11 2005/01/12 09:10:41 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl set ::AV [execsql {pragma auto_vacuum}] -set ::go 1 -for {set n 1} {$go} {incr n} { +# Usage: do_ioerr_test +# +# The first argument, , is an integer used to name the +# tests executed by this proc. Options are as follows: +# +# -tclprep TCL script to run to prepare test. +# -sqlprep SQL script to run to prepare test. +# -tclbody TCL script to run with IO error simulation. +# -sqlbody TCL script to run with IO error simulation. +# -exclude List of 'N' values not to test. +# +proc do_ioerr_test {tn args} { + array set ::ioerropts $args - # If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error - # on the 8th IO operation in the SQL script below doesn't report an error. - # - # This is because the 8th IO call attempts to read page 2 of the database - # file when the file on disk is only 1 page. The pager layer detects that - # this has happened and suppresses the error returned by the OS layer. - # - if {$::AV} { - if {$n==8} continue - } + set ::go 1 + for {set n 1} {$::go} {incr n} { + + if {[info exists ::ioerropts(-exclude)]} { + if {[lsearch $::ioerropts(-exclude) $n]!=-1} continue + } - do_test ioerr-1.$n.1 { - set ::sqlite_io_error_pending 0 - db close - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - sqlite3 db test.db - execsql {SELECT * FROM sqlite_master} - } {} - do_test ioerr-1.$n.2 [subst { - set ::sqlite_io_error_pending $n - }] $n - do_test ioerr-1.$n.3 { - set r [catch {db eval { - CREATE TABLE t1(a,b,c); - SELECT * FROM sqlite_master; - BEGIN TRANSACTION; - INSERT INTO t1 VALUES(1,2,3); - INSERT INTO t1 VALUES(4,5,6); - ROLLBACK; - SELECT * FROM t1; - BEGIN TRANSACTION; - INSERT INTO t1 VALUES(1,2,3); - INSERT INTO t1 VALUES(4,5,6); - COMMIT; - SELECT * FROM t1; - DELETE FROM t1 WHERE a<100; - }} msg] - # if {$r} {puts $msg} - set ::go [expr {$::sqlite_io_error_pending<=0}] - expr {$::sqlite_io_error_pending>0 || $r!=0} - } {1} + do_test ioerr-$tn.$n.1 { + set ::sqlite_io_error_pending 0 + db close + catch {file delete -force test.db} + catch {file delete -force test.db-journal} + catch {file delete -force test2.db} + catch {file delete -force test2.db-journal} + + set ::DB [sqlite3 db test.db] + + if {[info exists ::ioerropts(-tclprep)]} { + eval $::ioerropts(-tclprep) + } + if {[info exists ::ioerropts(-sqlprep)]} { + execsql $::ioerropts(-sqlprep) + } + expr 0 + } {0} + + do_test ioerr-$tn.$n.2 [subst { + set ::sqlite_io_error_pending $n + }] $n + + set ::ioerrorbody {} + if {[info exists ::ioerropts(-tclbody)]} { + append ::ioerrorbody "$::ioerropts(-tclbody)\n" + } + if {[info exists ::ioerropts(-sqlbody)]} { + append ::ioerrorbody "db eval {$::ioerropts(-sqlbody)}" + } + do_test ioerr-$tn.$n.3 { + set r [catch $::ioerrorbody msg] + set ::go [expr {$::sqlite_io_error_pending<=0}] + expr {$::sqlite_io_error_pending>0 || $r!=0} + } {1} + } + set ::sqlite_io_error_pending 0 } -set ::sqlite_io_error_pending 0 + +# If SQLITE_DEFAULT_AUTOVACUUM is set to true, then a simulated IO error +# on the 8th IO operation in the SQL script below doesn't report an error. +# +# This is because the 8th IO call attempts to read page 2 of the database +# file when the file on disk is only 1 page. The pager layer detects that +# this has happened and suppresses the error returned by the OS layer. +# +do_ioerr_test 1 -sqlprep { + SELECT * FROM sqlite_master; +} -sqlbody { + CREATE TABLE t1(a,b,c); + SELECT * FROM sqlite_master; + BEGIN TRANSACTION; + INSERT INTO t1 VALUES(1,2,3); + INSERT INTO t1 VALUES(4,5,6); + ROLLBACK; + SELECT * FROM t1; + BEGIN TRANSACTION; + INSERT INTO t1 VALUES(1,2,3); + INSERT INTO t1 VALUES(4,5,6); + COMMIT; + SELECT * FROM t1; + DELETE FROM t1 WHERE a<100; +} -exclude [expr [execsql {pragma auto_vacuum}] ? 8 : 0] + proc cksum {{db db}} { set txt [$db eval { @@ -95,6 +133,8 @@ for {set n 1} {$go} {incr n} { db close catch {file delete -force test.db} catch {file delete -force test.db-journal} + catch {file delete -force test2.db} + catch {file delete -force test2.db-journal} sqlite3 db test.db execsql { BEGIN; @@ -135,72 +175,51 @@ for {set n 1} {$go} {incr n} { } set ::sqlite_io_error_pending 0 -set ::go 1 -for {set n 1} {$go} {incr n} { - do_test ioerr-3.$n.1 { - set ::sqlite_io_error_pending 0 - db close - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - sqlite3 db test.db - execsql { - PRAGMA cache_size = 10; - BEGIN; - CREATE TABLE abc(a); - INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow - } - for {set i 0} {$i<150} {incr i} { - execsql { - INSERT INTO abc VALUES(randstr(100,100)); - } - } - execsql COMMIT - } {} - do_test ioerr-3.$n.2 [subst { - set ::sqlite_io_error_pending $n - }] $n - do_test ioerr-3.$n.3 { - set r [catch {db eval { - CREATE TABLE abc2(a); - BEGIN; - DELETE FROM abc WHERE length(a)>100; - UPDATE abc SET a = randstr(90,90); - COMMIT; - CREATE TABLE abc3(a); - }} msg] - set ::go [expr {$::sqlite_io_error_pending<=0}] - expr {$::sqlite_io_error_pending>0 || $r!=0} - } {1} -} -set ::sqlite_io_error_pending 0 -set ::go 1 -for {set n 1} {$go} {incr n} { - do_test ioerr-4.$n.1 { - set ::sqlite_io_error_pending 0 - db close - catch {file delete -force test.db} - catch {file delete -force test.db-journal} - sqlite3 db test.db - set sql "CREATE TABLE abc(a1" - for {set i 2} {$i<1300} {incr i} { - append sql ", a$i" +do_ioerr_test 3 -tclprep { + execsql { + PRAGMA cache_size = 10; + BEGIN; + CREATE TABLE abc(a); + INSERT INTO abc VALUES(randstr(1500,1500)); -- Page 4 is overflow + } + for {set i 0} {$i<150} {incr i} { + execsql { + INSERT INTO abc VALUES(randstr(100,100)); } - append sql ");" - execsql $sql - execsql {INSERT INTO abc (a1) VALUES(NULL)} - } {} - do_test ioerr-4.$n.2 [subst { - set ::sqlite_io_error_pending $n - }] $n - do_test ioerr-4.$n.3 { - set r [catch {db eval { - SELECT * FROM abc; - }} msg] - set ::go [expr {$::sqlite_io_error_pending<=0}] - expr {$::sqlite_io_error_pending>0 || $r!=0} - } {1} + } + execsql COMMIT +} -sqlbody { + CREATE TABLE abc2(a); + BEGIN; + DELETE FROM abc WHERE length(a)>100; + UPDATE abc SET a = randstr(90,90); + COMMIT; + CREATE TABLE abc3(a); +} + +# Test IO errors that can occur retrieving a record header that flows over +# onto an overflow page. +do_ioerr_test 4 -tclprep { + set sql "CREATE TABLE abc(a1" + for {set i 2} {$i<1300} {incr i} { + append sql ", a$i" + } + append sql ");" + execsql $sql + execsql {INSERT INTO abc (a1) VALUES(NULL)} +} -sqlbody { + SELECT * FROM abc; +} + +# Test IO errors that may occur during a multi-file commit. +do_ioerr_test 5 -sqlprep { + ATTACH 'test2.db' AS test2; +} -sqlbody { + BEGIN; + CREATE TABLE t1(a,b,c); + CREATE TABLE test2.t2(a,b,c); + COMMIT; } -set ::sqlite_io_error_pending 0 finish_test diff --git a/test/malloc.test b/test/malloc.test index 3d8876024d..9b117b68e9 100644 --- a/test/malloc.test +++ b/test/malloc.test @@ -14,7 +14,7 @@ # special feature is used to see what happens in the library if a malloc # were to really fail due to an out-of-memory situation. # -# $Id: malloc.test,v 1.14 2005/01/12 07:15:07 danielk1977 Exp $ +# $Id: malloc.test,v 1.15 2005/01/12 09:10:41 danielk1977 Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -342,8 +342,12 @@ for {set go 1; set i 1} {$go} {incr i} { # when converting UTF-16 text to integers and real numbers is handled # correctly. # -# This doesn't actually return an error to the user. That could be -# viewed as a bug. +# This is done by retrieving a string from the database engine and +# manipulating it using the sqlite3_column_*** APIs. This doesn't +# actually return an error to the user when a malloc() fails.. That +# could be viewed as a bug. +# +# These tests only run if UTF-16 support is compiled in. # for {set go 1; set i 1} {$go && $::sqlite_options(utf16)} {incr i} { do_test malloc-8.$i { @@ -382,6 +386,46 @@ for {set go 1; set i 1} {$go && $::sqlite_options(utf16)} {incr i} { } {0} } +# This block tests that malloc() failures that occur whilst commiting +# a multi-file transaction are handled correctly. +# +for {set go 1; set i 1} {$go} {incr i} { + do_test malloc-9.$i { + sqlite_malloc_fail 0 + catch {db close} + catch {file delete -force test.db} + catch {file delete -force test.db-journal} + catch {file delete -force test2.db} + catch {file delete -force test2.db-journal} + + sqlite3 db test.db + execsql { + ATTACH 'test2.db' as test2; + CREATE TABLE abc1(a, b, c); + CREATE TABLE test2.abc2(a, b, c); + } + + sqlite_malloc_fail $i + set v [catch {execsql { + BEGIN; + INSERT INTO abc1 VALUES(1, 2, 3); + INSERT INTO abc2 VALUES(1, 2, 3); + COMMIT; + }} msg] + set leftover [lindex [sqlite_malloc_stat] 2] + if {$leftover>0} { + if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"} + set ::go 0 + set v {1 1} + } else { + set v2 [expr {$msg=="" || $msg=="out of memory"}] + if {!$v2} {puts "\nError message returned: $msg"} + lappend v $v2 + } + } {1 1} +} + + # Ensure that no file descriptors were leaked. do_test malloc-99.X { catch {db close}