Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Per /chat and forum discussions: (A) Remove the value type output pointer from text/blob_v2(). (B) Teach blob_v2() to return an opaque non-NULL pointer for length-0 blobs. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | column-text-blob-v2 |
Files: | files | file ages | folders |
SHA3-256: |
c96539beb5ca3c6a467e5388b9427677 |
User & Date: | stephan 2025-07-02 13:24:50.303 |
Context
2025-07-02
| ||
15:29 | Correct mis-placed OOM checks in valueToTextV2(). (check-in: 9226a2a3c6 user: stephan tags: column-text-blob-v2) | |
13:24 | Per /chat and forum discussions: (A) Remove the value type output pointer from text/blob_v2(). (B) Teach blob_v2() to return an opaque non-NULL pointer for length-0 blobs. (check-in: c96539beb5 user: stephan tags: column-text-blob-v2) | |
07:52 | Add test1.c tcl bindings for sqlite3_column_text/blob_v2(). Replace, essentially randomly, some of the v1 API calls in capi2.test and capi2.test with the v2 calls to ensure identical results. Add a couple new tests comparing results between v1 and v2. (check-in: a3ca0adbaf user: stephan tags: column-text-blob-v2) | |
Changes
Changes to ext/wasm/api/sqlite3-api-glue.c-pp.js.
︙ | ︙ | |||
109 110 111 112 113 114 115 | /* sqlite3_cancel_auto_extension() has a hand-written binding. */ /* sqlite3_close_v2() is implemented by hand to perform some extra work. */ ["sqlite3_changes", "int", "sqlite3*"], ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/], ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], | | | | 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 | /* sqlite3_cancel_auto_extension() has a hand-written binding. */ /* sqlite3_close_v2() is implemented by hand to perform some extra work. */ ["sqlite3_changes", "int", "sqlite3*"], ["sqlite3_clear_bindings","int", "sqlite3_stmt*"], ["sqlite3_collation_needed", "int", "sqlite3*", "*", "*"/*=>v(ppis)*/], ["sqlite3_column_blob","*", "sqlite3_stmt*", "int"], ["sqlite3_column_blob_v2", "int", "sqlite3_stmt*", "int", "**", "*"], ["sqlite3_column_bytes","int", "sqlite3_stmt*", "int"], ["sqlite3_column_count", "int", "sqlite3_stmt*"], ["sqlite3_column_decltype", "string", "sqlite3_stmt*", "int"], ["sqlite3_column_double","f64", "sqlite3_stmt*", "int"], ["sqlite3_column_int","int", "sqlite3_stmt*", "int"], ["sqlite3_column_name","string", "sqlite3_stmt*", "int"], ["sqlite3_column_text","string", "sqlite3_stmt*", "int"], ["sqlite3_column_text_v2", "int", "sqlite3_stmt*", "int", "**", "*"], ["sqlite3_column_type","int", "sqlite3_stmt*", "int"], ["sqlite3_column_value","sqlite3_value*", "sqlite3_stmt*", "int"], ["sqlite3_commit_hook", "void*", [ "sqlite3*", new wasm.xWrap.FuncPtrAdapter({ name: 'sqlite3_commit_hook', signature: 'i(p)', |
︙ | ︙ | |||
303 304 305 306 307 308 309 | their first C-string arguments, so we cannot perform any value conversion on those. */ ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], ["sqlite3_user_data","void*", "sqlite3_context*"], ["sqlite3_value_blob", "*", "sqlite3_value*"], | | | | 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 | their first C-string arguments, so we cannot perform any value conversion on those. */ ["sqlite3_uri_boolean", "int", "sqlite3_filename", "string", "int"], ["sqlite3_uri_key", "string", "sqlite3_filename", "int"], ["sqlite3_uri_parameter", "string", "sqlite3_filename", "string"], ["sqlite3_user_data","void*", "sqlite3_context*"], ["sqlite3_value_blob", "*", "sqlite3_value*"], ["sqlite3_value_blob_v2", "int", "sqlite3_value*", "**", "*"], ["sqlite3_value_bytes","int", "sqlite3_value*"], ["sqlite3_value_double","f64", "sqlite3_value*"], ["sqlite3_value_dup", "sqlite3_value*", "sqlite3_value*"], ["sqlite3_value_free", undefined, "sqlite3_value*"], ["sqlite3_value_frombind", "int", "sqlite3_value*"], ["sqlite3_value_int","int", "sqlite3_value*"], ["sqlite3_value_nochange", "int", "sqlite3_value*"], ["sqlite3_value_numeric_type", "int", "sqlite3_value*"], ["sqlite3_value_pointer", "*", "sqlite3_value*", "string:static"], ["sqlite3_value_subtype", "int", "sqlite3_value*"], ["sqlite3_value_text", "string", "sqlite3_value*"], ["sqlite3_value_text_v2", "int", "sqlite3_value*", "**", "*"], ["sqlite3_value_type", "int", "sqlite3_value*"], ["sqlite3_vfs_find", "*", "string"], ["sqlite3_vfs_register", "int", "sqlite3_vfs*", "int"], ["sqlite3_vfs_unregister", "int", "sqlite3_vfs*"] ]/*wasm.bindingSignatures*/; if( !!wasm.exports.sqlite3_progress_handler ){ |
︙ | ︙ |
Changes to ext/wasm/tester1.c-pp.js.
︙ | ︙ | |||
3348 3349 3350 3351 3352 3353 3354 | "values(1,123),(2,null),(3,'hi world'),(4,X'232A'),(5,'')"]); const P = wasm.pstack; const stack = P.pointer; let q; try { let sv, rc; q = db.prepare("select a, b from t order by a"); | | | | | | | | | | | | | | | | | | | | < < < | | > > | > | < | | < < < < < | | | | | | > | | | < > | 3348 3349 3350 3351 3352 3353 3354 3355 3356 3357 3358 3359 3360 3361 3362 3363 3364 3365 3366 3367 3368 3369 3370 3371 3372 3373 3374 3375 3376 3377 3378 3379 3380 3381 3382 3383 3384 3385 3386 3387 3388 3389 3390 3391 3392 3393 3394 3395 3396 3397 3398 3399 3400 3401 3402 3403 3404 3405 3406 3407 3408 3409 3410 3411 3412 3413 3414 3415 3416 3417 3418 3419 3420 3421 3422 3423 3424 3425 3426 3427 3428 3429 3430 3431 3432 3433 3434 3435 3436 3437 3438 3439 3440 3441 3442 3443 3444 3445 3446 3447 3448 3449 3450 3451 3452 3453 3454 3455 3456 3457 3458 3459 3460 3461 3462 3463 3464 3465 3466 3467 3468 3469 3470 3471 3472 3473 3474 3475 3476 3477 3478 3479 3480 3481 3482 3483 3484 3485 3486 3487 3488 3489 3490 3491 3492 3493 3494 3495 3496 | "values(1,123),(2,null),(3,'hi world'),(4,X'232A'),(5,'')"]); const P = wasm.pstack; const stack = P.pointer; let q; try { let sv, rc; q = db.prepare("select a, b from t order by a"); let [ppOut, pnOut] = P.allocPtr(2); const clearPtrs = ()=>{ wasm.pokePtr(ppOut, 0).poke32(pnOut, 0); }; const next = ()=>{ T.assert( q.step() ); sv = capi.sqlite3_column_value(q, 1); T.assert( sv ); clearPtrs(); rc = capi.sqlite3_value_text_v2(sv, ppOut, pnOut); T.assert( 0===rc ); return sv; }; const cmp = function(expect){ const blob = wasm.peekPtr(ppOut); const len = wasm.peek32(pnOut); //log("blob=",wasm.cstrToJs(blob)); const str = wasm.cstrToJs(blob); if( !blob ){ T.assert( null===expect ) .assert( 0===len ); return; } T.assert(len === expect.length, "Lengths don't match: got ["+str +"] expected ["+expect+"]") .assert( str===expect, "String mismatch: got [" +str+"] expected ["+expect+"]"); }; const cmp2 = (expect)=>{ next(); cmp(expect); clearPtrs(); const rc = capi.sqlite3_column_text_v2(q, 1, ppOut, pnOut); T.assert( 0==rc, "expecting column_text_v2() rc 0 but got "+rc ); cmp(expect); }; cmp2('123'); cmp2(null); cmp2('hi world'); cmp2('#*'); cmp2(''); // empty strings are not null const checkRc = (name, descr, rc)=>{ T.assert( capi[name] === rc, descr+": expecting "+name+"("+ capi[name]+") but got "+rc); }; /** The following tests cover the same code paths for both text_v2 and blob_v2, so are elided from the blob_v2 checks in the next test group. */ // This does not set a persistent error flag on q: checkRc('SQLITE_RANGE', "column_text_v2() bad index", capi.sqlite3_column_text_v2(q, 11, ppOut, pnOut) ); checkRc('SQLITE_OK', "column_text_v2() valid index", capi.sqlite3_column_text_v2(q, 1, ppOut, 0)); checkRc('SQLITE_OK', "column null pnOut", capi.sqlite3_column_text_v2(q, 1, ppOut, 0)); /* The MISUSE returns only apply because we build with SQLITE_ENABLE_API_ARMOR. Without API_ARMOR, these result in null pointer dereferences. */ checkRc('SQLITE_MISUSE', "value null ppOut", capi.sqlite3_value_text_v2(sv, 0, pnOut)); checkRc('SQLITE_MISUSE', "value null arg0", capi.sqlite3_value_text_v2(0, ppOut, pnOut)); checkRc('SQLITE_MISUSE', "column null ppOut", capi.sqlite3_column_text_v2(q, 1, 0, pnOut)); }finally{ if( q ) q.finalize(); db.close(); P.restore(stack); } }) //////////////////////////////////////////////////////////////////// .t("value_blob_v2() and friends...", function(sqlite3){ const db = new sqlite3.oo1.DB(); db.exec(["create table t(a,b); insert into t(a,b) ", "values(1,123),(2,null),(3,'hi'),(4,X'23002A'),(5,'')"]); const P = wasm.pstack; const stack = P.pointer; let q; try { let sv, rc; q = db.prepare("select a, b from t order by a"); let [ppOut, pnOut] = P.allocPtr(2); const clearPtrs = ()=>{ wasm.pokePtr(ppOut, 0).poke32(pnOut, 0); }; const next = ()=>{ ++next.n; T.assert( q.step() ); sv = capi.sqlite3_column_value(q, 1); T.assert( sv ); clearPtrs(); T.assert( !wasm.peekPtr(ppOut) ); rc = capi.sqlite3_value_blob_v2(sv, ppOut, pnOut); T.assert( 0==rc, "expecting value_blob_v2() rc 0 but got "+rc ); return sv; }; next.n = 0; const cmp = (byteList)=>{ const blob = wasm.peekPtr(ppOut); const len = wasm.peek32(pnOut); T.assert(len === byteList.length, "Lengths don't match: " +len +" != " + byteList.length) for( let i = 0; i < len; ++i ){ T.assert( byteList[i] === wasm.peek8(blob+i), "mismatch at offset "+i+": "+byteList[i] +"!=="+wasm.peek8(blob+i) ); } }; const cmp2 = (byteList)=>{ next(); cmp(byteList); clearPtrs(); const rc = capi.sqlite3_column_blob_v2(q, 1, ppOut, pnOut); T.assert( 0==rc, "expecting column_blob_v2() rc 0 but got "+rc); cmp(byteList); }; cmp2([49,50,51]); // 123 cmp2([]); // null T.assert( !wasm.peekPtr(ppOut), "Expecting NULL in row "+next.n); cmp2([104,105]); // "hi" cmp2([0x23, 0, 0x2a]); // X'23002A' cmp2([]) /* length-0 blob */; T.assert( wasm.peekPtr(ppOut), "Expecting non-NULL in row "+next.n); /** Tests which cover the same code paths for both text_v2 and blob_v2 are in the previous test group. */ }finally{ if( q ) q.finalize(); db.close(); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5285 5286 5287 5288 5289 5290 5291 | ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. ^The leftmost column of the result set has the index 0. ** ^The number of columns in the result can be determined using ** [sqlite3_column_count()]. ** | < < < < < < < < < < < < < | | | | | 5285 5286 5287 5288 5289 5290 5291 5292 5293 5294 5295 5296 5297 5298 5299 5300 5301 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 | ** to the [prepared statement] that is being evaluated (the [sqlite3_stmt*] ** that was returned from [sqlite3_prepare_v2()] or one of its variants) ** and the second argument is the index of the column for which information ** should be returned. ^The leftmost column of the result set has the index 0. ** ^The number of columns in the result can be determined using ** [sqlite3_column_count()]. ** ** If the SQL statement does not currently point to a valid row, or if the ** column index is out of range, the result is undefined. ** These routines may only be called when the most recent call to ** [sqlite3_step()] has returned [SQLITE_ROW] and neither ** [sqlite3_reset()] nor [sqlite3_finalize()] have been called subsequently. ** If any of these routines are called after [sqlite3_reset()] or ** [sqlite3_finalize()] or after [sqlite3_step()] has returned ** something other than [SQLITE_ROW], the results are undefined. ** If [sqlite3_step()] or [sqlite3_reset()] or [sqlite3_finalize()] ** are called from a different thread while any of these routines ** are pending, then the results are undefined. ** ** The interfaces (_blob, _double, _int, _int64, _text, and _text16) ** each return the value of a result column in a specific data format. If ** the result column is not initially in the requested format (for example, ** if the query returns an integer but the sqlite3_column_text() interface ** is used to extract the value) then an automatic type conversion is performed. ** ** ^The (_blob_v2, _text_v2) interfaces behave like ** sqlite3_value_blob_v2() and sqlite3_value_text_v2(), with one ** exception: they return SQLITE_RANGE if the column index is out of ** bounds. ** ** ^The sqlite3_column_type() routine returns the ** [SQLITE_INTEGER | datatype code] for the initial data type ** of the result column. ^The returned value is one of [SQLITE_INTEGER], ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL]. ** The return value of sqlite3_column_type() can be used to decide which ** of the first six interface should be used to extract the column value. |
︙ | ︙ | |||
5491 5492 5493 5494 5495 5496 5497 | ** other SQLite interface is called on the same [database connection]. ** ** The previous paragraph does not apply to the text_v2 and blob_v2 ** interfaces, which return SQLITE_NOMEM to the client for ** out-of-memory conditions. */ const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); | | | | 5478 5479 5480 5481 5482 5483 5484 5485 5486 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 | ** other SQLite interface is called on the same [database connection]. ** ** The previous paragraph does not apply to the text_v2 and blob_v2 ** interfaces, which return SQLITE_NOMEM to the client for ** out-of-memory conditions. */ const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); int sqlite3_column_blob_v2(sqlite3_stmt*, int iCol, const void **, int*); double sqlite3_column_double(sqlite3_stmt*, int iCol); int sqlite3_column_int(sqlite3_stmt*, int iCol); sqlite3_int64 sqlite3_column_int64(sqlite3_stmt*, int iCol); const unsigned char *sqlite3_column_text(sqlite3_stmt*, int iCol); int sqlite3_column_text_v2(sqlite3_stmt*, int iCol, const unsigned char **, int*); const void *sqlite3_column_text16(sqlite3_stmt*, int iCol); sqlite3_value *sqlite3_column_value(sqlite3_stmt*, int iCol); int sqlite3_column_bytes(sqlite3_stmt*, int iCol); int sqlite3_column_bytes16(sqlite3_stmt*, int iCol); int sqlite3_column_type(sqlite3_stmt*, int iCol); /* |
︙ | ︙ | |||
5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 5960 5961 5962 | ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ ** Other interfaces might change the datatype for an sqlite3_value object. ** For example, if the datatype is initially SQLITE_INTEGER and ** sqlite3_value_text(V) is called to extract a text value for that ** integer, then subsequent calls to sqlite3_value_type(V) might return ** SQLITE_TEXT. Whether or not a persistent internal datatype conversion ** occurs is undefined and may change from one release of SQLite to the next. ** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. | > > > > > > > > > > | 5936 5937 5938 5939 5940 5941 5942 5943 5944 5945 5946 5947 5948 5949 5950 5951 5952 5953 5954 5955 5956 5957 5958 5959 | ** [SQLITE_FLOAT], [SQLITE_TEXT], [SQLITE_BLOB], or [SQLITE_NULL].)^ ** Other interfaces might change the datatype for an sqlite3_value object. ** For example, if the datatype is initially SQLITE_INTEGER and ** sqlite3_value_text(V) is called to extract a text value for that ** integer, then subsequent calls to sqlite3_value_type(V) might return ** SQLITE_TEXT. Whether or not a persistent internal datatype conversion ** occurs is undefined and may change from one release of SQLite to the next. ** ** ^sqlite3_value_blob_v2() and sqlite3_value_text_v2() interfaces ** return their content via their 2nd and 3rd arguments, output ** pointers. They behave the same as their "v1" counterparts with one ** exception: sqlite3_value_blob_v2() resolves length-0 blobs to an ** opaque non-NULL pointer instead of NULL. Their 3rd argument, if not ** NULL, will get the length of the returned blob assigned to it. If ** these functions fail they return non-0 and do not modify their ** output pointers. On success they return 0 and will update their 2nd ** and (if not NULL) 3rd output pointer arguments. ** ** ^(The sqlite3_value_numeric_type() interface attempts to apply ** numeric affinity to the value. This means that an attempt is ** made to convert the value to an integer or floating point. If ** such a conversion is possible without loss of information (in other ** words, if the value is a string that looks like a number) ** then the conversion is performed. Otherwise no conversion occurs. |
︙ | ︙ | |||
5977 5978 5979 5980 5981 5982 5983 | ** ** ^The sqlite3_value_frombind(X) interface returns non-zero if the ** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] ** interfaces. ^If X comes from an SQL literal value, or a table column, ** or an expression, then sqlite3_value_frombind(X) returns zero. ** ** Please pay particular attention to the fact that the pointer returned | | > | | 5974 5975 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 | ** ** ^The sqlite3_value_frombind(X) interface returns non-zero if the ** value X originated from one of the [sqlite3_bind_int|sqlite3_bind()] ** interfaces. ^If X comes from an SQL literal value, or a table column, ** or an expression, then sqlite3_value_frombind(X) returns zero. ** ** Please pay particular attention to the fact that the pointer returned ** from [sqlite3_value_blob()], [sqlite3_value_blob_v2()], ** [sqlite3_value_text()], [sqlite3_value_text_v2()], or ** [sqlite3_value_text16()] can be invalidated by a subsequent call to ** [sqlite3_value_bytes()], [sqlite3_value_bytes16()], [sqlite3_value_text()], ** [sqlite3_value_text_v2()], or [sqlite3_value_text16()]. ** ** These routines must be called from the same thread as ** the SQL function that supplied the [sqlite3_value*] parameters. ** ** As long as the input parameter is correct, these routines can only ** fail if an out-of-memory error occurs during a format conversion. ** Only the following subset of interfaces are subject to out-of-memory |
︙ | ︙ | |||
6014 6015 6016 6017 6018 6019 6020 | ** other SQLite interface is called on the same [database connection]. ** ** The previous paragraph does not apply to the text_v2 and blob_v2 ** interfaces, which return SQLITE_NOMEM to the client for ** out-of-memory conditions. */ const void *sqlite3_value_blob(sqlite3_value*); | | | | 6012 6013 6014 6015 6016 6017 6018 6019 6020 6021 6022 6023 6024 6025 6026 6027 6028 6029 6030 6031 6032 | ** other SQLite interface is called on the same [database connection]. ** ** The previous paragraph does not apply to the text_v2 and blob_v2 ** interfaces, which return SQLITE_NOMEM to the client for ** out-of-memory conditions. */ const void *sqlite3_value_blob(sqlite3_value*); int sqlite3_value_blob_v2(sqlite3_value*, const void **, int*); double sqlite3_value_double(sqlite3_value*); int sqlite3_value_int(sqlite3_value*); sqlite3_int64 sqlite3_value_int64(sqlite3_value*); void *sqlite3_value_pointer(sqlite3_value*, const char*); const unsigned char *sqlite3_value_text(sqlite3_value*); int sqlite3_value_text_v2(sqlite3_value*, const unsigned char **, int*); const void *sqlite3_value_text16(sqlite3_value*); const void *sqlite3_value_text16le(sqlite3_value*); const void *sqlite3_value_text16be(sqlite3_value*); int sqlite3_value_bytes(sqlite3_value*); int sqlite3_value_bytes16(sqlite3_value*); int sqlite3_value_type(sqlite3_value*); int sqlite3_value_numeric_type(sqlite3_value*); |
︙ | ︙ |
Changes to src/sqliteInt.h.
︙ | ︙ | |||
5395 5396 5397 5398 5399 5400 5401 | void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif u8 sqlite3GetBoolean(const char *z,u8); const void *sqlite3ValueText(sqlite3_value*, u8); | | | 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 5407 5408 5409 | void sqlite3FileSuffix3(const char*, char*); #else # define sqlite3FileSuffix3(X,Y) #endif u8 sqlite3GetBoolean(const char *z,u8); const void *sqlite3ValueText(sqlite3_value*, u8); int sqlite3ValueTextV2(sqlite3_value*, u8, const void **, int*); int sqlite3ValueIsOfClass(const sqlite3_value*, void(*)(void*)); int sqlite3ValueBytes(sqlite3_value*, u8); void sqlite3ValueSetStr(sqlite3_value*, int, const void *,u8, void(*)(void*)); void sqlite3ValueSetNull(sqlite3_value*); void sqlite3ValueFree(sqlite3_value*); |
︙ | ︙ |
Changes to src/test1.c.
︙ | ︙ | |||
5630 5631 5632 5633 5634 5635 5636 | Tcl_WrongNumArgs(interp, 1, objv, "STMT column"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | | | 5630 5631 5632 5633 5634 5635 5636 5637 5638 5639 5640 5641 5642 5643 5644 | Tcl_WrongNumArgs(interp, 1, objv, "STMT column"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; rc = sqlite3_column_blob_v2(pStmt, col, &pBlob, &len); if( rc ) return TCL_ERROR; Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len)); return TCL_OK; } /* ** Usage: sqlite3_column_double STMT column |
︙ | ︙ | |||
5751 5752 5753 5754 5755 5756 5757 | if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT column"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; | | | 5751 5752 5753 5754 5755 5756 5757 5758 5759 5760 5761 5762 5763 5764 5765 | if( objc!=3 ){ Tcl_WrongNumArgs(interp, 1, objv, "STMT column"); return TCL_ERROR; } if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR; if( sqlite3_column_text_v2(pStmt, col, &zRet, &len) ){ return TCL_ERROR; } if( zRet ){ Tcl_SetResult(interp, (char *)zRet, 0); } return TCL_OK; } |
︙ | ︙ |
Changes to src/vdbeapi.c.
︙ | ︙ | |||
187 188 189 190 191 192 193 | } p->flags |= MEM_Blob; return p->n ? p->z : 0; }else{ return sqlite3_value_text(pVal); } } | | | > | < | < | 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 | } p->flags |= MEM_Blob; return p->n ? p->z : 0; }else{ return sqlite3_value_text(pVal); } } int sqlite3_value_blob_v2(sqlite3_value *pVal, const void **pOut, int *pnOut){ static const unsigned char aZeroLength[] = {0,0}; Mem *p = (Mem*)pVal; #ifdef SQLITE_ENABLE_API_ARMOR if( pVal==0 || pOut==0 ) return SQLITE_MISUSE_BKPT; #endif if( p->flags & (MEM_Blob|MEM_Str) ){ if( ExpandBlob(p)!=SQLITE_OK ){ assert( p->flags==MEM_Null && p->z==0 ); return SQLITE_NOMEM_BKPT; } p->flags |= MEM_Blob; *pOut = p->n ? p->z : (const void *)&aZeroLength[0]; if( pnOut ) *pnOut = p->n; return 0; } return sqlite3_value_text_v2(pVal, (const unsigned char **)pOut, pnOut); } int sqlite3_value_bytes(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF8); } int sqlite3_value_bytes16(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); } |
︙ | ︙ | |||
242 243 244 245 246 247 248 | }else{ return 0; } } const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } | | < | | | 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 | }else{ return 0; } } const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const unsigned char *)sqlite3ValueText(pVal, SQLITE_UTF8); } int sqlite3_value_text_v2(sqlite3_value *pVal, const unsigned char **pOut, int *pnOut){ int n = 0; #ifdef SQLITE_ENABLE_API_ARMOR if( pVal==0 || pOut==0 ) return SQLITE_MISUSE_BKPT; #endif return sqlite3ValueTextV2(pVal, SQLITE_UTF8, (const void **)pOut, pnOut ? pnOut : &n); } #ifndef SQLITE_OMIT_UTF16 const void *sqlite3_value_text16(sqlite3_value* pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16NATIVE); } const void *sqlite3_value_text16be(sqlite3_value *pVal){ return sqlite3ValueText(pVal, SQLITE_UTF16BE); |
︙ | ︙ | |||
1366 1367 1368 1369 1370 1371 1372 | ** ** If bBlob is true, sqlite3_value_blob_v2() is used for the ** extraction, else sqlite3_value_text_v2() is used. ** ** This is expected to only be called by sqlite3_column_blob_v2(), ** sqlite3_column_text_v2(), or APIs with similar semantics. ** | | | | | | 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 | ** ** If bBlob is true, sqlite3_value_blob_v2() is used for the ** extraction, else sqlite3_value_text_v2() is used. ** ** This is expected to only be called by sqlite3_column_blob_v2(), ** sqlite3_column_text_v2(), or APIs with similar semantics. ** ** Design notes based on /chat discussions: ** ** sqlite3_column_text/blob_v2() can report SQLITE_RANGE and ** SQLITE_MISUSE, but must not perist those errors and must not take ** prior error state into account (e.g. do not propagate a ** SQLITE_RANGE error across calls). They unavoidably persist ** SQLITE_NOMEM errors via deeper APIs. This routine specifically does ** not call columnMallocFailure() to avoid calling sqlite3ApiExit(). */ static int columnMemV2(sqlite3_stmt *pStmt, int iCol, int bBlob, const void **pOut, int * pnOut){ int rc = 0; Vdbe * const pVm = (Vdbe*)pStmt; #ifdef SQLITE_ENABLE_API_ARMOR if( pVm==0 || pOut==0 ) return SQLITE_MISUSE_BKPT; #endif assert( pVm->db ); sqlite3_mutex_enter(pVm->db->mutex); if( pVm->pResultRow!=0 && iCol<pVm->nResColumn && iCol>=0 ){ Mem * const pMem = &pVm->pResultRow[iCol]; rc = bBlob ? sqlite3_value_blob_v2(pMem, pOut, pnOut) : sqlite3_value_text_v2(pMem, (const unsigned char **)pOut, pnOut); }else{ rc = pVm->pResultRow==0 ? SQLITE_MISUSE_BKPT : SQLITE_RANGE; } sqlite3_mutex_leave(pVm->db->mutex); return rc; } |
︙ | ︙ | |||
1447 1448 1449 1450 1451 1452 1453 | ** need to call malloc() to expand the result of a zeroblob() ** expression. */ columnMallocFailure(pStmt); return val; } int sqlite3_column_blob_v2(sqlite3_stmt *pStmt, int iCol, | | | | 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 | ** need to call malloc() to expand the result of a zeroblob() ** expression. */ columnMallocFailure(pStmt); return val; } int sqlite3_column_blob_v2(sqlite3_stmt *pStmt, int iCol, const void **pOut, int *pnOut){ return columnMemV2(pStmt, iCol, 1, pOut, pnOut); } int sqlite3_column_bytes(sqlite3_stmt *pStmt, int i){ int val = sqlite3_value_bytes( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } int sqlite3_column_bytes16(sqlite3_stmt *pStmt, int i){ |
︙ | ︙ | |||
1481 1482 1483 1484 1485 1486 1487 | } const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } int sqlite3_column_text_v2(sqlite3_stmt *pStmt, int iCol, | | < | | 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 | } const unsigned char *sqlite3_column_text(sqlite3_stmt *pStmt, int i){ const unsigned char *val = sqlite3_value_text( columnMem(pStmt,i) ); columnMallocFailure(pStmt); return val; } int sqlite3_column_text_v2(sqlite3_stmt *pStmt, int iCol, const unsigned char **pOut, int *pnOut){ return columnMemV2(pStmt, iCol, 0, (const void **)pOut, pnOut); } sqlite3_value *sqlite3_column_value(sqlite3_stmt *pStmt, int i){ Mem *pOut = columnMem(pStmt, i); if( pOut->flags&MEM_Static ){ pOut->flags &= ~MEM_Static; pOut->flags |= MEM_Ephem; } |
︙ | ︙ |
Changes to src/vdbemem.c.
︙ | ︙ | |||
1356 1357 1358 1359 1360 1361 1362 | } } /* ** This works like valueToText() but returns its result using ** different semantics. On success, return 0, set *pOut to a ** zero-terminated version of that string, and set *pnOut (which must | | < | | < | 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377 1378 1379 1380 | } } /* ** This works like valueToText() but returns its result using ** different semantics. On success, return 0, set *pOut to a ** zero-terminated version of that string, and set *pnOut (which must ** not be NULL to the string-length of that memory. ** ** On error, return non-0 and do not modify pOut or pnOut. ** ** Maintenance note: this is almost a copy/paste clone of ** valueToText(), but the two should probably not be consolidated. The ** initial version of this API did so in [730c6a623e29b59b] and the ** CPU cycles doubled. */ static SQLITE_NOINLINE int valueToTextV2(sqlite3_value* pVal, u8 enc, const void **pOut, int *pnOut){ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( (pVal->flags & (MEM_Null))==0 ); assert( pOut!=0 ); assert( pnOut!=0 ); |
︙ | ︙ | |||
1403 1404 1405 1406 1407 1408 1409 | } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); *pOut = pVal->z; *pnOut = pVal->n; | < | 1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | } assert(pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) || pVal->db==0 || pVal->db->mallocFailed ); if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); *pOut = pVal->z; *pnOut = pVal->n; return 0; } return (pVal->db && pVal->db->mallocFailed) ? SQLITE_NOMEM_BKPT : SQLITE_ERROR; } |
︙ | ︙ | |||
1441 1442 1443 1444 1445 1446 1447 | } /* This works similarly to sqlite3ValueText() but returns its result ** with different semantics. ** ** On success, returns 0, sets *pOut to the underlying value (or NULL ** in the case of NULL), and sets *pnOut to the memory's usable | < | < | < | < < | | 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 | } /* This works similarly to sqlite3ValueText() but returns its result ** with different semantics. ** ** On success, returns 0, sets *pOut to the underlying value (or NULL ** in the case of NULL), and sets *pnOut to the memory's usable ** length. On error, neither *pOut nor *pnOut are modified. ** ** Results are undefined if pVal, pOut, or pnOut are NULL. */ int sqlite3ValueTextV2(sqlite3_value* pVal, u8 enc, const void **pOut, int *pnOut){ /*if( !pVal ) return SQLITE_MISUSE_BKPT;*/ assert( pVal!=0 ); assert( pVal->db==0 || sqlite3_mutex_held(pVal->db->mutex) ); assert( (enc&3)==(enc&~SQLITE_UTF16_ALIGNED) ); assert( !sqlite3VdbeMemIsRowSet(pVal) ); assert( pOut!=0 ); assert( pnOut!=0 ); if( (pVal->flags&(MEM_Str|MEM_Term))==(MEM_Str|MEM_Term) && pVal->enc==enc ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); *pOut = pVal->z; *pnOut = pVal->n; return 0; } if( pVal->flags&MEM_Null ){ *pOut = 0; *pnOut = 0; return 0; } return valueToTextV2(pVal, enc, pOut, pnOut); } /* Return true if sqlit3_value object pVal is a string or blob value ** that uses the destructor specified in the second argument. ** ** TODO: Maybe someday promote this interface into a published API so ** that third-party extensions can get access to it? |
︙ | ︙ |