Index: src/test1.c ================================================================== --- src/test1.c +++ src/test1.c @@ -11,11 +11,11 @@ ************************************************************************* ** Code for testing all sorts of SQLite interfaces. This code ** is not included in the SQLite library. It is used for automated ** testing of the SQLite library. ** -** $Id: test1.c,v 1.325 2008/09/11 10:29:16 danielk1977 Exp $ +** $Id: test1.c,v 1.326 2008/10/02 14:49:02 danielk1977 Exp $ */ #include "sqliteInt.h" #include "tcl.h" #include #include @@ -1557,11 +1557,11 @@ return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } /* -** sqlite3_blob_write CHANNEL OFFSET DATA +** sqlite3_blob_write CHANNEL OFFSET DATA ?NDATA? ** ** This command is used to test the sqlite3_blob_write() in ways that ** the Tcl channel interface does not. The first argument should ** be the name of a valid channel created by the [incrblob] method ** of a database handle. This function calls sqlite3_blob_write() @@ -1586,27 +1586,27 @@ int rc; unsigned char *zBuf; int nBuf; - if( objc!=4 ){ - Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA"); + if( objc!=4 && objc!=5 ){ + Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET DATA ?NDATA?"); return TCL_ERROR; } channel = Tcl_GetChannel(interp, Tcl_GetString(objv[1]), ¬Used); - if( !channel - || TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) - || iOffset<0 - ){ + if( !channel || TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ return TCL_ERROR; } instanceData = Tcl_GetChannelInstanceData(channel); pBlob = *((sqlite3_blob **)instanceData); zBuf = Tcl_GetByteArrayFromObj(objv[3], &nBuf); + if( objc==5 && Tcl_GetIntFromObj(interp, objv[4], &nBuf) ){ + return TCL_ERROR; + } rc = sqlite3_blob_write(pBlob, zBuf, nBuf, iOffset); if( rc!=SQLITE_OK ){ Tcl_SetResult(interp, (char *)sqlite3TestErrorName(rc), TCL_VOLATILE); } Index: src/vdbeblob.c ================================================================== --- src/vdbeblob.c +++ src/vdbeblob.c @@ -10,11 +10,11 @@ ** ************************************************************************* ** ** This file contains code used to implement incremental BLOB I/O. ** -** $Id: vdbeblob.c,v 1.25 2008/07/28 19:34:54 drh Exp $ +** $Id: vdbeblob.c,v 1.26 2008/10/02 14:49:02 danielk1977 Exp $ */ #include "sqliteInt.h" #include "vdbeInt.h" @@ -285,21 +285,21 @@ int rc; Incrblob *p = (Incrblob *)pBlob; Vdbe *v; sqlite3 *db = p->db; - /* Request is out of range. Return a transient error. */ - if( (iOffset+n)>p->nByte ){ - return SQLITE_ERROR; - } - sqlite3_mutex_enter(db->mutex); - - /* If there is no statement handle, then the blob-handle has - ** already been invalidated. Return SQLITE_ABORT in this case. - */ - v = (Vdbe*)p->pStmt; - if( v==0 ){ + sqlite3_mutex_enter(db->mutex); + v = (Vdbe*)p->pStmt; + + if( n<0 || iOffset<0 || (iOffset+n)>p->nByte ){ + /* Request is out of range. Return a transient error. */ + rc = SQLITE_ERROR; + sqlite3Error(db, SQLITE_ERROR, 0); + } else if( v==0 ){ + /* If there is no statement handle, then the blob-handle has + ** already been invalidated. Return SQLITE_ABORT in this case. + */ rc = SQLITE_ABORT; }else{ /* Call either BtreeData() or BtreePutData(). If SQLITE_ABORT is ** returned, clean-up the statement handle. */ Index: test/incrblob.test ================================================================== --- test/incrblob.test +++ test/incrblob.test @@ -7,11 +7,11 @@ # May you find forgiveness for yourself and forgive others. # May you share freely, never taking more than you give. # #*********************************************************************** # -# $Id: incrblob.test,v 1.21 2008/09/11 11:28:00 danielk1977 Exp $ +# $Id: incrblob.test,v 1.22 2008/10/02 14:49:02 danielk1977 Exp $ # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -615,7 +615,39 @@ sqlite3_errcode db } {SQLITE_READONLY} do_test incrblob-7.6 { sqlite3_errmsg db } {attempt to write a readonly database} + +# Test that if either the "offset" or "amount" arguments to +# sqlite3_blob_write() are less than zero, SQLITE_ERROR is returned. +# +do_test incrblob-8.1 { + execsql { INSERT INTO t1 VALUES(314159, 'sqlite') } + set ::b [db incrblob t1 b 314159] + fconfigure $::b -translation binary + set rc [catch {sqlite3_blob_write $::b 10 HELLO -1} msg] + lappend rc $msg +} {1 SQLITE_ERROR} +do_test incrblob-8.2 { + sqlite3_errcode db +} {SQLITE_ERROR} +do_test incrblob-8.3 { + set rc [catch {sqlite3_blob_write $::b -1 HELLO 5} msg] + lappend rc $msg +} {1 SQLITE_ERROR} +do_test incrblob-8.4 { + sqlite3_errcode db +} {SQLITE_ERROR} +do_test incrblob-8.5 { + execsql {SELECT b FROM t1 WHERE a = 314159} +} {sqlite} +do_test incrblob-8.6 { + set rc [catch {sqlite3_blob_write $::b 0 etilqs 6} msg] + lappend rc $msg +} {0 {}} +do_test incrblob-8.7 { + execsql {SELECT b FROM t1 WHERE a = 314159} +} {etilqs} + finish_test