1
0
mirror of https://github.com/sqlite/sqlite.git synced 2025-08-10 01:02:56 +03:00

Make sure sqlite3_value_bytes() does not reformat the content after a

call to sqlite3_value_blob().  Add documentation to explain this hazard.
Add many new tests.  Ticket #2321. (CVS 3880)

FossilOrigin-Name: e92bd97a3726bbb7978489e2994747127c4aefcf
This commit is contained in:
drh
2007-04-27 17:16:20 +00:00
parent ba6d351486
commit 9310ef23e2
8 changed files with 430 additions and 35 deletions

View File

@@ -1,5 +1,5 @@
C Extra\stests\sfor\sincremental\svacuum.\s(CVS\s3879)
D 2007-04-27T07:55:38
C Make\ssure\ssqlite3_value_bytes()\sdoes\snot\sreformat\sthe\scontent\safter\sa\ncall\sto\ssqlite3_value_blob().\s\sAdd\sdocumentation\sto\sexplain\sthis\shazard.\nAdd\smany\snew\stests.\s\sTicket\s#2321.\s(CVS\s3880)
D 2007-04-27T17:16:20
F Makefile.in 8cab54f7c9f5af8f22fd97ddf1ecfd1e1860de62
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -68,7 +68,7 @@ F src/date.c 94a6777df13d2aaacd19de080d9e8d3444364133
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
F src/expr.c 2f0f9f89efe9170e5e6ca5d5e93a9d5896fff5ac
F src/func.c b989aa0ecc66a6d48b46f297299d52f12d84bce9
F src/func.c 89d8547a9cb1c5ad8e0b86b3d74de56e5254254b
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
F src/insert.c 413cc06990cb3c401e64e596776c1e43934f8841
@@ -102,7 +102,7 @@ F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
F src/sqliteInt.h 0b14d0eae083aafca0562d2261a404e5e5abc5f0
F src/table.c 6d0da66dde26ee75614ed8f584a1996467088d06
F src/tclsqlite.c ec69eb9ad56d03fbf7570ca1ca5ea947d1ec4b6f
F src/test1.c 53b7eb5cba0012f592b5860f6ad3b5a3f887eb1e
F src/test1.c f1271d41719d05348e6dc39722260e17b8d7ddc1
F src/test2.c 24458b17ab2f3c90cbc1c8446bd7ffe69be62f88
F src/test3.c 65f92247cf8592854e9bf5115b3fb711f8b33280
F src/test4.c 8b784cd82de158a2317cb4ac4bc86f91ad315e25
@@ -128,7 +128,7 @@ F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
F src/vdbe.c a3cf3792fdbd382f756eb7eb50006b2f3f8d4283
F src/vdbe.h 0025259af1939fb264a545816c69e4b5b8d52691
F src/vdbeInt.h 4b19fd8febad3fd14c4c97adaefc06754d323132
F src/vdbeapi.c 245263aa2d70d87b1201753cddc881996f219843
F src/vdbeapi.c 37fc2818bec64b361af73f3935699107bab0e625
F src/vdbeaux.c ef59545f53f90394283f2fd003375d3ebbf0bd6e
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
F src/vdbemem.c 981a113405bd9b80aeb71fe246a2f01708e8a8f7
@@ -297,6 +297,7 @@ F test/pagesize.test e0a8b3fe80f8b8e808d94a00734c7a18c76c407e
F test/pragma.test fecb7085f58d9fb5172a5c0b63fd3b25c7bfb414
F test/printf.test 483b9fe75ffae1fb27328bdce5560b452ba83577
F test/progress.test 8b22b4974b0a95272566385f8cb8c341c7130df8 x
F test/ptrchng.test 1c712dd6516e1377471744fa765e41c79a357da6
F test/quick.test 8e7ffe36a1c920cdcce5d641646abde2dafd764b
F test/quote.test 215897dbe8de1a6f701265836d6601cc6ed103e6
F test/rdonly.test b34db316525440d3b42c32e83942c02c37d28ef0
@@ -418,8 +419,8 @@ F www/arch2b.fig d22a2c9642d584b89d4088b1e51e2bb0f7c04bed
F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0
F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06
F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e
F www/capi3.tcl 7a7cc225fe02eb7ab861a6019b08baa0014409e1
F www/capi3ref.tcl 80178d2697e97236c208a2a6a507e82d121acc71
F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716
F www/capi3ref.tcl 0d742d6bd59bc51bbb4be014e7ea47e97786d318
F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58
F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e
F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084
@@ -463,7 +464,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
P 4d4180d6474d8d74460fb9333580b9b60c89f353
R cb55629cd4ed6b5c3bd0582e6bc3a138
U danielk1977
Z f3e9134088bb4d98704fded975f43270
P 40ba6493e9e8ba135552a2a0943ab499713ac001
R ae6e82023418585801b4f01168703216
U drh
Z e4fdef4577a3571a48a38a52b01018a7

View File

@@ -1 +1 @@
40ba6493e9e8ba135552a2a0943ab499713ac001
e92bd97a3726bbb7978489e2994747127c4aefcf

View File

@@ -16,7 +16,7 @@
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
** All other code has file scope.
**
** $Id: func.c,v 1.141 2007/04/27 01:18:03 drh Exp $
** $Id: func.c,v 1.142 2007/04/27 17:16:20 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>
@@ -215,11 +215,12 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
char *z1;
const char *z2;
int i;
int i, n;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
n = sqlite3_value_bytes(argv[0]);
z2 = (char*)sqlite3_value_text(argv[0]);
if( z2 ){
z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
z1 = sqlite3_malloc(n+1);
if( z1 ){
strcpy(z1, z2);
for(i=0; z1[i]; i++){
@@ -232,11 +233,12 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
char *z1;
const char *z2;
int i;
int i, n;
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
n = sqlite3_value_bytes(argv[0]);
z2 = (char*)sqlite3_value_text(argv[0]);
if( z2 ){
z1 = sqlite3_malloc(sqlite3_value_bytes(argv[0])+1);
z1 = sqlite3_malloc(n+1);
if( z1 ){
strcpy(z1, z2);
for(i=0; z1[i]; i++){
@@ -703,15 +705,15 @@ static void replaceFunc(
int i, j; /* Loop counters */
assert( argc==3 );
nStr = sqlite3_value_bytes(argv[0]);
zStr = sqlite3_value_text(argv[0]);
if( zStr==0 ) return;
nStr = sqlite3_value_bytes(argv[0]);
nPattern = sqlite3_value_bytes(argv[1]);
zPattern = sqlite3_value_text(argv[1]);
if( zPattern==0 || zPattern[0]==0 ) return;
nPattern = sqlite3_value_bytes(argv[1]);
nRep = sqlite3_value_bytes(argv[2]);
zRep = sqlite3_value_text(argv[2]);
if( zRep==0 ) return;
nRep = sqlite3_value_bytes(argv[2]);
if( nPattern>=nRep ){
nOut = nStr;
}else{
@@ -754,9 +756,9 @@ static void trimFunc(
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
return;
}
nIn = sqlite3_value_bytes(argv[0]);
zIn = sqlite3_value_text(argv[0]);
if( zIn==0 ) return;
nIn = sqlite3_value_bytes(argv[0]);
if( argc==1 ){
static const unsigned char zSpace[] = " ";
zCharSet = zSpace;

View File

@@ -13,7 +13,7 @@
** is not included in the SQLite library. It is used for automated
** testing of the SQLite library.
**
** $Id: test1.c,v 1.239 2007/04/23 23:56:31 drh Exp $
** $Id: test1.c,v 1.240 2007/04/27 17:16:20 drh Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@@ -557,8 +557,9 @@ static void t1_ifnullFunc(
int i;
for(i=0; i<argc; i++){
if( SQLITE_NULL!=sqlite3_value_type(argv[i]) ){
int n = sqlite3_value_bytes(argv[i]);
sqlite3_result_text(context, (char*)sqlite3_value_text(argv[i]),
sqlite3_value_bytes(argv[i]), SQLITE_TRANSIENT);
n, SQLITE_TRANSIENT);
break;
}
}
@@ -707,6 +708,81 @@ static void tkt2213Function(
}
}
/*
** The following SQL function takes 4 arguments. The 2nd and
** 4th argument must be one of these strings: 'text', 'text16',
** or 'blob' corresponding to API functions
**
** sqlite3_value_text()
** sqlite3_value_text16()
** sqlite3_value_blob()
**
** The third argument is a string, either 'bytes' or 'bytes16' or 'noop',
** corresponding to APIs:
**
** sqlite3_value_bytes()
** sqlite3_value_bytes16()
** noop
**
** The APIs designated by the 2nd through 4th arguments are applied
** to the first argument in order. If the pointers returned by the
** second and fourth are different, this routine returns 1. Otherwise,
** this routine returns 0.
**
** This function is used to test to see when returned pointers from
** the _text(), _text16() and _blob() APIs become invalidated.
*/
static void ptrChngFunction(
sqlite3_context *context,
int argc,
sqlite3_value **argv
){
const void *p1, *p2;
const char *zCmd;
if( argc!=4 ) return;
zCmd = (const char*)sqlite3_value_text(argv[1]);
if( zCmd==0 ) return;
if( strcmp(zCmd,"text")==0 ){
p1 = (const void*)sqlite3_value_text(argv[0]);
#ifndef SQLITE_OMIT_UTF16
}else if( strcmp(zCmd, "text16")==0 ){
p1 = (const void*)sqlite3_value_text16(argv[0]);
#endif
}else if( strcmp(zCmd, "blob")==0 ){
p1 = (const void*)sqlite3_value_blob(argv[0]);
}else{
return;
}
zCmd = (const char*)sqlite3_value_text(argv[2]);
if( zCmd==0 ) return;
if( strcmp(zCmd,"bytes")==0 ){
sqlite3_value_bytes(argv[0]);
#ifndef SQLITE_OMIT_UTF16
}else if( strcmp(zCmd, "bytes16")==0 ){
sqlite3_value_bytes16(argv[0]);
#endif
}else if( strcmp(zCmd, "noop")==0 ){
/* do nothing */
}else{
return;
}
zCmd = (const char*)sqlite3_value_text(argv[3]);
if( zCmd==0 ) return;
if( strcmp(zCmd,"text")==0 ){
p2 = (const void*)sqlite3_value_text(argv[0]);
#ifndef SQLITE_OMIT_UTF16
}else if( strcmp(zCmd, "text16")==0 ){
p2 = (const void*)sqlite3_value_text16(argv[0]);
#endif
}else if( strcmp(zCmd, "blob")==0 ){
p2 = (const void*)sqlite3_value_blob(argv[0]);
}else{
return;
}
sqlite3_result_int(context, p1!=p2);
}
/*
** Usage: sqlite_test_create_function DB
**
@@ -754,6 +830,10 @@ static int test_create_function(
rc = sqlite3_create_function(db, "tkt2213func", 1, SQLITE_ANY, 0,
tkt2213Function, 0, 0);
}
if( rc==SQLITE_OK ){
rc = sqlite3_create_function(db, "pointer_change", 4, SQLITE_ANY, 0,
ptrChngFunction, 0, 0);
}
#ifndef SQLITE_OMIT_UTF16
/* Use the sqlite3_create_function16() API here. Mainly for fun, but also
@@ -3129,8 +3209,8 @@ static int test_column_blob(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
if( Tcl_GetIntFromObj(interp, objv[2], &col) ) return TCL_ERROR;
pBlob = sqlite3_column_blob(pStmt, col);
len = sqlite3_column_bytes(pStmt, col);
pBlob = sqlite3_column_blob(pStmt, col);
Tcl_SetObjResult(interp, Tcl_NewByteArrayObj(pBlob, len));
return TCL_OK;
}

View File

@@ -37,6 +37,9 @@ int sqlite3_expired(sqlite3_stmt *pStmt){
const void *sqlite3_value_blob(sqlite3_value *pVal){
Mem *p = (Mem*)pVal;
if( p->flags & (MEM_Blob|MEM_Str) ){
if( (p->flags & MEM_Term)==0 ){
p->flags &= ~MEM_Str;
}
return p->z;
}else{
return sqlite3_value_text(pVal);

217
test/ptrchng.test Normal file
View File

@@ -0,0 +1,217 @@
# 2007 April 27
#
# 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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# The focus of the tests in this file are to verify that the
# underlying TEXT or BLOB representation of an sqlite3_value
# changes appropriately when APIs from the following set are
# called:
#
# sqlite3_value_text()
# sqlite3_value_text16()
# sqlite3_value_blob()
# sqlite3_value_bytes()
# sqlite3_value_bytes16()
#
# $Id: ptrchng.test,v 1.1 2007/04/27 17:16:22 drh Exp $
set testdir [file dirname $argv0]
source $testdir/tester.tcl
# Register the "pointer_change" SQL function.
#
sqlite3_create_function db
do_test ptrchng-1.1 {
execsql {
CREATE TABLE t1(x INTEGER PRIMARY KEY, y BLOB);
INSERT INTO t1 VALUES(1, 'abc');
INSERT INTO t1 VALUES(2,
'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ01234356789');
INSERT INTO t1 VALUES(3, x'626c6f62');
INSERT INTO t1 VALUES(4,
x'000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f2021222324'
);
SELECT count(*) FROM t1;
}
} {4}
# For the short entries that fit in the Mem.zBuf[], the pointer should
# never change regardless of what type conversions occur.
#
do_test ptrchng-2.1 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=1
}
} {0}
do_test ptrchng-2.2 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=1
}
} {0}
ifcapable utf16 {
do_test ptrchng-2.3 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=1
}
} {0}
do_test ptrchng-2.4 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=1
}
} {0}
do_test ptrchng-2.5 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=1
}
} {0}
do_test ptrchng-2.6 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=1
}
} {0}
}
do_test ptrchng-2.11 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=3
}
} {0}
do_test ptrchng-2.12 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=3
}
} {0}
ifcapable utf16 {
do_test ptrchng-2.13 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=3
}
} {0}
do_test ptrchng-2.14 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=3
}
} {0}
do_test ptrchng-2.15 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=3
}
} {0}
do_test ptrchng-2.16 {
btree_breakpoint
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=3
}
} {0}
}
# For the long entries that do not fit in the Mem.zBuf[], the pointer
# should change sometimes.
#
do_test ptrchng-3.1 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=2
}
} {0}
do_test ptrchng-3.2 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=2
}
} {0}
ifcapable utf16 {
do_test ptrchng-3.3 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=2
}
} {1}
do_test ptrchng-3.4 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=2
}
} {1}
do_test ptrchng-3.5 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=2
}
} {0}
do_test ptrchng-3.6 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=2
}
} {1}
}
do_test ptrchng-3.11 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'blob') FROM t1 WHERE x=4
}
} {0}
do_test ptrchng-3.12 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text') FROM t1 WHERE x=4
}
} {0}
ifcapable utf16 {
do_test ptrchng-3.13 {
execsql {
SELECT pointer_change(y, 'text', 'noop', 'text16') FROM t1 WHERE x=4
}
} {1}
do_test ptrchng-3.14 {
execsql {
SELECT pointer_change(y, 'blob', 'noop', 'text16') FROM t1 WHERE x=4
}
} {1}
do_test ptrchng-3.15 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1 WHERE x=4
}
} {0}
do_test ptrchng-3.16 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'text') FROM t1 WHERE x=4
}
} {1}
}
# A call to _bytes() should never reformat a _text() or _blob().
#
do_test ptrchng-4.1 {
execsql {
SELECT pointer_change(y, 'text', 'bytes', 'text') FROM t1
}
} {0 0 0 0}
do_test ptrchng-4.2 {
execsql {
SELECT pointer_change(y, 'blob', 'bytes', 'blob') FROM t1
}
} {0 0 0 0}
# A call to _blob() should never trigger a reformat
#
do_test ptrchng-5.1 {
execsql {
SELECT pointer_change(y, 'text', 'bytes', 'blob') FROM t1
}
} {0 0 0 0}
ifcapable utf16 {
do_test ptrchng-5.2 {
execsql {
SELECT pointer_change(y, 'text16', 'noop', 'blob') FROM t1
}
} {0 0 0 0}
do_test ptrchng-5.3 {
execsql {
SELECT pointer_change(y, 'text16', 'bytes16', 'blob') FROM t1
}
} {0 0 0 0}
}
finish_test

View File

@@ -1,4 +1,4 @@
set rcsid {$Id: capi3.tcl,v 1.9 2005/03/11 04:39:58 drh Exp $}
set rcsid {$Id: capi3.tcl,v 1.10 2007/04/27 17:16:22 drh Exp $}
source common.tcl
header {C/C++ Interface For SQLite Version 3}
@@ -324,6 +324,56 @@ sqlite3_column_type(). If a different format is requested, the data
is converted automatically.
</p>
<p>
Data format conversions can invalidate the pointer returned by
prior calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
sqlite3_column_text16(). Pointers might be invalided in the following
cases:
</p>
<ul>
<li><p>
The initial content is a BLOB and sqlite3_column_text()
or sqlite3_column_text16()
is called. A zero-terminator might need to be added to the string.
</p></li>
<li><p>
The initial content is UTF-8 text and sqlite3_column_bytes16() or
sqlite3_column_text16() is called. The content must be converted to UTF-16.
</p></li>
<li><p>
The initial content is UTF-16 text and sqlite3_column_bytes() or
sqlite3_column_text() is called. The content must be converted to UTF-8.
</p></li>
</ul>
<p>
Note that conversions between UTF-16be and UTF-16le
are always done in place and do
not invalidate a prior pointer, though of course the content of the buffer
that the prior pointer points to will have been modified. Other kinds
of conversion are done in place when it is possible, but sometime it is
not possible and in those cases prior pointers are invalidated.
</p>
<p>
The safest and easiest to remember policy is this: assume that any
result from
<ul>
<li>sqlite3_column_blob(),</li>
<li>sqlite3_column_text(), or</li>
<li>sqlite3_column_text16()</li>
</ul>
is invalided by subsequent calls to
<ul>
<li>sqlite3_column_bytes(),</li>
<li>sqlite3_column_bytes16(),</li>
<li>sqlite3_column_text(), or</li>
<li>sqlite3_column_text16().</li>
</ul>
This means that you should always call sqlite3_column_bytes() or
sqlite3_column_bytes16() <u>before</u> calling sqlite3_column_blob(),
sqlite3_column_text(), or sqlite3_column_text16().
</p>
<h4>2.3 User-defined functions</h4>
<p>

View File

@@ -1,4 +1,4 @@
set rcsid {$Id: capi3ref.tcl,v 1.55 2007/04/16 15:35:24 drh Exp $}
set rcsid {$Id: capi3ref.tcl,v 1.56 2007/04/27 17:16:22 drh Exp $}
source common.tcl
header {C/C++ Interface For SQLite Version 3}
puts {
@@ -432,15 +432,51 @@ int sqlite3_column_type(sqlite3_stmt*, int iCol);
Note that when type conversions occur, pointers returned by prior
calls to sqlite3_column_blob(), sqlite3_column_text(), and/or
sqlite3_column_text16() may be invalidated. So, for example, if
you initially call sqlite3_column_text() and get back a pointer to
a UTF-8 string, then you call sqlite3_column_text16(), after the
call to sqlite3_column_text16() the pointer returned by the prior
call to sqlite3_column_text() will likely point to deallocated memory.
Attempting to use the original pointer might lead to heap corruption
or a segfault. Note also that calls to sqlite3_column_bytes()
and sqlite3_column_bytes16() can also cause type conversion that
and deallocate prior buffers. Use these routines carefully.
sqlite3_column_text16() may be invalidated.
Type conversions and pointer invalidations might occur
in the following cases:
<ul>
<li><p>
The initial content is a BLOB and sqlite3_column_text()
or sqlite3_column_text16()
is called. A zero-terminator might need to be added to the string.
</p></li>
<li><p>
The initial content is UTF-8 text and sqlite3_column_bytes16() or
sqlite3_column_text16() is called. The content must be converted to UTF-16.
</p></li>
<li><p>
The initial content is UTF-16 text and sqlite3_column_bytes() or
sqlite3_column_text() is called. The content must be converted to UTF-8.
</p></li>
</ul>
Conversions between UTF-16be and UTF-16le
are always done in place and do
not invalidate a prior pointer, though of course the content of the buffer
that the prior pointer points to will have been modified. Other kinds
of conversion are done in place when it is possible, but sometime it is
not possible and in those cases prior pointers are invalidated.
The safest and easiest to remember policy is this: assume that any
result from
<ul>
<li>sqlite3_column_blob(),</li>
<li>sqlite3_column_text(), or</li>
<li>sqlite3_column_text16()</li>
</ul>
is invalided by subsequent calls to
<ul>
<li>sqlite3_column_bytes(),</li>
<li>sqlite3_column_bytes16(),</li>
<li>sqlite3_column_text(), or</li>
<li>sqlite3_column_text16().</li>
</ul>
This means that you should always call sqlite3_column_bytes() or
sqlite3_column_bytes16() <u>before</u> calling sqlite3_column_blob(),
sqlite3_column_text(), or sqlite3_column_text16().
}
api {} {
@@ -1491,6 +1527,12 @@ int sqlite3_value_type(sqlite3_value*);
See the documentation under sqlite3_column_blob for additional
information.
Please pay particular attention to the fact that the pointer that
is returned from sqlite3_value_blob(), sqlite3_value_text(), or
sqlite3_value_text16() can be invalidated by a subsequent call to
sqlite3_value_bytes(), sqlite3_value_bytes16(), sqlite_value_text(),
or sqlite3_value_text16().
}
api {} {