mirror of
https://github.com/sqlite/sqlite.git
synced 2025-08-05 15:55:57 +03:00
Clarification on the best practices for using the _bytes() APIs.
Change sqlite3_value_blob() to force the representation to be purely a BLOB and not a dual BLOB/String. Ticket #2360. (CVS 4005) FossilOrigin-Name: cf2dd45b58380de7f3e167b5357848d12872caa3
This commit is contained in:
16
manifest
16
manifest
@@ -1,5 +1,5 @@
|
|||||||
C A\snew\sapproach\sfor\sUTF-8\stranslation.\s(CVS\s4004)
|
C Clarification\son\sthe\sbest\spractices\sfor\susing\sthe\s_bytes()\sAPIs.\nChange\ssqlite3_value_blob()\sto\sforce\sthe\srepresentation\sto\sbe\spurely\na\sBLOB\sand\snot\sa\sdual\sBLOB/String.\s\sTicket\s#2360.\s(CVS\s4005)
|
||||||
D 2007-05-15T11:55:09
|
D 2007-05-15T13:27:07
|
||||||
F Makefile.in 87b200ad9970907f76df734d29dff3d294c10935
|
F Makefile.in 87b200ad9970907f76df734d29dff3d294c10935
|
||||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||||
@@ -71,7 +71,7 @@ F src/date.c 6049db7d5a8fdf2c677ff7d58fa31d4f6593c988
|
|||||||
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
|
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
|
||||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||||
F src/expr.c 436f1d3e5addf95c195016b518cd2f44a6f5f081
|
F src/expr.c 436f1d3e5addf95c195016b518cd2f44a6f5f081
|
||||||
F src/func.c fc1524fd6097b19c54cc4555e3ea724eec628e2c
|
F src/func.c 047c974d530ceca010293f4ae145e4ebc762e9d2
|
||||||
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
|
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
|
||||||
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
|
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
|
||||||
F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d
|
F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d
|
||||||
@@ -135,7 +135,7 @@ F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
|
|||||||
F src/vdbe.c 5deb4cdccd57065ccf8a2e5c704e8473c90d204b
|
F src/vdbe.c 5deb4cdccd57065ccf8a2e5c704e8473c90d204b
|
||||||
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
|
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
|
||||||
F src/vdbeInt.h bddb7931fc1216fda6f6720e18d2a9b1e0f8fc96
|
F src/vdbeInt.h bddb7931fc1216fda6f6720e18d2a9b1e0f8fc96
|
||||||
F src/vdbeapi.c 3ca7808c67a10b5c20150108b431d520d141e93e
|
F src/vdbeapi.c 805147e4e6cd8218ded3dddf4e83ac6154b74a09
|
||||||
F src/vdbeaux.c 62011e2ccf5fa9b3dcc7fa6ff5f0e0638d324a70
|
F src/vdbeaux.c 62011e2ccf5fa9b3dcc7fa6ff5f0e0638d324a70
|
||||||
F src/vdbeblob.c 96f3572fdc45eda5be06e6372b612bc30742d9f0
|
F src/vdbeblob.c 96f3572fdc45eda5be06e6372b612bc30742d9f0
|
||||||
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
|
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
|
||||||
@@ -447,7 +447,7 @@ F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0
|
|||||||
F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06
|
F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06
|
||||||
F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e
|
F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e
|
||||||
F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716
|
F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716
|
||||||
F www/capi3ref.tcl be09756d8b9aebd2d7b597fb910eed66fb4480e6
|
F www/capi3ref.tcl 31da5635eb64ab0f47c71b93b131a6bcb1ddebc9
|
||||||
F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58
|
F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58
|
||||||
F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e
|
F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e
|
||||||
F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084
|
F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084
|
||||||
@@ -491,7 +491,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
|||||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||||
P 252810424d8c4dcd19b369d62027094df7cf0bcc
|
P 6c8ad2790eaede90b3f1ef62614e667178b2a8c4
|
||||||
R 8b16cbfea1aee4c8ac49aefcccb7ea15
|
R 61699b7a12569d4bc746b73ba93dce41
|
||||||
U drh
|
U drh
|
||||||
Z 1d3ef6d9d156a8b50e6d1607d4475644
|
Z 4386a51ac4f148f41d41e7eee93b8111
|
||||||
|
@@ -1 +1 @@
|
|||||||
6c8ad2790eaede90b3f1ef62614e667178b2a8c4
|
cf2dd45b58380de7f3e167b5357848d12872caa3
|
35
src/func.c
35
src/func.c
@@ -16,7 +16,7 @@
|
|||||||
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
** sqliteRegisterBuildinFunctions() found at the bottom of the file.
|
||||||
** All other code has file scope.
|
** All other code has file scope.
|
||||||
**
|
**
|
||||||
** $Id: func.c,v 1.157 2007/05/15 11:55:09 drh Exp $
|
** $Id: func.c,v 1.158 2007/05/15 13:27:07 drh Exp $
|
||||||
*/
|
*/
|
||||||
#include "sqliteInt.h"
|
#include "sqliteInt.h"
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@@ -176,6 +176,7 @@ static void substrFunc(
|
|||||||
len = sqlite3_value_bytes(argv[0]);
|
len = sqlite3_value_bytes(argv[0]);
|
||||||
z = sqlite3_value_blob(argv[0]);
|
z = sqlite3_value_blob(argv[0]);
|
||||||
if( z==0 ) return;
|
if( z==0 ) return;
|
||||||
|
assert( len==sqlite3_value_bytes(argv[0]) );
|
||||||
}else{
|
}else{
|
||||||
z = sqlite3_value_text(argv[0]);
|
z = sqlite3_value_text(argv[0]);
|
||||||
if( z==0 ) return;
|
if( z==0 ) return;
|
||||||
@@ -242,8 +243,10 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||||||
const char *z2;
|
const char *z2;
|
||||||
int i, n;
|
int i, n;
|
||||||
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
||||||
n = sqlite3_value_bytes(argv[0]);
|
|
||||||
z2 = (char*)sqlite3_value_text(argv[0]);
|
z2 = (char*)sqlite3_value_text(argv[0]);
|
||||||
|
n = sqlite3_value_bytes(argv[0]);
|
||||||
|
/* Verify that the call to _bytes() does not invalidate the _text() pointer */
|
||||||
|
assert( z2==(char*)sqlite3_value_text(argv[0]) );
|
||||||
if( z2 ){
|
if( z2 ){
|
||||||
z1 = sqlite3_malloc(n+1);
|
z1 = sqlite3_malloc(n+1);
|
||||||
if( z1 ){
|
if( z1 ){
|
||||||
@@ -260,8 +263,10 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||||||
const char *z2;
|
const char *z2;
|
||||||
int i, n;
|
int i, n;
|
||||||
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
if( argc<1 || SQLITE_NULL==sqlite3_value_type(argv[0]) ) return;
|
||||||
n = sqlite3_value_bytes(argv[0]);
|
|
||||||
z2 = (char*)sqlite3_value_text(argv[0]);
|
z2 = (char*)sqlite3_value_text(argv[0]);
|
||||||
|
n = sqlite3_value_bytes(argv[0]);
|
||||||
|
/* Verify that the call to _bytes() does not invalidate the _text() pointer */
|
||||||
|
assert( z2==(char*)sqlite3_value_text(argv[0]) );
|
||||||
if( z2 ){
|
if( z2 ){
|
||||||
z1 = sqlite3_malloc(n+1);
|
z1 = sqlite3_malloc(n+1);
|
||||||
if( z1 ){
|
if( z1 ){
|
||||||
@@ -562,6 +567,9 @@ static void likeFunc(
|
|||||||
const unsigned char *zA, *zB;
|
const unsigned char *zA, *zB;
|
||||||
int escape = 0;
|
int escape = 0;
|
||||||
|
|
||||||
|
zB = sqlite3_value_text(argv[0]);
|
||||||
|
zA = sqlite3_value_text(argv[1]);
|
||||||
|
|
||||||
/* Limit the length of the LIKE or GLOB pattern to avoid problems
|
/* Limit the length of the LIKE or GLOB pattern to avoid problems
|
||||||
** of deep recursion and N*N behavior in patternCompare().
|
** of deep recursion and N*N behavior in patternCompare().
|
||||||
*/
|
*/
|
||||||
@@ -569,9 +577,8 @@ static void likeFunc(
|
|||||||
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
|
sqlite3_result_error(context, "LIKE or GLOB pattern too complex", -1);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
assert( zB==sqlite3_value_text(argv[0]) ); /* Encoding did not change */
|
||||||
|
|
||||||
zB = sqlite3_value_text(argv[0]);
|
|
||||||
zA = sqlite3_value_text(argv[1]);
|
|
||||||
if( argc==3 ){
|
if( argc==3 ){
|
||||||
/* The escape character string must consist of a single UTF-8 character.
|
/* The escape character string must consist of a single UTF-8 character.
|
||||||
** Otherwise, return an error.
|
** Otherwise, return an error.
|
||||||
@@ -655,8 +662,9 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
|||||||
}
|
}
|
||||||
case SQLITE_BLOB: {
|
case SQLITE_BLOB: {
|
||||||
char *zText = 0;
|
char *zText = 0;
|
||||||
int nBlob = sqlite3_value_bytes(argv[0]);
|
|
||||||
char const *zBlob = sqlite3_value_blob(argv[0]);
|
char const *zBlob = sqlite3_value_blob(argv[0]);
|
||||||
|
int nBlob = sqlite3_value_bytes(argv[0]);
|
||||||
|
assert( zBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
||||||
|
|
||||||
if( 2*nBlob+4>SQLITE_MAX_LENGTH ){
|
if( 2*nBlob+4>SQLITE_MAX_LENGTH ){
|
||||||
sqlite3_result_error_toobig(context);
|
sqlite3_result_error_toobig(context);
|
||||||
@@ -722,12 +730,13 @@ static void hexFunc(
|
|||||||
const unsigned char *pBlob;
|
const unsigned char *pBlob;
|
||||||
char *zHex, *z;
|
char *zHex, *z;
|
||||||
assert( argc==1 );
|
assert( argc==1 );
|
||||||
|
pBlob = sqlite3_value_blob(argv[0]);
|
||||||
n = sqlite3_value_bytes(argv[0]);
|
n = sqlite3_value_bytes(argv[0]);
|
||||||
if( n*2+1>SQLITE_MAX_LENGTH ){
|
if( n*2+1>SQLITE_MAX_LENGTH ){
|
||||||
sqlite3_result_error_toobig(context);
|
sqlite3_result_error_toobig(context);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
pBlob = sqlite3_value_blob(argv[0]);
|
assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
||||||
z = zHex = sqlite3_malloc(n*2 + 1);
|
z = zHex = sqlite3_malloc(n*2 + 1);
|
||||||
if( zHex==0 ) return;
|
if( zHex==0 ) return;
|
||||||
for(i=0; i<n; i++, pBlob++){
|
for(i=0; i<n; i++, pBlob++){
|
||||||
@@ -776,15 +785,18 @@ static void replaceFunc(
|
|||||||
int i, j; /* Loop counters */
|
int i, j; /* Loop counters */
|
||||||
|
|
||||||
assert( argc==3 );
|
assert( argc==3 );
|
||||||
nStr = sqlite3_value_bytes(argv[0]);
|
|
||||||
zStr = sqlite3_value_text(argv[0]);
|
zStr = sqlite3_value_text(argv[0]);
|
||||||
if( zStr==0 ) return;
|
if( zStr==0 ) return;
|
||||||
nPattern = sqlite3_value_bytes(argv[1]);
|
nStr = sqlite3_value_bytes(argv[0]);
|
||||||
|
assert( zStr==sqlite3_value_text(argv[0]) ); /* No encoding change */
|
||||||
zPattern = sqlite3_value_text(argv[1]);
|
zPattern = sqlite3_value_text(argv[1]);
|
||||||
if( zPattern==0 || zPattern[0]==0 ) return;
|
if( zPattern==0 || zPattern[0]==0 ) return;
|
||||||
nRep = sqlite3_value_bytes(argv[2]);
|
nPattern = sqlite3_value_bytes(argv[1]);
|
||||||
|
assert( zPattern==sqlite3_value_text(argv[1]) ); /* No encoding change */
|
||||||
zRep = sqlite3_value_text(argv[2]);
|
zRep = sqlite3_value_text(argv[2]);
|
||||||
if( zRep==0 ) return;
|
if( zRep==0 ) return;
|
||||||
|
nRep = sqlite3_value_bytes(argv[2]);
|
||||||
|
assert( zRep==sqlite3_value_text(argv[2]) );
|
||||||
nOut = nStr + 1;
|
nOut = nStr + 1;
|
||||||
assert( nOut<SQLITE_MAX_LENGTH );
|
assert( nOut<SQLITE_MAX_LENGTH );
|
||||||
zOut = sqlite3_malloc((int)nOut);
|
zOut = sqlite3_malloc((int)nOut);
|
||||||
@@ -840,9 +852,10 @@ static void trimFunc(
|
|||||||
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
if( sqlite3_value_type(argv[0])==SQLITE_NULL ){
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
nIn = sqlite3_value_bytes(argv[0]);
|
|
||||||
zIn = sqlite3_value_text(argv[0]);
|
zIn = sqlite3_value_text(argv[0]);
|
||||||
if( zIn==0 ) return;
|
if( zIn==0 ) return;
|
||||||
|
nIn = sqlite3_value_bytes(argv[0]);
|
||||||
|
assert( zIn==sqlite3_value_text(argv[0]) );
|
||||||
if( argc==1 ){
|
if( argc==1 ){
|
||||||
static const unsigned char lenOne[] = { 1 };
|
static const unsigned char lenOne[] = { 1 };
|
||||||
static const unsigned char *azOne[] = { (u8*)" " };
|
static const unsigned char *azOne[] = { (u8*)" " };
|
||||||
|
@@ -38,9 +38,9 @@ const void *sqlite3_value_blob(sqlite3_value *pVal){
|
|||||||
Mem *p = (Mem*)pVal;
|
Mem *p = (Mem*)pVal;
|
||||||
if( p->flags & (MEM_Blob|MEM_Str) ){
|
if( p->flags & (MEM_Blob|MEM_Str) ){
|
||||||
sqlite3VdbeMemExpandBlob(p);
|
sqlite3VdbeMemExpandBlob(p);
|
||||||
if( (p->flags & MEM_Term)==0 ){
|
|
||||||
p->flags &= ~MEM_Str;
|
p->flags &= ~MEM_Str;
|
||||||
}
|
p->flags |= MEM_Blob;
|
||||||
|
p->type = SQLITE_BLOB;
|
||||||
return p->z;
|
return p->z;
|
||||||
}else{
|
}else{
|
||||||
return sqlite3_value_text(pVal);
|
return sqlite3_value_text(pVal);
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
set rcsid {$Id: capi3ref.tcl,v 1.57 2007/05/07 11:24:31 drh Exp $}
|
set rcsid {$Id: capi3ref.tcl,v 1.58 2007/05/15 13:27:08 drh Exp $}
|
||||||
source common.tcl
|
source common.tcl
|
||||||
header {C/C++ Interface For SQLite Version 3}
|
header {C/C++ Interface For SQLite Version 3}
|
||||||
puts {
|
puts {
|
||||||
@@ -391,20 +391,23 @@ int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
|||||||
If the SQL statement is not currently point to a valid row, or if the
|
If the SQL statement is not currently point to a valid row, or if the
|
||||||
the column index is out of range, the result is undefined.
|
the column index is out of range, the result is undefined.
|
||||||
|
|
||||||
If the result is a BLOB then the sqlite3_column_bytes() routine returns
|
If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
|
||||||
the number of bytes in that BLOB. No type conversions occur.
|
routine returns the number of bytes in that BLOB or string.
|
||||||
If the result is a string (or a number since a number can be converted
|
If the result is a UTF-16 string, then sqlite3_column_bytes() converts
|
||||||
into a string) then sqlite3_column_bytes() converts
|
the string to UTF-8 and then returns the number of bytes.
|
||||||
the value into a UTF-8 string and returns
|
If the result is a numeric value then sqlite3_column_bytes() uses
|
||||||
the number of bytes in the resulting string. The value returned does
|
sqlite3_snprintf() to convert that value to a UTF-8 string and returns
|
||||||
not include the \\000 terminator at the end of the string. The
|
the number of bytes in that string.
|
||||||
sqlite3_column_bytes16() routine converts the value into a UTF-16
|
The value returned does
|
||||||
encoding and returns the number of bytes (not characters) in the
|
not include the \\000 terminator at the end of the string.
|
||||||
resulting string. The \\u0000 terminator is not included in this count.
|
|
||||||
|
The sqlite3_column_bytes16() routine is similar to sqlite3_column_bytes()
|
||||||
|
but leaves the result in UTF-16 instead of UTF-8.
|
||||||
|
The \\u0000 terminator is not included in this count.
|
||||||
|
|
||||||
These routines attempt to convert the value where appropriate. For
|
These routines attempt to convert the value where appropriate. For
|
||||||
example, if the internal representation is FLOAT and a text result
|
example, if the internal representation is FLOAT and a text result
|
||||||
is requested, sprintf() is used internally to do the conversion
|
is requested, sqlite3_snprintf() is used internally to do the conversion
|
||||||
automatically. The following table details the conversions that
|
automatically. The following table details the conversions that
|
||||||
are applied:
|
are applied:
|
||||||
|
|
||||||
@@ -459,24 +462,21 @@ int sqlite3_column_type(sqlite3_stmt*, int iCol);
|
|||||||
of conversion are done in place when it is possible, but sometime it is
|
of conversion are done in place when it is possible, but sometime it is
|
||||||
not possible and in those cases prior pointers are invalidated.
|
not possible and in those cases prior pointers are invalidated.
|
||||||
|
|
||||||
The safest and easiest to remember policy is this: assume that any
|
The safest and easiest to remember policy is to invoke these routines
|
||||||
result from
|
in one of the following ways:
|
||||||
<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().
|
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>sqlite3_column_text() followed by sqlite3_column_bytes()</li>
|
||||||
|
<li>sqlite3_column_blob() followed by sqlite3_column_bytes()</li>
|
||||||
|
<li>sqlite3_column_text16() followed by sqlite3_column_bytes16()</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
In other words, you should call sqlite3_column_text(), sqlite3_column_blob(),
|
||||||
|
or sqlite3_column_text16() first to force the result into the desired
|
||||||
|
format, then invoke sqlite3_column_bytes() or sqlite3_column_bytes16() to
|
||||||
|
find the size of the result. Do not mix call to sqlite3_column_text() or
|
||||||
|
sqlite3_column_blob() with calls to sqlite3_column_bytes16(). And do not
|
||||||
|
mix calls to sqlite3_column_text16() with calls to sqlite3_column_bytes().
|
||||||
}
|
}
|
||||||
|
|
||||||
api {} {
|
api {} {
|
||||||
|
Reference in New Issue
Block a user