-C Fix\sa\sformatting\serrror\sin\sI/O\slogging.\s(CVS\s3914)
-D 2007-05-04T12:01:03
+C Test\scases\sand\scorrections\sto\sIO\sand\smalloc()\serror\shandling\sin\sincremental\sblob\sIO\sfunctions.\s(CVS\s3915)
+D 2007-05-04T12:05:56
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
F src/analyze.c 4bbf5ddf9680587c6d4917e02e378b6037be3651
F src/attach.c a16ada4a4654a0d126b8223ec9494ebb81bc5c3c
F src/auth.c 902f4722661c796b97f007d9606bd7529c02597f
-F src/btree.c b88c9265e323b9a55290c39f9712e44050a6162c
+F src/btree.c a47fe8172eb62468f78a2fe4904d2e6b050038fb
F src/btree.h 2c187d60cf76d74c2b4767294d6b5fa267037ff0
F src/build.c 02e01ec7907c7d947ab3041fda0e81eaed05db42
F src/callback.c 6414ed32d55859d0f65067aa5b88d2da27b3af9e
F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
F src/sqliteInt.h 5a8c0221a4f11998f46aa76364a9559af8d7c1f7
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
-F src/tclsqlite.c dde509871614d17f8ab5f3b4bc496b0af07280c7
+F src/tclsqlite.c 0906902b96e4b292ba98499dd380e22d3322f817
F src/test1.c 29a39fdde51f4612082ecf3f5af54dac93766f87
F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
F src/test3.c 946ea9d1a8c928656e3c70f0a2fcb8e733a15e86
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97
F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af
-F src/vdbeaux.c 51acaab4275b5fddc7af5e7d1d2594044216ac46
-F src/vdbeblob.c ed2f9b46cc2de8de97d2a4a4ec466c5914d68333
+F src/vdbeaux.c 966d166f9d4079552c7cb48855afe8c1aa331556
+F src/vdbeblob.c 58b3f68f6bc18b58aeab3a31cff083cb4127292f
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb
F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf
F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a
F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d
F test/incrblob.test 5cf5a7693c6cde33eef361d94c00c7bdbc30f563
+F test/incrblob_err.test 9f78c159279c992fa5ce49c06f50b680fc470520
F test/incrvacuum.test 2173bc075c7b3b96ccf228d737dd4f5c29500dc4
F test/incrvacuum_ioerr.test 0ebc382bcc2036ec58cf49cc5ffada45f75d907b
F test/index.test e65df12bed94b2903ee89987115e1578687e9266
F test/tableapi.test 036575a98dcce7c92e9f39056839bbad8a715412
F test/tclsqlite.test 726c301d35a2c1f4181fb772a607f785dd9e284e
F test/temptable.test c36f3e5a94507abb64f7ba23deeb4e1a8a8c3821
-F test/tester.tcl dcebe3c5bf15f3b4ba015b4b2237030c1e384941
+F test/tester.tcl 9382df472e0e86cbfddc44ab8c8cc02497bc9c8a
F test/thread1.test 776c9e459b75ba905193b351926ac4019b049f35
F test/thread2.test 6d7b30102d600f51b4055ee3a5a19228799049fb
F test/threadtest1.c 6029d9c5567db28e6dc908a0c63099c3ba6c383b
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P 2a178d0c7950c9d403c0bc43c2043de945fb24e0
-R 2c92eb8d26a624968d9428e7829962d0
-U drh
-Z f76b8b0273f8e85ef3b644774d94b3bf
+P 2d37687a08a7b6b3a7f77f55a7c2e29a1f8731a8
+R 631ed7d60317b63e0f0649096fcada2a
+U danielk1977
+Z dfc7741fad7b57c2866d720631f3b47d
-2d37687a08a7b6b3a7f77f55a7c2e29a1f8731a8
\ No newline at end of file
+641e55284e1ba6070073c83ac6ed78ffb29f7e60
\ No newline at end of file
** May you share freely, never taking more than you give.
**
*************************************************************************
-** $Id: btree.c,v 1.371 2007/05/04 08:32:14 danielk1977 Exp $
+** $Id: btree.c,v 1.372 2007/05/04 12:05:56 danielk1977 Exp $
**
** This file implements a external (disk-based) database using BTrees.
** For a detailed discussion of BTrees, refer to
static void releasePage(MemPage *pPage); /* Forward reference */
+#ifndef SQLITE_OMIT_INCRBLOB
+/*
+** Invalidate the overflow page-list cache for cursor pCur, if any.
+*/
+static void invalidateOverflowCache(BtCursor *pCur){
+ sqliteFree(pCur->aOverflow);
+ pCur->aOverflow = 0;
+}
+
+/*
+** Invalidate the overflow page-list cache for all cursors opened
+** on the shared btree structure pBt.
+*/
+static void invalidateAllOverflowCache(BtShared *pBt){
+ BtCursor *p;
+ for(p=pBt->pCursor; p; p=p->pNext){
+ invalidateOverflowCache(p);
+ }
+}
+#else
+ #define invalidateOverflowCache(x)
+ #define invalidateAllOverflowCache(x)
+#endif
+
/*
** Save the current cursor position in the variables BtCursor.nKey
** and BtCursor.pKey. The cursor's state is set to CURSOR_REQUIRESEEK.
pCur->eState = CURSOR_REQUIRESEEK;
}
-#ifndef SQLITE_OMIT_INCRBLOB
- /* Delete the cache of overflow page numbers. */
- sqliteFree(pCur->aOverflow);
- pCur->aOverflow = 0;
-#endif
-
+ invalidateOverflowCache(pCur);
return rc;
}
*/
int sqlite3BtreeIncrVacuum(Btree *p){
BtShared *pBt = p->pBt;
- BtCursor *pCur;
-
assert( pBt->inTransaction==TRANS_WRITE && p->inTrans==TRANS_WRITE );
if( !pBt->autoVacuum ){
return SQLITE_DONE;
}
-#ifndef SQLITE_OMIT_INCRBLOB
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- /* Delete the cache of overflow page numbers. */
- sqliteFree(pCur->aOverflow);
- pCur->aOverflow = 0;
- }
-#endif
+ invalidateAllOverflowCache(pBt);
return incrVacuumStep(pBt, 0);
}
int nRef = sqlite3PagerRefcount(pPager);
#endif
-#ifndef SQLITE_OMIT_INCRBLOB
- BtCursor *pCur;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- /* Delete the cache of overflow page numbers. */
- sqliteFree(pCur->aOverflow);
- pCur->aOverflow = 0;
- }
-#endif
-
+ invalidateAllOverflowCache(pBt);
assert(pBt->autoVacuum);
if( !pBt->incrVacuum ){
Pgno nFin = 0;
}
releasePage(pCur->pPage);
unlockBtreeIfUnused(pBt);
-#ifndef SQLITE_OMIT_INCRBLOB
- sqliteFree(pCur->aOverflow);
-#endif
+ invalidateOverflowCache(pCur);
sqliteFree(pCur);
return SQLITE_OK;
}
Pgno pgnoMove; /* Move a page here to make room for the root-page */
MemPage *pPageMove; /* The page to move to. */
-#ifndef SQLITE_OMIT_INCRBLOB
/* Creating a new table may probably require moving an existing database
** to make room for the new tables root page. In case this page turns
** out to be an overflow page, delete all overflow page-map caches
** held by open cursors.
*/
- BtCursor *pCur;
- for(pCur=pBt->pCursor; pCur; pCur=pCur->pNext){
- sqliteFree(pCur->aOverflow);
- pCur->aOverflow = 0;
- }
-#endif
+ invalidateAllOverflowCache(pBt);
/* Read the value of meta[3] from the database to determine where the
** root page of the new table should go. meta[3] is the largest root-page
** A TCL Interface to SQLite. Append this file to sqlite3.c and
** compile the whole thing to build a TCL-enabled version of SQLite.
**
-** $Id: tclsqlite.c,v 1.182 2007/05/03 16:31:26 danielk1977 Exp $
+** $Id: tclsqlite.c,v 1.183 2007/05/04 12:05:56 danielk1977 Exp $
*/
#include "tcl.h"
#include <errno.h>
*/
static int incrblobClose(ClientData instanceData, Tcl_Interp *interp){
IncrblobChannel *p = (IncrblobChannel *)instanceData;
- sqlite3_blob_close(p->pBlob);
+ int rc = sqlite3_blob_close(p->pBlob);
+ sqlite3 *db = p->pDb->db;
/* Remove the channel from the SqliteDb.pIncrblob list. */
if( p->pNext ){
p->pDb->pIncrblob = p->pNext;
}
+ /* Free the IncrblobChannel structure */
Tcl_Free((char *)p);
+
+ if( rc!=SQLITE_OK ){
+ Tcl_SetResult(interp, (char *)sqlite3_errmsg(db), TCL_VOLATILE);
+ return TCL_ERROR;
+ }
return TCL_OK;
}
** Change N opcodes starting at addr to No-ops.
*/
void sqlite3VdbeChangeToNoop(Vdbe *p, int addr, int N){
- VdbeOp *pOp = &p->aOp[addr];
- while( N-- ){
- freeP3(pOp->p3type, pOp->p3);
- memset(pOp, 0, sizeof(pOp[0]));
- pOp->opcode = OP_Noop;
- pOp++;
+ if( p && p->aOp ){
+ VdbeOp *pOp = &p->aOp[addr];
+ while( N-- ){
+ freeP3(pOp->p3type, pOp->p3);
+ memset(pOp, 0, sizeof(pOp[0]));
+ pOp->opcode = OP_Noop;
+ pOp++;
+ }
}
}
**
*************************************************************************
**
-** $Id: vdbeblob.c,v 1.5 2007/05/03 18:14:10 danielk1977 Exp $
+** $Id: vdbeblob.c,v 1.6 2007/05/04 12:05:56 danielk1977 Exp $
*/
#include "sqliteInt.h"
** and offset cache without causing any IO.
*/
sqlite3VdbeChangeP2(v, 5, pTab->nCol+1);
- sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
+ if( !sqlite3MallocFailed() ){
+ sqlite3VdbeMakeReady(v, 1, 0, 1, 0);
+ }
}
rc = sqlite3SafetyOff(db);
- if( rc!=SQLITE_OK ){
- return rc;
+ if( rc!=SQLITE_OK || sqlite3MallocFailed() ){
+ goto blob_open_out;
}
sqlite3_bind_int64((sqlite3_stmt *)v, 1, iRow);
}
blob_open_out:
+ zErr[sizeof(zErr)-1] = '\0';
if( rc!=SQLITE_OK || sqlite3MallocFailed() ){
sqlite3_finalize((sqlite3_stmt *)v);
}
- zErr[sizeof(zErr)-1] = '\0';
- sqlite3Error(db, rc, zErr);
+ sqlite3Error(db, rc, (rc==SQLITE_OK?0:zErr));
return sqlite3ApiExit(db, rc);
}
*/
int sqlite3_blob_close(sqlite3_blob *pBlob){
Incrblob *p = (Incrblob *)pBlob;
- sqlite3_finalize(p->pStmt);
+ sqlite3_stmt *pStmt = p->pStmt;
sqliteFree(p);
- return SQLITE_OK;
+ return sqlite3_finalize(pStmt);
}
/*
** Read data from a blob handle.
*/
int sqlite3_blob_read(sqlite3_blob *pBlob, void *z, int n, int iOffset){
+ int rc = SQLITE_ERROR;
Incrblob *p = (Incrblob *)pBlob;
- if( (iOffset+n)>p->nByte ){
- return SQLITE_ERROR;
+ Vdbe *v = (Vdbe *)(p->pStmt);
+ if( (iOffset+n)<=p->nByte ){
+ rc = sqlite3BtreeData(p->pCsr, iOffset+p->iOffset, n, z);
}
- return sqlite3BtreeData(p->pCsr, iOffset+p->iOffset, n, z);
+ v->rc = rc;
+ return sqlite3ApiExit(v->db, v->rc);
}
/*
** Write data to a blob handle.
*/
int sqlite3_blob_write(sqlite3_blob *pBlob, const void *z, int n, int iOffset){
+ int rc = SQLITE_ERROR;
Incrblob *p = (Incrblob *)pBlob;
- if( (iOffset+n)>p->nByte ){
- return SQLITE_ERROR;
+ Vdbe *v = (Vdbe *)(p->pStmt);
+ if( (iOffset+n)<=p->nByte ){
+ rc = sqlite3BtreePutData(p->pCsr, iOffset+p->iOffset, n, z);
}
- return sqlite3BtreePutData(p->pCsr, iOffset+p->iOffset, n, z);
+ v->rc = rc;
+ return sqlite3ApiExit(v->db, v->rc);
}
/*
--- /dev/null
+# 2007 May 1
+#
+# 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.
+#
+#***********************************************************************
+#
+# $Id: incrblob_err.test,v 1.1 2007/05/04 12:05:56 danielk1977 Exp $
+#
+
+set testdir [file dirname $argv0]
+source $testdir/tester.tcl
+
+# Usage: do_malloc_test <test number> <options...>
+#
+# The first argument, <test number>, 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 malloc failure simulation.
+# -sqlbody TCL script to run with malloc failure simulation.
+# -cleanup TCL script to run after the test.
+#
+# This command runs a series of tests to verify SQLite's ability
+# to handle an out-of-memory condition gracefully. It is assumed
+# that if this condition occurs a malloc() call will return a
+# NULL pointer. Linux, for example, doesn't do that by default. See
+# the "BUGS" section of malloc(3).
+#
+# Each iteration of a loop, the TCL commands in any argument passed
+# to the -tclbody switch, followed by the SQL commands in any argument
+# passed to the -sqlbody switch are executed. Each iteration the
+# Nth call to sqliteMalloc() is made to fail, where N is increased
+# each time the loop runs starting from 1. When all commands execute
+# successfully, the loop ends.
+#
+proc do_malloc_test {tn args} {
+ array unset ::mallocopts
+ array set ::mallocopts $args
+
+ set ::go 1
+ for {set ::n 1} {$::go && $::n < 50000} {incr ::n} {
+ do_test incrblob_err-$tn.$::n {
+
+ # Remove all traces of database files test.db and test2.db from the files
+ # system. Then open (empty database) "test.db" with the handle [db].
+ #
+ 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}
+ catch {sqlite3 db test.db}
+ set ::DB [sqlite3_connection_pointer db]
+
+ # Execute any -tclprep and -sqlprep scripts.
+ #
+ if {[info exists ::mallocopts(-tclprep)]} {
+ eval $::mallocopts(-tclprep)
+ }
+ if {[info exists ::mallocopts(-sqlprep)]} {
+ execsql $::mallocopts(-sqlprep)
+ }
+
+ # Now set the ${::n}th malloc() to fail and execute the -tclbody and
+ # -sqlbody scripts.
+ #
+ sqlite_malloc_fail $::n
+ set ::mallocbody {}
+ if {[info exists ::mallocopts(-tclbody)]} {
+ append ::mallocbody "$::mallocopts(-tclbody)\n"
+ }
+ if {[info exists ::mallocopts(-sqlbody)]} {
+ append ::mallocbody "db eval {$::mallocopts(-sqlbody)}"
+ }
+ set v [catch $::mallocbody msg]
+
+ # If the test fails (if $v!=0) and the database connection actually
+ # exists, make sure the failure code is SQLITE_NOMEM.
+ if {$v && [info command db]=="db" && [info exists ::mallocopts(-sqlbody)]
+ && [db errorcode]!=7} {
+ set v 999
+ }
+
+ set leftover [lindex [sqlite_malloc_stat] 2]
+ if {$leftover>0} {
+ if {$leftover>1} {puts "\nLeftover: $leftover\nReturn=$v Message=$msg"}
+ set ::go 0
+ if {$v} {
+ puts "\nError message returned: $msg"
+ } else {
+ 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}
+
+ if {[info exists ::mallocopts(-cleanup)]} {
+ catch [list uplevel #0 $::mallocopts(-cleanup)] msg
+ }
+ }
+ unset ::mallocopts
+}
+
+set ::fd [open [info script]]
+set ::data [read $::fd]
+close $::fd
+
+do_malloc_test 1 -tclprep {
+ set bytes [file size [info script]]
+ execsql {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, zeroblob($::bytes));
+ }
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ set rc [catch {puts -nonewline $::blob $::data}]
+ if {$rc} { error "out of memory" }
+}
+
+do_malloc_test 2 -tclprep {
+ execsql {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, $::data);
+ }
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ set rc [catch {set ::r [read $::blob]}]
+ if {$rc} {
+ error "out of memory"
+ } elseif {$::r ne $::data} {
+ error "Bad data read..."
+ }
+}
+
+do_malloc_test 3 -tclprep {
+ execsql {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, $::data);
+ }
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ set rc [catch {set ::r [read $::blob]}]
+ if {$rc} {
+ error "out of memory"
+ } elseif {$::r ne $::data} {
+ error "Bad data read..."
+ }
+ set rc [catch {close $::blob}]
+ if {$rc} {
+ error "out of memory"
+ }
+}
+sqlite_malloc_fail 0
+
+do_ioerr_test incrblob_err-4 -cksum 1 -sqlprep {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, $::data);
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ read $::blob
+}
+
+do_ioerr_test incrblob_err-5 -cksum 1 -sqlprep {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, zeroblob(length(CAST($::data AS BLOB))));
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ puts -nonewline $::blob $::data
+ close $::blob
+}
+
+do_ioerr_test incrblob_err-6 -cksum 1 -sqlprep {
+ CREATE TABLE blobs(k, v BLOB);
+ INSERT INTO blobs VALUES(1, $::data || $::data || $::data);
+} -tclbody {
+ set ::blob [db incrblob blobs v 1]
+ seek $::blob -20 end
+ puts -nonewline $::blob "12345678900987654321"
+ close $::blob
+}
+
+finish_test
# This file implements some common TCL routines used for regression
# testing the SQLite library
#
-# $Id: tester.tcl,v 1.80 2007/04/28 15:47:45 danielk1977 Exp $
+# $Id: tester.tcl,v 1.81 2007/05/04 12:05:56 danielk1977 Exp $
# Make sure tclsqlite3 was compiled correctly. Abort now with an
# error message if not.
set ::go 1
for {set n $::ioerropts(-start)} {$::go} {incr n} {
-set ::TN $n
+ set ::TN $n
incr ::ioerropts(-count) -1
if {$::ioerropts(-count)<0} break
# 1. We never hit the IO error and the SQL returned OK
# 2. An IO error was hit and the SQL failed
#
+#puts "$s $r $::go - $msg"
expr { ($s && !$r && !$::go) || (!$s && $r && $::go) }
} {1}