diff --git a/manifest b/manifest index dcb854d0b8..ff539b71f8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sI/O\stracing\soutput.\s\sRequire\s-DSQLITE_ENABLE_IOTRACE\swhen\ncompiling\sshell.c\sin\sorder\sto\slink\sin\sthe\sI/O\stracing\scapability.\s(CVS\s3909) -D 2007-05-03T17:18:37 +C Test\ssome\smore\sincremental\sIO\serror\scases.\s(CVS\s3910) +D 2007-05-03T18:14:10 F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028 @@ -130,7 +130,7 @@ F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691 F src/vdbeInt.h cb02cbbceddf3b40d49012e9f41576f17bcbec97 F src/vdbeapi.c 37d793559390bec8a00c556f651f21b5f9e589af F src/vdbeaux.c 8c7f22e22d1ea578971f5a3fcd3a56a6882ced64 -F src/vdbeblob.c 74fe0c7fc149a80715be7e3a33ed0e545d5e33e1 +F src/vdbeblob.c ed2f9b46cc2de8de97d2a4a4ec466c5914d68333 F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f F src/vdbemem.c ba98f8572ec4609846b368fa7580db178022f1bb F src/vtab.c 89a0d5f39c1beba65a77fdb4d507b831fc5e6baf @@ -242,7 +242,7 @@ F test/fts2n.test a70357e72742681eaebfdbe9007b87ff3b771638 F test/func.test 6727c7729472ae52b5acd86e802f89aa350ba50f F test/hook.test 7e7645fd9a033f79cce8fdff151e32715e7ec50a F test/in.test 369cb2aa1eab02296b4ec470732fe8c131260b1d -F test/incrblob.test 9f6f5c23716d6c9386d1011cff732399900750df +F test/incrblob.test 5cf5a7693c6cde33eef361d94c00c7bdbc30f563 F test/incrvacuum.test 2173bc075c7b3b96ccf228d737dd4f5c29500dc4 F test/incrvacuum_ioerr.test 0ebc382bcc2036ec58cf49cc5ffada45f75d907b F test/index.test e65df12bed94b2903ee89987115e1578687e9266 @@ -473,7 +473,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5 -P 92b53601657be3f1be70873b2960cd97b97f72a1 -R 2fb024d0ffb855b54c72bde6978aacd6 -U drh -Z f0fb6fb797fd898d24e13ec3e7829264 +P 8a43e1676fdd29903e0b3f9d3b05d217d42962b8 +R f2daf03cbf23d5e395cd82f06da9d675 +U danielk1977 +Z 8d660e54025b30b52414bf1578df31ed diff --git a/manifest.uuid b/manifest.uuid index 32922fd565..090107392a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8a43e1676fdd29903e0b3f9d3b05d217d42962b8 \ No newline at end of file +64705410bdf43b6283f7a7e59ce8c20d09cd46e4 \ No newline at end of file diff --git a/src/vdbeblob.c b/src/vdbeblob.c index b095a5e814..c81ac21410 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -10,7 +10,7 @@ ** ************************************************************************* ** -** $Id: vdbeblob.c,v 1.4 2007/05/03 16:31:26 danielk1977 Exp $ +** $Id: vdbeblob.c,v 1.5 2007/05/03 18:14:10 danielk1977 Exp $ */ #include "sqliteInt.h" @@ -101,7 +101,6 @@ int sqlite3_blob_open( if( !pTab ){ if( sParse.zErrMsg ){ sqlite3_snprintf(sizeof(zErr), zErr, "%s", sParse.zErrMsg); - zErr[sizeof(zErr)-1] = '\0'; } sqliteFree(sParse.zErrMsg); rc = SQLITE_ERROR; @@ -116,12 +115,31 @@ int sqlite3_blob_open( } } if( iCol==pTab->nCol ){ - sprintf(zErr, "no such column: \"%s\"", zColumn); + sqlite3_snprintf(sizeof(zErr), zErr, "no such column: \"%s\"", zColumn); rc = SQLITE_ERROR; sqlite3SafetyOff(db); goto blob_open_out; } + /* If the value is being opened for writing, check that the + ** column is not indexed. It is against the rules to open an + ** indexed column for writing. + */ + if( flags ){ + Index *pIdx; + for(pIdx=pTab->pIndex; pIdx; pIdx=pIdx->pNext){ + int j; + for(j=0; jnColumn; j++){ + if( pIdx->aiColumn[j]==iCol ){ + strcpy(zErr, "cannot open indexed column for writing"); + rc = SQLITE_ERROR; + sqlite3SafetyOff(db); + goto blob_open_out; + } + } + } + } + v = sqlite3VdbeCreate(db); if( v ){ int iDb = sqlite3SchemaToIndex(db, pTab->pSchema); @@ -138,8 +156,8 @@ int sqlite3_blob_open( /* Configure the db number pushed onto the stack */ sqlite3VdbeChangeP1(v, 2, iDb); - /* Remove either the OP_OpenWrite or OpenRead. Set the P2 parameter - ** of the other to pTab->tnum. + /* Remove either the OP_OpenWrite or OpenRead. Set the P2 + ** parameter of the other to pTab->tnum. */ sqlite3VdbeChangeToNoop(v, (flags ? 3 : 4), 1); sqlite3VdbeChangeP2(v, (flags ? 4 : 3), pTab->tnum); @@ -165,7 +183,7 @@ int sqlite3_blob_open( if( rc!=SQLITE_ROW ){ nAttempt++; rc = sqlite3_finalize((sqlite3_stmt *)v); - sprintf(zErr, "no such rowid: %lld", iRow); + sqlite3_snprintf(sizeof(zErr), zErr, sqlite3_errmsg(db)); v = 0; } } while( nAttempt<5 && rc==SQLITE_SCHEMA ); @@ -179,6 +197,9 @@ int sqlite3_blob_open( u32 type = v->apCsr[0]->aType[iCol]; if( type<12 ){ + sqlite3_snprintf(sizeof(zErr), zErr, "cannot open value of type %s", + type==0?"null": type==7?"real": "integer" + ); rc = SQLITE_ERROR; goto blob_open_out; } @@ -196,6 +217,7 @@ int sqlite3_blob_open( *ppBlob = (sqlite3_blob *)pBlob; rc = SQLITE_OK; }else if( rc==SQLITE_OK ){ + sqlite3_snprintf(sizeof(zErr), zErr, "no such rowid: %lld", iRow); rc = SQLITE_ERROR; } @@ -203,6 +225,7 @@ blob_open_out: if( rc!=SQLITE_OK || sqlite3MallocFailed() ){ sqlite3_finalize((sqlite3_stmt *)v); } + zErr[sizeof(zErr)-1] = '\0'; sqlite3Error(db, rc, zErr); return sqlite3ApiExit(db, rc); } diff --git a/test/incrblob.test b/test/incrblob.test index 96038c6c6e..ff88ba706d 100644 --- a/test/incrblob.test +++ b/test/incrblob.test @@ -9,7 +9,7 @@ # #*********************************************************************** # -# $Id: incrblob.test,v 1.5 2007/05/03 16:31:26 danielk1977 Exp $ +# $Id: incrblob.test,v 1.6 2007/05/03 18:14:10 danielk1977 Exp $ # set testdir [file dirname $argv0] @@ -208,6 +208,7 @@ do_test incrblob-3.2 { set rc [catch { puts -nonewline $::blob "helloworld" } msg] + close $::blob list $rc $msg } "1 {channel \"$::blob\" wasn't opened for writing}" @@ -221,27 +222,31 @@ do_test incrblob-3.2 { # 4.3 - Attempt to open a table that does not exist. # 4.4 - Attempt to open a database that does not exist. # +# 4.5 - Attempt to open an integer +# 4.6 - Attempt to open a real value +# 4.7 - Attempt to open an SQL null +# +# 4.8 - Attempt to open an indexed column for writing +# 4.9 - Attempt to open an indexed column for reading (this works) +# do_test incrblob-4.1 { set rc [catch { set ::blob [db incrblob blobs v 2] } msg ] list $rc $msg } {1 {no such rowid: 2}} - do_test incrblob-4.2 { set rc [catch { set ::blob [db incrblob blobs blue 1] } msg ] list $rc $msg } {1 {no such column: "blue"}} - do_test incrblob-4.3 { set rc [catch { set ::blob [db incrblob nosuchtable blue 1] - } msg ] + } msg ] list $rc $msg } {1 {no such table: main.nosuchtable}} - do_test incrblob-4.4 { set rc [catch { set ::blob [db incrblob nosuchdb blobs v 1] @@ -249,5 +254,167 @@ do_test incrblob-4.4 { list $rc $msg } {1 {no such table: nosuchdb.blobs}} -finish_test +do_test incrblob-4.5 { + set rc [catch { + set ::blob [db incrblob blobs i 1] + } msg ] + list $rc $msg +} {1 {cannot open value of type integer}} +do_test incrblob-4.6 { + execsql { + INSERT INTO blobs(k, v, i) VALUES(123, 567.765, NULL); + } + set rc [catch { + set ::blob [db incrblob blobs v 2] + } msg ] + list $rc $msg +} {1 {cannot open value of type real}} +do_test incrblob-4.7 { + set rc [catch { + set ::blob [db incrblob blobs i 2] + } msg ] + list $rc $msg +} {1 {cannot open value of type null}} +do_test incrblob-4.8 { + execsql { + INSERT INTO blobs(k, v, i) VALUES(X'010203040506070809', 'hello', 'world'); + } + set rc [catch { + set ::blob [db incrblob blobs k 3] + } msg ] + list $rc $msg +} {1 {cannot open indexed column for writing}} + +do_test incrblob-4.9.1 { + set rc [catch { + set ::blob [db incrblob -readonly blobs k 3] + } msg] +} {0} +do_test incrblob-4.9.2 { + binary scan [read $::blob] c* c + close $::blob + set c +} {1 2 3 4 5 6 7 8 9} + +#------------------------------------------------------------------------ +# incrblob-5.*: +# +# Test that opening a blob in an attached database works. +# +do_test incrblob-5.1 { + file delete -force test2.db test2.db-journal + set ::size [expr [file size [info script]]] + execsql { + ATTACH 'test2.db' AS aux; + CREATE TABLE aux.files(name, text); + INSERT INTO aux.files VALUES('this one', zeroblob($::size)); + } + set fd [db incrblob aux files text 1] + set fd2 [open [info script]] + puts -nonewline $fd [read $fd2] + close $fd + close $fd2 + set ::text [db one {select text from aux.files}] + string length $::text +} [file size [info script]] +do_test incrblob-5.2 { + set fd2 [open [info script]] + set ::data [read $fd2] + close $fd2 + set ::data +} $::text + +# free memory +unset ::data +unset ::text + +#------------------------------------------------------------------------ +# incrblob-6.*: +# +# Test that opening a blob for write-access is impossible if +# another connection has the database RESERVED lock. +# +# Then test that blob writes that take place inside of a +# transaction are not visible to external connections until +# after the transaction is commited and the blob channel +# closed. +# +do_test incrblob-6.1 { + sqlite3 db2 test.db + execsql { + BEGIN; + INSERT INTO blobs(k, v, i) VALUES('a', 'different', 'connection'); + } db2 +} {} +do_test incrblob-6.2 { + execsql { + SELECT rowid FROM blobs + } +} {1 2 3} +do_test incrblob-6.3 { + set rc [catch { + db incrblob blobs v 1 + } msg] + list $rc $msg +} {1 {database is locked}} +do_test incrblob-6.4 { + set rc [catch { + db incrblob blobs v 3 + } msg] + list $rc $msg +} {1 {database is locked}} +do_test incrblob-6.5 { + set ::blob [db incrblob -readonly blobs v 3] + read $::blob +} {hello} +do_test incrblob-6.6 { + close $::blob +} {} + +do_test incrblob-6.7 { + set ::blob [db2 incrblob blobs i 4] + gets $::blob +} {connection} +do_test incrblob-6.8 { + tell $::blob +} {10} +breakpoint +do_test incrblob-6.9 { + seek $::blob 0 + puts -nonewline $::blob "invocation" + flush $::blob +} {} + +# At this point rollback or commit should be illegal (because +# there is an open blob channel). +do_test incrblob-6.10 { + catchsql { + ROLLBACK; + } db2 +} {1 {cannot rollback transaction - SQL statements in progress}} +do_test incrblob-6.11 { + catchsql { + COMMIT; + } db2 +} {1 {cannot commit transaction - SQL statements in progress}} + +do_test incrblob-6.12 { + execsql { + SELECT * FROM blobs WHERE rowid = 4; + } +} {} +do_test incrblob-6.13 { + close $::blob + execsql { + COMMIT; + } db2 +} {} +do_test incrblob-6.14 { + execsql { + SELECT * FROM blobs WHERE rowid = 4; + } +} {a different invocation} +db2 close + +finish_test