Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Add new test file e_blobopen.test, containing tests for sqlite3_blob_open(). |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA1: |
ecbccd0e594d22b3ae7fabc8037951dc |
User & Date: | dan 2014-11-07 14:41:11.404 |
Context
2014-11-10
| ||
14:42 | Shorten over-length source code lines in shell.c. (check-in: 7f3819f642 user: drh tags: trunk) | |
2014-11-07
| ||
14:41 | Add new test file e_blobopen.test, containing tests for sqlite3_blob_open(). (check-in: ecbccd0e59 user: dan tags: trunk) | |
14:37 | Fix another harmless comment typo. (check-in: b45bc80bb1 user: drh tags: trunk) | |
Changes
Changes to main.mk.
︙ | ︙ | |||
242 243 244 245 246 247 248 249 250 251 252 253 254 255 | $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ | > | 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 | $(TOP)/src/test6.c \ $(TOP)/src/test7.c \ $(TOP)/src/test8.c \ $(TOP)/src/test9.c \ $(TOP)/src/test_autoext.c \ $(TOP)/src/test_async.c \ $(TOP)/src/test_backup.c \ $(TOP)/src/test_blob.c \ $(TOP)/src/test_btree.c \ $(TOP)/src/test_config.c \ $(TOP)/src/test_demovfs.c \ $(TOP)/src/test_devsym.c \ $(TOP)/src/test_fs.c \ $(TOP)/src/test_func.c \ $(TOP)/src/test_hexio.c \ |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5652 5653 5654 5655 5656 5657 5658 5659 | ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located ** in row iRow, column zColumn, table zTable in database zDb; ** in other words, the same BLOB that would be selected by: ** ** <pre> ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** </pre>)^ ** | < < < < < < | | | | | > > > > | | > > > > > | > > > > > > > > > > > > > > > | | < < < > < < < | | < | 5652 5653 5654 5655 5656 5657 5658 5659 5660 5661 5662 5663 5664 5665 5666 5667 5668 5669 5670 5671 5672 5673 5674 5675 5676 5677 5678 5679 5680 5681 5682 5683 5684 5685 5686 5687 5688 5689 5690 5691 5692 5693 5694 5695 5696 5697 5698 5699 5700 5701 5702 5703 5704 5705 5706 5707 5708 5709 5710 5711 5712 5713 5714 5715 5716 5717 5718 5719 5720 5721 5722 | ** ^(This interfaces opens a [BLOB handle | handle] to the BLOB located ** in row iRow, column zColumn, table zTable in database zDb; ** in other words, the same BLOB that would be selected by: ** ** <pre> ** SELECT zColumn FROM zDb.zTable WHERE [rowid] = iRow; ** </pre>)^ ** ** ^(Parameter zDb is not the filename that contains the database, but ** rather the symbolic name of the database. For attached databases, this is ** the name that appears after the AS keyword in the [ATTACH] statement. ** For the main database file, the database name is "main". For TEMP ** tables, the database name is "temp".)^ ** ** ^If the flags parameter is non-zero, then the BLOB is opened for read ** and write access. ^If the flags parameter is zero, the BLOB is opened for ** read-only access. ** ** ^(On success, [SQLITE_OK] is returned and the new [BLOB handle] is stored ** in *ppBlob. Otherwise an [error code] is returned and, unless the error ** code is SQLITE_MISUSE, *ppBlob is set to NULL.)^ ^This means that, provided ** the API is not misused, it is always safe to call [sqlite3_blob_close()] ** on *ppBlob after this function it returns. ** ** This function fails with SQLITE_ERROR if any of the following are true: ** <ul> ** <li> ^(Database zDb does not exist)^, ** <li> ^(Table zTable does not exist within database zDb)^, ** <li> ^(Table zTable is a WITHOUT ROWID table)^, ** <li> ^(Column zColumn does not exist)^, ** <li> ^(Row iRow is not present in the table)^, ** <li> ^(The specified column of row iRow contains a value that is not ** a TEXT or BLOB value)^, ** <li> ^(Column zColumn is part of an index, PRIMARY KEY or UNIQUE ** constraint and the blob is being opened for read/write access)^, ** <li> ^([foreign key constraints | Foreign key constraints] are enabled, ** column zColumn is part of a [child key] definition and the blob is ** being opened for read/write access)^. ** </ul> ** ** ^Unless it returns SQLITE_MISUSE, this function sets the ** [database connection] error code and message accessible via ** [sqlite3_errcode()] and [sqlite3_errmsg()] and related functions. ** ** ** ^(If the row that a BLOB handle points to is modified by an ** [UPDATE], [DELETE], or by [ON CONFLICT] side-effects ** then the BLOB handle is marked as "expired". ** This is true if any column of the row is changed, even a column ** other than the one the BLOB handle is open on.)^ ** ^Calls to [sqlite3_blob_read()] and [sqlite3_blob_write()] for ** an expired BLOB handle fail with a return code of [SQLITE_ABORT]. ** ^(Changes written into a BLOB prior to the BLOB expiring are not ** rolled back by the expiration of the BLOB. Such changes will eventually ** commit if the transaction continues to completion.)^ ** ** ^Use the [sqlite3_blob_bytes()] interface to determine the size of ** the opened blob. ^The size of a blob may not be changed by this ** interface. Use the [UPDATE] SQL command to change the size of a ** blob. ** ** ^The [sqlite3_bind_zeroblob()] and [sqlite3_result_zeroblob()] interfaces ** and the built-in [zeroblob] SQL function may be used to create a ** zero-filled blob to read or write using the incremental-blob interface. ** ** To avoid a resource leak, every open [BLOB handle] should eventually ** be released by a call to [sqlite3_blob_close()]. */ int sqlite3_blob_open( sqlite3*, const char *zDb, |
︙ | ︙ |
Changes to src/tclsqlite.c.
︙ | ︙ | |||
3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 | extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*); extern int Sqlitetest8_Init(Tcl_Interp*); extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetest_mutex_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); | > | 3721 3722 3723 3724 3725 3726 3727 3728 3729 3730 3731 3732 3733 3734 3735 | extern int Sqlitetest5_Init(Tcl_Interp*); extern int Sqlitetest6_Init(Tcl_Interp*); extern int Sqlitetest7_Init(Tcl_Interp*); extern int Sqlitetest8_Init(Tcl_Interp*); extern int Sqlitetest9_Init(Tcl_Interp*); extern int Sqlitetestasync_Init(Tcl_Interp*); extern int Sqlitetest_autoext_Init(Tcl_Interp*); extern int Sqlitetest_blob_Init(Tcl_Interp*); extern int Sqlitetest_demovfs_Init(Tcl_Interp *); extern int Sqlitetest_func_Init(Tcl_Interp*); extern int Sqlitetest_hexio_Init(Tcl_Interp*); extern int Sqlitetest_init_Init(Tcl_Interp*); extern int Sqlitetest_malloc_Init(Tcl_Interp*); extern int Sqlitetest_mutex_Init(Tcl_Interp*); extern int Sqlitetestschema_Init(Tcl_Interp*); |
︙ | ︙ | |||
3764 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 | Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest7_Init(interp); Sqlitetest8_Init(interp); Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); | > | 3765 3766 3767 3768 3769 3770 3771 3772 3773 3774 3775 3776 3777 3778 3779 | Sqlitetest5_Init(interp); Sqlitetest6_Init(interp); Sqlitetest7_Init(interp); Sqlitetest8_Init(interp); Sqlitetest9_Init(interp); Sqlitetestasync_Init(interp); Sqlitetest_autoext_Init(interp); Sqlitetest_blob_Init(interp); Sqlitetest_demovfs_Init(interp); Sqlitetest_func_Init(interp); Sqlitetest_hexio_Init(interp); Sqlitetest_init_Init(interp); Sqlitetest_malloc_Init(interp); Sqlitetest_mutex_Init(interp); Sqlitetestschema_Init(interp); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
1647 1648 1649 1650 1651 1652 1653 | instanceData = Tcl_GetChannelInstanceData(channel); *ppBlob = *((sqlite3_blob **)instanceData); } return TCL_OK; } | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < | 1647 1648 1649 1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 | instanceData = Tcl_GetChannelInstanceData(channel); *ppBlob = *((sqlite3_blob **)instanceData); } return TCL_OK; } static int test_blob_reopen( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ Tcl_WideInt iRowid; |
︙ | ︙ | |||
6906 6907 6908 6909 6910 6911 6912 | { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB | < < < < | 6758 6759 6760 6761 6762 6763 6764 6765 6766 6767 6768 6769 6770 6771 6772 | { "sqlite3_shared_cache_report", sqlite3BtreeSharedCacheReport, 0}, #endif { "sqlite3_libversion_number", test_libversion_number, 0 }, #ifdef SQLITE_ENABLE_COLUMN_METADATA { "sqlite3_table_column_metadata", test_table_column_metadata, 0 }, #endif #ifndef SQLITE_OMIT_INCRBLOB { "sqlite3_blob_reopen", test_blob_reopen, 0 }, #endif { "pcache_stats", test_pcache_stats, 0 }, #ifdef SQLITE_ENABLE_UNLOCK_NOTIFY { "sqlite3_unlock_notify", test_unlock_notify, 0 }, #endif { "sqlite3_wal_checkpoint", test_wal_checkpoint, 0 }, { "sqlite3_wal_checkpoint_v2",test_wal_checkpoint_v2, 0 }, |
︙ | ︙ |
Added src/test_blob.c.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 | /* ** 2014 October 30 ** ** 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. ** ************************************************************************* ** */ #include "sqliteInt.h" #include "tcl.h" #include <stdlib.h> #include <string.h> #include <assert.h> /* These functions are implemented in main.c. */ extern const char *sqlite3ErrName(int); /* From test1.c: */ extern int getDbPointer(Tcl_Interp *interp, const char *zA, sqlite3 **ppDb); extern void *sqlite3TestTextToPtr(const char *z); /* ** Return a pointer to a buffer containing a text representation of the ** pointer passed as the only argument. The original pointer may be extracted ** from the text using sqlite3TestTextToPtr(). */ static char *ptrToText(void *p){ static char buf[100]; sqlite3_snprintf(sizeof(buf)-1, buf, "%p", p); return buf; } /* ** Attempt to extract a blob handle (type sqlite3_blob*) from the Tcl ** object passed as the second argument. If successful, set *ppBlob to ** point to the blob handle and return TCL_OK. Otherwise, store an error ** message in the tcl interpreter and return TCL_ERROR. The final value ** of *ppBlob is undefined in this case. ** ** If the object contains a string that begins with "incrblob_", then it ** is assumed to be the name of a Tcl channel opened using the [db incrblob] ** command (see tclsqlite.c). Otherwise, it is assumed to be a pointer ** encoded using the ptrToText() routine or similar. */ static int blobHandleFromObj( Tcl_Interp *interp, Tcl_Obj *pObj, sqlite3_blob **ppBlob ){ char *z; int n; z = Tcl_GetStringFromObj(pObj, &n); if( n==0 ){ *ppBlob = 0; }else if( n>9 && 0==memcmp("incrblob_", z, 9) ){ int notUsed; Tcl_Channel channel; ClientData instanceData; channel = Tcl_GetChannel(interp, z, ¬Used); if( !channel ) return TCL_ERROR; Tcl_Flush(channel); Tcl_Seek(channel, 0, SEEK_SET); instanceData = Tcl_GetChannelInstanceData(channel); *ppBlob = *((sqlite3_blob **)instanceData); }else{ *ppBlob = (sqlite3_blob*)sqlite3TestTextToPtr(z); } return TCL_OK; } /* ** Like Tcl_GetString(), except that if the string is 0 bytes in size, a ** NULL Pointer is returned. */ static char *blobStringFromObj(Tcl_Obj *pObj){ int n; char *z; z = Tcl_GetStringFromObj(pObj, &n); return (n ? z : 0); } /* ** sqlite3_blob_open DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME ** ** Tcl test harness for the sqlite3_blob_open() function. */ static int test_blob_open( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* Calling TCL interpreter */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3 *db; const char *zDb; const char *zTable; const char *zColumn; sqlite_int64 iRowid; int flags; const char *zVarname; int nVarname; sqlite3_blob *pBlob = (sqlite3_blob*)0xFFFFFFFF; int rc; if( objc!=8 ){ const char *zUsage = "DB DATABASE TABLE COLUMN ROWID FLAGS VARNAME"; Tcl_WrongNumArgs(interp, 1, objv, zUsage); return TCL_ERROR; } if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; zDb = Tcl_GetString(objv[2]); zTable = blobStringFromObj(objv[3]); zColumn = Tcl_GetString(objv[4]); if( Tcl_GetWideIntFromObj(interp, objv[5], &iRowid) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[6], &flags) ) return TCL_ERROR; zVarname = Tcl_GetStringFromObj(objv[7], &nVarname); if( nVarname>0 ){ rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, &pBlob); Tcl_SetVar(interp, zVarname, ptrToText(pBlob), 0); }else{ rc = sqlite3_blob_open(db, zDb, zTable, zColumn, iRowid, flags, 0); } if( rc==SQLITE_OK ){ Tcl_ResetResult(interp); }else{ Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); return TCL_ERROR; } return TCL_OK; } /* ** sqlite3_blob_close HANDLE */ static int test_blob_close( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int rc; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; rc = sqlite3_blob_close(pBlob); if( rc ){ Tcl_SetResult(interp, (char*)sqlite3ErrName(rc), TCL_VOLATILE); }else{ Tcl_ResetResult(interp); } return TCL_OK; } /* ** sqlite3_blob_bytes HANDLE */ static int test_blob_bytes( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int nByte; if( objc!=2 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE"); return TCL_ERROR; } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; nByte = sqlite3_blob_bytes(pBlob); Tcl_SetObjResult(interp, Tcl_NewIntObj(nByte)); return TCL_OK; } /* ** sqlite3_blob_read CHANNEL OFFSET N ** ** This command is used to test the sqlite3_blob_read() 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_read() ** to read N bytes from offset OFFSET from the underlying SQLite ** blob handle. ** ** On success, a byte-array object containing the read data is ** returned. On failure, the interpreter result is set to the ** text representation of the returned error code (i.e. "SQLITE_NOMEM") ** and a Tcl exception is thrown. */ static int test_blob_read( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int nByte; int iOffset; unsigned char *zBuf = 0; int rc; if( objc!=4 ){ Tcl_WrongNumArgs(interp, 1, objv, "CHANNEL OFFSET N"); return TCL_ERROR; } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) || TCL_OK!=Tcl_GetIntFromObj(interp, objv[3], &nByte) ){ return TCL_ERROR; } if( nByte>0 ){ zBuf = (unsigned char *)Tcl_Alloc(nByte); } rc = sqlite3_blob_read(pBlob, zBuf, nByte, iOffset); if( rc==SQLITE_OK ){ Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(zBuf, nByte)); }else{ Tcl_SetResult(interp, (char *)sqlite3ErrName(rc), TCL_VOLATILE); } Tcl_Free((char *)zBuf); return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } /* ** sqlite3_blob_write HANDLE 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() ** to write the DATA byte-array to the underlying SQLite blob handle. ** at offset OFFSET. ** ** On success, an empty string is returned. On failure, the interpreter ** result is set to the text representation of the returned error code ** (i.e. "SQLITE_NOMEM") and a Tcl exception is thrown. */ static int test_blob_write( ClientData clientData, /* Not used */ Tcl_Interp *interp, /* The TCL interpreter that invoked this command */ int objc, /* Number of arguments */ Tcl_Obj *CONST objv[] /* Command arguments */ ){ sqlite3_blob *pBlob; int iOffset; int rc; unsigned char *zBuf; int nBuf; if( objc!=4 && objc!=5 ){ Tcl_WrongNumArgs(interp, 1, objv, "HANDLE OFFSET DATA ?NDATA?"); return TCL_ERROR; } if( blobHandleFromObj(interp, objv[1], &pBlob) ) return TCL_ERROR; if( TCL_OK!=Tcl_GetIntFromObj(interp, objv[2], &iOffset) ){ return TCL_ERROR; } 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 *)sqlite3ErrName(rc), TCL_VOLATILE); } return (rc==SQLITE_OK ? TCL_OK : TCL_ERROR); } /* ** Register commands with the TCL interpreter. */ int Sqlitetest_blob_Init(Tcl_Interp *interp){ static struct { char *zName; Tcl_ObjCmdProc *xProc; } aObjCmd[] = { { "sqlite3_blob_open", test_blob_open }, { "sqlite3_blob_close", test_blob_close }, { "sqlite3_blob_bytes", test_blob_bytes }, { "sqlite3_blob_read", test_blob_read }, { "sqlite3_blob_write", test_blob_write }, }; int i; for(i=0; i<sizeof(aObjCmd)/sizeof(aObjCmd[0]); i++){ Tcl_CreateObjCommand(interp, aObjCmd[i].zName, aObjCmd[i].xProc, 0, 0); } return TCL_OK; } |
Changes to src/test_config.c.
︙ | ︙ | |||
150 151 152 153 154 155 156 157 158 159 160 161 162 163 | #endif #ifdef SQLITE_OMIT_ANALYZE Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif | > > > > > > | 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 | #endif #ifdef SQLITE_OMIT_ANALYZE Tcl_SetVar2(interp, "sqlite_options", "analyze", "0", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "analyze", "1", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_API_ARMOR Tcl_SetVar2(interp, "sqlite_options", "api_armor", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "api_armor", "0", TCL_GLOBAL_ONLY); #endif #ifdef SQLITE_ENABLE_ATOMIC_WRITE Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "1", TCL_GLOBAL_ONLY); #else Tcl_SetVar2(interp, "sqlite_options", "atomicwrite", "0", TCL_GLOBAL_ONLY); #endif |
︙ | ︙ |
Changes to src/vdbe.c.
︙ | ︙ | |||
3794 3795 3796 3797 3798 3799 3800 | if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); #endif } pIdxKey = &r; }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree | | | > | 3794 3795 3796 3797 3798 3799 3800 3801 3802 3803 3804 3805 3806 3807 3808 3809 3810 3811 3812 | if( ii ) REGISTER_TRACE(pOp->p3+ii, &r.aMem[ii]); #endif } pIdxKey = &r; }else{ pIdxKey = sqlite3VdbeAllocUnpackedRecord( pC->pKeyInfo, aTempRec, sizeof(aTempRec), &pFree ); if( pIdxKey==0 ) goto no_mem; assert( pIn3->flags & MEM_Blob ); /* assert( (pIn3->flags & MEM_Zero)==0 ); // zeroblobs already expanded */ ExpandBlob(pIn3); sqlite3VdbeRecordUnpack(pC->pKeyInfo, pIn3->n, pIn3->z, pIdxKey); } pIdxKey->default_rc = 0; if( pOp->opcode==OP_NoConflict ){ /* For the OP_NoConflict opcode, take the jump if any of the ** input fields are NULL, since any key with a NULL will not ** conflict */ |
︙ | ︙ |
Added test/e_blobopen.test.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 | # 2014 October 30 # # 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. # #*********************************************************************** # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix e_blobopen forcedelete test.db2 do_execsql_test 1.0 { ATTACH 'test.db2' AS aux; CREATE TABLE main.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); CREATE TEMP TABLE t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); CREATE TABLE aux.t1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); CREATE TABLE main.x1(a INTEGER PRIMARY KEY, b TEXT, c BLOB); CREATE TEMP TABLE x2(a INTEGER PRIMARY KEY, b TEXT, c BLOB); CREATE TABLE aux.x3(a INTEGER PRIMARY KEY, b TEXT, c BLOB); INSERT INTO main.t1 VALUES(1, 'main one', X'0101'); INSERT INTO main.t1 VALUES(2, 'main two', X'0102'); INSERT INTO main.t1 VALUES(3, 'main three', X'0103'); INSERT INTO main.t1 VALUES(4, 'main four', X'0104'); INSERT INTO main.t1 VALUES(5, 'main five', X'0105'); INSERT INTO main.x1 VALUES(1, 'x main one', X'000101'); INSERT INTO main.x1 VALUES(2, 'x main two', X'000102'); INSERT INTO main.x1 VALUES(3, 'x main three', X'000103'); INSERT INTO main.x1 VALUES(4, 'x main four', X'000104'); INSERT INTO main.x1 VALUES(5, 'x main five', X'000105'); INSERT INTO temp.t1 VALUES(1, 'temp one', X'0201'); INSERT INTO temp.t1 VALUES(2, 'temp two', X'0202'); INSERT INTO temp.t1 VALUES(3, 'temp three', X'0203'); INSERT INTO temp.t1 VALUES(4, 'temp four', X'0204'); INSERT INTO temp.t1 VALUES(5, 'temp five', X'0205'); INSERT INTO temp.x2 VALUES(1, 'x temp one', X'000201'); INSERT INTO temp.x2 VALUES(2, 'x temp two', X'000202'); INSERT INTO temp.x2 VALUES(3, 'x temp three', X'000203'); INSERT INTO temp.x2 VALUES(4, 'x temp four', X'000204'); INSERT INTO temp.x2 VALUES(5, 'x temp five', X'000205'); INSERT INTO aux.t1 VALUES(1, 'aux one', X'0301'); INSERT INTO aux.t1 VALUES(2, 'aux two', X'0302'); INSERT INTO aux.t1 VALUES(3, 'aux three', X'0303'); INSERT INTO aux.t1 VALUES(4, 'aux four', X'0304'); INSERT INTO aux.t1 VALUES(5, 'aux five', X'0305'); INSERT INTO aux.x3 VALUES(1, 'x aux one', X'000301'); INSERT INTO aux.x3 VALUES(2, 'x aux two', X'000302'); INSERT INTO aux.x3 VALUES(3, 'x aux three', X'000303'); INSERT INTO aux.x3 VALUES(4, 'x aux four', X'000304'); INSERT INTO aux.x3 VALUES(5, 'x aux five', X'000305'); } #------------------------------------------------------------------------- # EVIDENCE-OF: R-37639-55938 This interfaces opens a handle to the BLOB # located in row iRow, column zColumn, table zTable in database zDb; in # other words, the same BLOB that would be selected by: SELECT zColumn # FROM zDb.zTable WHERE rowid = iRow; # proc read_blob {zDb zTab zCol iRow} { sqlite3_blob_open db $zDb $zTab $zCol $iRow 0 B set nByte [sqlite3_blob_bytes $B] set data [sqlite3_blob_read $B 0 $nByte] sqlite3_blob_close $B return $data } do_test 1.1.1 { read_blob main t1 b 1 } "main one" do_test 1.1.2 { read_blob main t1 c 1 } "\01\01" do_test 1.1.3 { read_blob temp t1 b 1 } "temp one" do_test 1.1.4 { read_blob temp t1 c 1 } "\02\01" do_test 1.1.6 { read_blob aux t1 b 1 } "aux one" do_test 1.1.7 { read_blob aux t1 c 1 } "\03\01" do_test 1.2.1 { read_blob main t1 b 4 } "main four" do_test 1.2.2 { read_blob main t1 c 4 } "\01\04" do_test 1.2.3 { read_blob temp t1 b 4 } "temp four" do_test 1.2.4 { read_blob temp t1 c 4 } "\02\04" do_test 1.2.6 { read_blob aux t1 b 4 } "aux four" do_test 1.2.7 { read_blob aux t1 c 4 } "\03\04" do_test 1.3.1 { read_blob main x1 b 2 } "x main two" do_test 1.3.2 { read_blob main x1 c 2 } "\00\01\02" do_test 1.3.3 { read_blob temp x2 b 2 } "x temp two" do_test 1.3.4 { read_blob temp x2 c 2 } "\00\02\02" do_test 1.3.6 { read_blob aux x3 b 2 } "x aux two" do_test 1.3.7 { read_blob aux x3 c 2 } "\00\03\02" #------------------------------------------------------------------------- # EVIDENCE-OF: R-27234-05761 Parameter zDb is not the filename that # contains the database, but rather the symbolic name of the database. # For attached databases, this is the name that appears after the AS # keyword in the ATTACH statement. For the main database file, the # database name is "main". For TEMP tables, the database name is "temp". # # The test cases immediately above demonstrate that the database name # for the main db, for TEMP tables and for those in attached databases # is correct. The following tests check that filenames cannot be # used as well. # do_test 2.1 { list [catch { sqlite3_blob_open db "test.db" t1 b 1 0 B } msg] $msg } {1 SQLITE_ERROR} do_test 2.2 { list [catch { sqlite3_blob_open db "test.db2" t1 b 1 0 B } msg] $msg } {1 SQLITE_ERROR} #------------------------------------------------------------------------- # EVIDENCE-OF: R-50854-53979 If the flags parameter is non-zero, then # the BLOB is opened for read and write access. # # EVIDENCE-OF: R-03922-41160 If the flags parameter is zero, the BLOB is # opened for read-only access. # foreach {tn iRow flags} { 1 1 0 2 2 1 3 3 -1 4 4 2147483647 5 5 -2147483648 } { do_test 3.$tn.1 { sqlite3_blob_open db main x1 c $iRow $flags B set n [sqlite3_blob_bytes $B] sqlite3_blob_read $B 0 $n } [binary format ccc 0 1 $iRow] if {$flags==0} { # Blob was opened for read-only access - writing returns an error. do_test 3.$tn.2 { list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg } {1 SQLITE_READONLY} do_execsql_test 3.$tn.3 { SELECT c FROM x1 WHERE a=$iRow; } [binary format ccc 0 1 $iRow] } else { # Blob was opened for read/write access - writing succeeds do_test 3.$tn.4 { list [catch { sqlite3_blob_write $B 0 xxx 3 } msg] $msg } {0 {}} do_execsql_test 3.$tn.5 { SELECT c FROM x1 WHERE a=$iRow; } {xxx} } sqlite3_blob_close $B } #------------------------------------------------------------------------- # reset_db do_execsql_test 4.0 { CREATE TABLE t1(x, y); INSERT INTO t1 VALUES('abcd', 152); INSERT INTO t1 VALUES(NULL, X'00010203'); INSERT INTO t1 VALUES('', 154.2); CREATE TABLE t2(x PRIMARY KEY, y) WITHOUT ROWID; INSERT INTO t2 VALUES(1, 'blob'); CREATE TABLE t3(a PRIMARY KEY, b, c, d, e, f, UNIQUE(e, f)); INSERT INTO t3 VALUES('aaaa', 'bbbb', 'cccc', 'dddd', 'eeee', 'ffff'); CREATE INDEX t3b ON t3(b); CREATE TABLE p1(x PRIMARY KEY); INSERT INTO p1 VALUES('abc'); CREATE TABLE c1(a INTEGER PRIMARY KEY, b REFERENCES p1); INSERT INTO c1 VALUES(45, 'abc'); } proc test_blob_open {tn zDb zTab zCol iRow flags errcode errmsg} { global B set B "0x1234" if {$errcode=="SQLITE_OK"} { set expected "0 {}" } else { set expected "1 $errcode" } set ::res [list [ catch { sqlite3_blob_open db $zDb $zTab $zCol $iRow $flags B } msg ] $msg] do_test 4.$tn.1 { set ::res } $expected # EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this # function sets the database connection error code and message # accessible via sqlite3_errcode() and sqlite3_errmsg() and related # functions. # # This proc (test_blob_open) is used below to test various error and # non-error conditions. But never SQLITE_MISUSE conditions. So these # test cases are considered as partly verifying the requirement above. # See below for a test of the SQLITE_MISUSE case. # do_test 4.$tn.2 { sqlite3_errcode db } $errcode do_test 4.$tn.3 { sqlite3_errmsg db } $errmsg # EVIDENCE-OF: R-31086-35521 On success, SQLITE_OK is returned and the # new BLOB handle is stored in *ppBlob. Otherwise an error code is # returned and, unless the error code is SQLITE_MISUSE, *ppBlob is set # to NULL. # do_test 4.$tn.4 { expr {$B == "0"} } [expr {$errcode != "SQLITE_OK"}] # EVIDENCE-OF: R-63421-15521 This means that, provided the API is not # misused, it is always safe to call sqlite3_blob_close() on *ppBlob # after this function it returns. do_test 4.$tn.5 { sqlite3_blob_close $B } {} } # EVIDENCE-OF: R-31204-44780 Database zDb does not exist test_blob_open 1 nosuchdb t1 x 1 0 SQLITE_ERROR "no such table: nosuchdb.t1" # EVIDENCE-OF: R-28676-08005 Table zTable does not exist within database zDb test_blob_open 2 main tt1 x 1 0 SQLITE_ERROR "no such table: main.tt1" # EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table test_blob_open 3 main t2 y 1 0 SQLITE_ERROR \ "cannot open table without rowid: t2" # EVIDENCE-OF: R-56376-21261 Column zColumn does not exist test_blob_open 4 main t1 z 2 0 SQLITE_ERROR "no such column: \"z\"" # EVIDENCE-OF: R-28258-23166 Row iRow is not present in the table test_blob_open 5 main t1 y 6 0 SQLITE_ERROR "no such rowid: 6" # EVIDENCE-OF: R-11683-62380 The specified column of row iRow contains a # value that is not a TEXT or BLOB value test_blob_open 6 main t1 x 2 0 SQLITE_ERROR "cannot open value of type null" test_blob_open 7 main t1 y 1 0 SQLITE_ERROR "cannot open value of type integer" test_blob_open 8 main t1 y 3 0 SQLITE_ERROR "cannot open value of type real" # EVIDENCE-OF: R-34146-30782 Column zColumn is part of an index, PRIMARY # KEY or UNIQUE constraint and the blob is being opened for read/write # access # # Test cases 8.1.* show that such columns can be opened for read-access. # Tests 8.2.* show that read-write access is different. Columns "c" and "c" # are not part of an index, PK or UNIQUE constraint, so they work in both # cases. # test_blob_open 8.1.1 main t3 a 1 0 SQLITE_OK "not an error" test_blob_open 8.1.2 main t3 b 1 0 SQLITE_OK "not an error" test_blob_open 8.1.3 main t3 c 1 0 SQLITE_OK "not an error" test_blob_open 8.1.4 main t3 d 1 0 SQLITE_OK "not an error" test_blob_open 8.1.5 main t3 e 1 0 SQLITE_OK "not an error" test_blob_open 8.1.6 main t3 f 1 0 SQLITE_OK "not an error" set cannot "cannot open indexed column for writing" test_blob_open 8.2.1 main t3 a 1 8 SQLITE_ERROR $cannot test_blob_open 8.2.2 main t3 b 1 8 SQLITE_ERROR $cannot test_blob_open 8.2.3 main t3 c 1 8 SQLITE_OK "not an error" test_blob_open 8.2.4 main t3 d 1 8 SQLITE_OK "not an error" test_blob_open 8.2.5 main t3 e 1 8 SQLITE_ERROR $cannot test_blob_open 8.2.6 main t3 f 1 8 SQLITE_ERROR $cannot # EVIDENCE-OF: R-50117-55204 Foreign key constraints are enabled, column # zColumn is part of a child key definition and the blob is being opened # for read/write access # # 9.1: FK disabled, read-only access. # 9.2: FK disabled, read-only access. # 9.3: FK enabled, read/write access. # 9.4: FK enabled, read/write access. # test_blob_open 9.1 main c1 b 45 0 SQLITE_OK "not an error" test_blob_open 9.2 main c1 b 45 1 SQLITE_OK "not an error" execsql { PRAGMA foreign_keys = ON } test_blob_open 9.3 main c1 b 45 0 SQLITE_OK "not an error" test_blob_open 9.4 main c1 b 45 1 SQLITE_ERROR \ "cannot open foreign key column for writing" #------------------------------------------------------------------------- # EVIDENCE-OF: R-08940-21305 Unless it returns SQLITE_MISUSE, this # function sets the database connection error code and message # accessible via sqlite3_errcode() and sqlite3_errmsg() and related # functions. # # This requirement is partially verified by the many uses of test # command [test_blob_open] above. All that is left is to verify the # SQLITE_MISUSE case. # # SQLITE_MISUSE is only returned if SQLITE_ENABLE_API_ARMOR is defined # during compilation. # ifcapable api_armor { sqlite3_blob_open db main t1 x 1 0 B do_test 10.1.1 { list [catch {sqlite3_blob_open $B main t1 x 1 0 B2} msg] $msg } {1 SQLITE_MISUSE} do_test 10.1.2 { list [sqlite3_errcode db] [sqlite3_errmsg db] } {SQLITE_OK {not an error}} sqlite3_blob_close $B do_test 10.2.1 { list [catch {sqlite3_blob_open db main {} x 1 0 B} msg] $msg } {1 SQLITE_MISUSE} do_test 10.2.2 { list [sqlite3_errcode db] [sqlite3_errmsg db] } {SQLITE_OK {not an error}} } #------------------------------------------------------------------------- # EVIDENCE-OF: R-50542-62589 If the row that a BLOB handle points to is # modified by an UPDATE, DELETE, or by ON CONFLICT side-effects then the # BLOB handle is marked as "expired". This is true if any column of the # row is changed, even a column other than the one the BLOB handle is # open on. # # EVIDENCE-OF: R-48367-20048 Calls to sqlite3_blob_read() and # sqlite3_blob_write() for an expired BLOB handle fail with a return # code of SQLITE_ABORT. # # 11.2: read-only handle, DELETE. # 11.3: read-only handle, UPDATE. # 11.4: read-only handle, REPLACE. # 11.5: read/write handle, DELETE. # 11.6: read/write handle, UPDATE. # 11.7: read/write handle, REPLACE. # do_execsql_test 11.1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b, c UNIQUE); INSERT INTO b1 VALUES(1, '1234567890', 1); INSERT INTO b1 VALUES(2, '1234567890', 2); INSERT INTO b1 VALUES(3, '1234567890', 3); INSERT INTO b1 VALUES(4, '1234567890', 4); INSERT INTO b1 VALUES(5, '1234567890', 5); INSERT INTO b1 VALUES(6, '1234567890', 6); CREATE TABLE b2(a INTEGER PRIMARY KEY, b, c UNIQUE); INSERT INTO b2 VALUES(1, '1234567890', 1); INSERT INTO b2 VALUES(2, '1234567890', 2); INSERT INTO b2 VALUES(3, '1234567890', 3); INSERT INTO b2 VALUES(4, '1234567890', 4); INSERT INTO b2 VALUES(5, '1234567890', 5); INSERT INTO b2 VALUES(6, '1234567890', 6); } do_test 11.2.1 { sqlite3_blob_open db main b1 b 2 0 B sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.2.2 { # Deleting a different row does not invalidate the blob handle. execsql { DELETE FROM b1 WHERE a = 1 } sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.2.3 { execsql { DELETE FROM b1 WHERE a = 2 } list [catch { sqlite3_blob_read $B 0 10 } msg] $msg } {1 SQLITE_ABORT} do_test 11.2.4 { sqlite3_blob_close $B } {} do_test 11.3.1 { sqlite3_blob_open db main b1 b 3 0 B sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.3.2 { # Updating a different row execsql { UPDATE b1 SET c = 42 WHERE a=4 } sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.3.3 { execsql { UPDATE b1 SET c = 43 WHERE a=3 } list [catch { sqlite3_blob_read $B 0 10 } msg] $msg } {1 SQLITE_ABORT} do_test 11.3.4 { sqlite3_blob_close $B } {} do_test 11.4.1 { sqlite3_blob_open db main b1 b 6 0 B sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.4.2 { # Replace a different row execsql { INSERT OR REPLACE INTO b1 VALUES(10, 'abcdefghij', 5) } sqlite3_blob_read $B 0 10 } {1234567890} do_test 11.4.3 { execsql { INSERT OR REPLACE INTO b1 VALUES(11, 'abcdefghij', 6) } list [catch { sqlite3_blob_read $B 0 10 } msg] $msg } {1 SQLITE_ABORT} do_test 11.4.4 { sqlite3_blob_close $B } {} do_test 11.4.1 { sqlite3_blob_open db main b2 b 2 1 B sqlite3_blob_write $B 0 "abcdefghij" } {} do_test 11.4.2 { # Deleting a different row does not invalidate the blob handle. execsql { DELETE FROM b2 WHERE a = 1 } sqlite3_blob_write $B 0 "ABCDEFGHIJ" } {} do_test 11.4.3 { execsql { DELETE FROM b2 WHERE a = 2 } list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg } {1 SQLITE_ABORT} do_test 11.4.4 { sqlite3_blob_close $B } {} do_test 11.5.1 { sqlite3_blob_open db main b2 b 3 1 B sqlite3_blob_write $B 0 "abcdefghij" } {} do_test 11.5.2 { # Updating a different row execsql { UPDATE b2 SET c = 42 WHERE a=4 } sqlite3_blob_write $B 0 "ABCDEFGHIJ" } {} do_test 11.5.3 { execsql { UPDATE b2 SET c = 43 WHERE a=3 } list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg } {1 SQLITE_ABORT} do_test 11.5.4 { sqlite3_blob_close $B } {} do_test 11.6.1 { sqlite3_blob_open db main b2 b 6 1 B sqlite3_blob_write $B 0 "abcdefghij" } {} do_test 11.6.2 { # Replace a different row execsql { INSERT OR REPLACE INTO b2 VALUES(10, 'abcdefghij', 5) } sqlite3_blob_write $B 0 "ABCDEFGHIJ" } {} do_test 11.6.3 { execsql { INSERT OR REPLACE INTO b2 VALUES(11, 'abcdefghij', 6) } list [catch { sqlite3_blob_write $B 0 "0987654321" } msg] $msg } {1 SQLITE_ABORT} do_test 11.6.4 { sqlite3_blob_close $B } {} #------------------------------------------------------------------------- # EVIDENCE-OF: R-45408-40694 Changes written into a BLOB prior to the # BLOB expiring are not rolled back by the expiration of the BLOB. Such # changes will eventually commit if the transaction continues to # completion. # do_execsql_test 12.1 { CREATE TABLE b3(x INTEGER PRIMARY KEY, y TEXT, z INTEGER); INSERT INTO b3 VALUES(22, '..........', NULL); } do_test 12.2 { sqlite3_blob_open db main b3 y 22 1 B sqlite3_blob_write $B 0 "xxxxx" 5 } {} do_execsql_test 12.3 { UPDATE b3 SET z = 'not null'; } do_test 12.4 { list [catch {sqlite3_blob_write $B 5 "xxxxx" 5} msg] $msg } {1 SQLITE_ABORT} do_execsql_test 12.5 { SELECT * FROM b3; } {22 xxxxx..... {not null}} do_test 12.5 { sqlite3_blob_close $B } {} do_execsql_test 12.6 { SELECT * FROM b3; } {22 xxxxx..... {not null}} #------------------------------------------------------------------------- # EVIDENCE-OF: R-58813-55036 The sqlite3_bind_zeroblob() and # sqlite3_result_zeroblob() interfaces and the built-in zeroblob SQL # function may be used to create a zero-filled blob to read or write # using the incremental-blob interface. # do_execsql_test 13.1 { CREATE TABLE c2(i INTEGER PRIMARY KEY, j); INSERT INTO c2 VALUES(10, zeroblob(24)); } do_test 13.2 { set stmt [sqlite3_prepare_v2 db "INSERT INTO c2 VALUES(11, ?)" -1] sqlite3_bind_zeroblob $stmt 1 45 sqlite3_step $stmt sqlite3_finalize $stmt } {SQLITE_OK} # The blobs can be read: # do_test 13.3.1 { sqlite3_blob_open db main c2 j 10 1 B sqlite3_blob_open db main c2 j 11 1 B2 list [sqlite3_blob_bytes $B] [sqlite3_blob_bytes $B2] } {24 45} do_test 13.3.2 { sqlite3_blob_read $B 0 24 } [string repeat [binary format c 0] 24] do_test 13.3.3 { sqlite3_blob_read $B2 0 45 } [string repeat [binary format c 0] 45] # And also written: # do_test 13.4.1 { sqlite3_blob_write $B 0 [string repeat [binary format c 1] 24] } {} do_test 13.4.2 { sqlite3_blob_write $B2 0 [string repeat [binary format c 1] 45] } {} do_test 13.5 { sqlite3_blob_close $B sqlite3_blob_close $B2 execsql { SELECT j FROM c2 } } [list \ [string repeat [binary format c 1] 24] \ [string repeat [binary format c 1] 45] \ ] finish_test |
Changes to test/fkey7.test.
︙ | ︙ | |||
46 47 48 49 50 51 52 53 54 | } do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1} do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} finish_test | > > > > > > > > > > > > > > > > > | 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 | } do_tblsread_test 1.2 { UPDATE par SET b=? WHERE a=? } {par s1} do_tblsread_test 1.3 { UPDATE par SET a=? WHERE b=? } {c1 c2 par} do_tblsread_test 1.4 { UPDATE par SET c=? WHERE b=? } {c3 par} do_tblsread_test 1.5 { UPDATE par SET a=?,b=?,c=? WHERE b=? } {c1 c2 c3 par s1} ifcapable incrblob { do_execsql_test 2.0 { CREATE TABLE pX(x PRIMARY KEY); CREATE TABLE cX(a INTEGER PRIMARY KEY, b REFERENCES pX); } do_catchsql_test 2.1 { INSERT INTO cX VALUES(11, zeroblob(40)); } {1 {FOREIGN KEY constraint failed}} do_test 2.2 { set stmt [sqlite3_prepare_v2 db "INSERT INTO cX VALUES(11, ?)" -1] sqlite3_bind_zeroblob $stmt 1 45 sqlite3_step $stmt sqlite3_finalize $stmt } {SQLITE_CONSTRAINT} } finish_test |
Changes to test/without_rowid5.test.
︙ | ︙ | |||
181 182 183 184 185 186 187 | do_execsql_test without_rowid5-5.9 { SELECT count(*) FROM nnw; } {1} # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # | < | | 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 | do_execsql_test without_rowid5-5.9 { SELECT count(*) FROM nnw; } {1} # EVIDENCE-OF: R-12643-30541 The incremental blob I/O mechanism does not # work for WITHOUT ROWID tables. # # EVIDENCE-OF: R-40134-30296 Table zTable is a WITHOUT ROWID table # do_execsql_test without_rowid5-6.1 { CREATE TABLE b1(a INTEGER PRIMARY KEY, b BLOB) WITHOUT ROWID; INSERT INTO b1 VALUES(1,x'0102030405060708090a0b0c0d0e0f'); } {} do_test without_rowid5-6.2 { set rc [catch {db incrblob b1 b 1} msg] |
︙ | ︙ |