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:
23
manifest
23
manifest
@@ -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
|
||||
|
@@ -1 +1 @@
|
||||
40ba6493e9e8ba135552a2a0943ab499713ac001
|
||||
e92bd97a3726bbb7978489e2994747127c4aefcf
|
20
src/func.c
20
src/func.c
@@ -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;
|
||||
|
86
src/test1.c
86
src/test1.c
@@ -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;
|
||||
}
|
||||
|
@@ -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
217
test/ptrchng.test
Normal 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
|
@@ -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>
|
||||
|
@@ -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 {} {
|
||||
|
Reference in New Issue
Block a user