Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Experimentally add another output pointer to the text/blob_v2() family which gets the sqlite3_value_type() assigned to it if it's not NULL, based on feedback in the forum. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | column-text-blob-v2 |
Files: | files | file ages | folders |
SHA3-256: |
4aab781d2abc64a39c53acd0faf6d60b |
User & Date: | stephan 2025-07-01 16:38:58.203 |
Context
2025-07-01
| ||
17:38 | Random JS cleanups and docs. (check-in: 5a2734bbf8 user: stephan tags: column-text-blob-v2) | |
16:38 | Experimentally add another output pointer to the text/blob_v2() family which gets the sqlite3_value_type() assigned to it if it's not NULL, based on feedback in the forum. (check-in: 4aab781d2a user: stephan tags: column-text-blob-v2) | |
14:44 | Simplify the column_text/blob_v2() JS tests a bit and correct the text_v2() tests to call into both the column and value variants. (check-in: d5cb808043 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 3497 3498 3499 3500 3501 3502 3503 3504 3505 | "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, pType] = P.allocPtr(3); const clearPtrs = ()=>{ wasm.pokePtr(ppOut, 0); wasm.poke32(pnOut, 0); wasm.poke32(pType, 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, pType); T.assert( 0===rc ); return sv; }; const cmp = function(type,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 = (type,expect)=>{ next(); cmp(type,expect); clearPtrs(); const rc = capi.sqlite3_column_text_v2(q, 1, ppOut, pnOut, pType); T.assert( 0==rc, "expecting column_text_v2() rc 0 but got "+rc ); cmp(type,expect); }; cmp2(capi.SQLITE_INTEGER,'123'); cmp2(capi.SQLITE_NULL,null); cmp2(capi.SQLITE_TEXT,'hi world'); cmp2(capi.SQLITE_BLOB, '#*'); cmp2(capi.SQLITE_TEXT, ''); // 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, 0) ); checkRc('SQLITE_OK', "column_text_v2() valid index", capi.sqlite3_column_text_v2(q, 1, ppOut, 0, 0)); checkRc('SQLITE_OK', "column null pnOut", capi.sqlite3_column_text_v2(q, 1, ppOut, 0, 0)); /* Some of the following only applies because we build with SQLITE_ENABLE_API_ARMOR. */ checkRc('SQLITE_MISUSE', "value null ppOut", capi.sqlite3_value_text_v2(sv, 0, pnOut, 0)); checkRc('SQLITE_MISUSE', "value null arg0", capi.sqlite3_value_text_v2(0, ppOut, pnOut, 0)); checkRc('SQLITE_MISUSE', "column null ppOut", capi.sqlite3_column_text_v2(q, 1, 0, pnOut, 0)); /* But a 0 pnOut is always okay. */ checkRc('SQLITE_OK', "value null pnOut", capi.sqlite3_value_text_v2(sv, ppOut, 0, 0)); }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, pType] = P.allocPtr(3); const clearPtrs = ()=>{ wasm.pokePtr(ppOut, 0); wasm.poke32(pnOut, 0); wasm.poke32(pType, 0); }; const next = ()=>{ T.assert( q.step() ); sv = capi.sqlite3_column_value(q, 1); T.assert( sv ); clearPtrs(); rc = capi.sqlite3_value_blob_v2(sv, ppOut, pnOut, pType); T.assert( 0==rc, "expecting value_blob_v2() rc 0 but got "+rc ); return sv; }; const cmp = (type,byteList)=>{ const blob = wasm.peekPtr(ppOut); const len = wasm.peek32(pnOut); //log("blob=",wasm.cstrToJs(blob)); T.assert(len === byteList.length, "Lengths don't match") T.assert( len ? !!blob : !blob, "Expecting len=non-0/blob=non-null or len=0/blob=null. "+ "Got len="+len+" blob=@"+blob ); T.assert( type === wasm.peek32(pType), "Expecting value_blob_v2 type "+type+" but got " +wasm.peek32(pType)+". Value="+wasm.cstrToJs(blob)); 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 = (type,byteList)=>{ next(); cmp(type,byteList); clearPtrs(); const rc = capi.sqlite3_column_blob_v2(q, 1, ppOut, pnOut, pType); T.assert( 0==rc, "expecting column_blob_v2() rc 0 but got "+rc); cmp(type,byteList); }; cmp2(capi.SQLITE_INTEGER, [49,50,51]); // 123 cmp2(capi.SQLITE_NULL, []); // null cmp2(capi.SQLITE_TEXT, [104,105]); // "hi" cmp2(capi.SQLITE_BLOB, [0x23, 0, 0x2a]); // X'23002A' cmp2(capi.SQLITE_TEXT, []) /* length-0 non-NULL blobs are NULL but this one has type TEXT */; /** 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(); P.restore(stack); |
︙ | ︙ |
Changes to src/sqlite.h.in.
︙ | ︙ | |||
5461 5462 5463 5464 5465 5466 5467 | ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); | | | | 5461 5462 5463 5464 5465 5466 5467 5468 5469 5470 5471 5472 5473 5474 5475 5476 5477 5478 5479 5480 | ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ const void *sqlite3_column_blob(sqlite3_stmt*, int iCol); int sqlite3_column_blob_v2(sqlite3_stmt*, int iCol, const void **, int*, 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*, 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); /* |
︙ | ︙ | |||
5976 5977 5978 5979 5980 5981 5982 | ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ const void *sqlite3_value_blob(sqlite3_value*); | | | | 5976 5977 5978 5979 5980 5981 5982 5983 5984 5985 5986 5987 5988 5989 5990 5991 5992 5993 5994 5995 5996 | ** routines is the same as if the column had contained an SQL NULL value. ** Valid SQL NULL returns can be distinguished from out-of-memory errors ** by invoking the [sqlite3_errcode()] immediately after the suspect ** return value is obtained and before any ** other SQLite interface is called on the same [database connection]. */ const void *sqlite3_value_blob(sqlite3_value*); int sqlite3_value_blob_v2(sqlite3_value*, const void **, int*, 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*, 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*); 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/vdbeapi.c.
︙ | ︙ | |||
188 189 190 191 192 193 194 | 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, | | > | | 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 | 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, int *pType){ 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 : 0; if( pnOut ) *pnOut = p->n; if( pType ) *pType = sqlite3_value_type(pVal); return 0; }else{ return sqlite3_value_text_v2(pVal, (const unsigned char **)pOut, pnOut, pType); } } int sqlite3_value_bytes(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF8); } int sqlite3_value_bytes16(sqlite3_value *pVal){ return sqlite3ValueBytes(pVal, SQLITE_UTF16NATIVE); |
︙ | ︙ | |||
246 247 248 249 250 251 252 | } } 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, | | < < | < < | | > | 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 | } } 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 *pType){ int n = 0; return (pVal && pOut) ? sqlite3ValueTextV2(pVal, SQLITE_UTF8, (const void **)pOut, pnOut ? pnOut : &n, pType) : SQLITE_MISUSE_BKPT; } #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); |
︙ | ︙ | |||
1380 1381 1382 1383 1384 1385 1386 | ** 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, | | | | | 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 1403 1404 | ** 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 *pType){ int rc = 0; Vdbe * const pVm = (Vdbe*)pStmt; if( pVm==0 || pOut==0 ) return SQLITE_MISUSE_BKPT; 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, pType) : sqlite3_value_text_v2(pMem, (const unsigned char **)pOut, pnOut, pType); }else{ rc = pVm->pResultRow==0 ? SQLITE_MISUSE_BKPT : SQLITE_RANGE; } sqlite3_mutex_leave(pVm->db->mutex); return rc; } |
︙ | ︙ | |||
1449 1450 1451 1452 1453 1454 1455 | ** 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, | | | | 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 | ** 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, int *pType){ return columnMemV2(pStmt, iCol, 1, pOut, pnOut, pType); } 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){ |
︙ | ︙ | |||
1483 1484 1485 1486 1487 1488 1489 | } 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, | | | | | 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 | } 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, int *pType){ return columnMemV2(pStmt, iCol, 0, (const void **)pOut, pnOut, pType); } 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 1381 1382 | } } /* ** 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. If pType is not ** NULL, it will be set to the sqlite3_value_type() of pVal. ** ** On error, return non-0 and do not modify pOut, pnOut, or pType. ** ** 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, int *pType){ 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 ); |
︙ | ︙ | |||
1401 1402 1403 1404 1405 1406 1407 1408 1409 1410 1411 1412 1413 1414 | return SQLITE_NOMEM_BKPT; } #endif 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; } | > | 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 | return SQLITE_NOMEM_BKPT; } #endif if( pVal->enc==(enc & ~SQLITE_UTF16_ALIGNED) ){ assert( sqlite3VdbeMemValidStrRep(pVal) ); *pOut = pVal->z; *pnOut = pVal->n; if( pType ) *pType = sqlite3_value_type(pVal); return 0; } return (pVal->db && pVal->db->mallocFailed) ? SQLITE_NOMEM_BKPT : SQLITE_ERROR; } |
︙ | ︙ | |||
1438 1439 1440 1441 1442 1443 1444 | } /* 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 | > | > < < | < | | | | > > > | | 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 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 | } /* 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. If *pType is not NULL, it is set to the ** sqlite3_value_type() of pVal. On error, neither *pOut nor *pnOut ** nor *pType are modified. ** ** Results are undefined if pVal, pOut, or pnOut are NULL. pType may ** be NULL. */ int sqlite3ValueTextV2(sqlite3_value* pVal, u8 enc, const void **pOut, int *pnOut, int *pType){ /*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; if( pType ) *pType = sqlite3_value_type( pVal ); return 0; } if( pVal->flags&MEM_Null ){ *pOut = 0; *pnOut = 0; if( pType ) *pType = sqlite3_value_type( pVal ); return 0; } return valueToTextV2(pVal, enc, pOut, pnOut, pType); } /* 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? |
︙ | ︙ |