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:
parent
4a919118d3
commit
1f0feef80b
16
manifest
16
manifest
@ -1,5 +1,5 @@
|
||||
C A\snew\sapproach\sfor\sUTF-8\stranslation.\s(CVS\s4004)
|
||||
D 2007-05-15T11:55:09
|
||||
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-15T13:27:07
|
||||
F Makefile.in 87b200ad9970907f76df734d29dff3d294c10935
|
||||
F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
|
||||
F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
|
||||
@ -71,7 +71,7 @@ F src/date.c 6049db7d5a8fdf2c677ff7d58fa31d4f6593c988
|
||||
F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
|
||||
F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
|
||||
F src/expr.c 436f1d3e5addf95c195016b518cd2f44a6f5f081
|
||||
F src/func.c fc1524fd6097b19c54cc4555e3ea724eec628e2c
|
||||
F src/func.c 047c974d530ceca010293f4ae145e4ebc762e9d2
|
||||
F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
|
||||
F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
|
||||
F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d
|
||||
@ -135,7 +135,7 @@ F src/vacuum.c 8bd895d29e7074e78d4e80f948e35ddc9cf2beef
|
||||
F src/vdbe.c 5deb4cdccd57065ccf8a2e5c704e8473c90d204b
|
||||
F src/vdbe.h 001c5b257567c1d3de7feb2203aac71d0d7b16a3
|
||||
F src/vdbeInt.h bddb7931fc1216fda6f6720e18d2a9b1e0f8fc96
|
||||
F src/vdbeapi.c 3ca7808c67a10b5c20150108b431d520d141e93e
|
||||
F src/vdbeapi.c 805147e4e6cd8218ded3dddf4e83ac6154b74a09
|
||||
F src/vdbeaux.c 62011e2ccf5fa9b3dcc7fa6ff5f0e0638d324a70
|
||||
F src/vdbeblob.c 96f3572fdc45eda5be06e6372b612bc30742d9f0
|
||||
F src/vdbefifo.c 3ca8049c561d5d67cbcb94dc909ae9bb68c0bf8f
|
||||
@ -447,7 +447,7 @@ F www/audit.tcl 90e09d580f79c7efec0c7d6f447b7ec5c2dce5c0
|
||||
F www/autoinc.tcl b357f5ba954b046ee35392ce0f884a2fcfcdea06
|
||||
F www/c_interface.tcl b51b08591554c16a0c3ef718364a508ac25abc7e
|
||||
F www/capi3.tcl 88884dd743039d1a95aa57f4a5eb369de7744716
|
||||
F www/capi3ref.tcl be09756d8b9aebd2d7b597fb910eed66fb4480e6
|
||||
F www/capi3ref.tcl 31da5635eb64ab0f47c71b93b131a6bcb1ddebc9
|
||||
F www/changes.tcl 550300b0ff00fc1b872f7802b2d5a1e7587d3e58
|
||||
F www/common.tcl 2b793e5c31486c8a01dd27dc0a631ad93704438e
|
||||
F www/compile.tcl 276546d7eb445add5a867193bbd80f6919a6b084
|
||||
@ -491,7 +491,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
|
||||
F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
|
||||
F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
|
||||
F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
|
||||
P 252810424d8c4dcd19b369d62027094df7cf0bcc
|
||||
R 8b16cbfea1aee4c8ac49aefcccb7ea15
|
||||
P 6c8ad2790eaede90b3f1ef62614e667178b2a8c4
|
||||
R 61699b7a12569d4bc746b73ba93dce41
|
||||
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.
|
||||
** 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 <ctype.h>
|
||||
@ -176,6 +176,7 @@ static void substrFunc(
|
||||
len = sqlite3_value_bytes(argv[0]);
|
||||
z = sqlite3_value_blob(argv[0]);
|
||||
if( z==0 ) return;
|
||||
assert( len==sqlite3_value_bytes(argv[0]) );
|
||||
}else{
|
||||
z = sqlite3_value_text(argv[0]);
|
||||
if( z==0 ) return;
|
||||
@ -242,8 +243,10 @@ static void upperFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
const char *z2;
|
||||
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]);
|
||||
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 ){
|
||||
z1 = sqlite3_malloc(n+1);
|
||||
if( z1 ){
|
||||
@ -260,8 +263,10 @@ static void lowerFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
const char *z2;
|
||||
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]);
|
||||
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 ){
|
||||
z1 = sqlite3_malloc(n+1);
|
||||
if( z1 ){
|
||||
@ -562,6 +567,9 @@ static void likeFunc(
|
||||
const unsigned char *zA, *zB;
|
||||
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
|
||||
** 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);
|
||||
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 ){
|
||||
/* The escape character string must consist of a single UTF-8 character.
|
||||
** Otherwise, return an error.
|
||||
@ -655,8 +662,9 @@ static void quoteFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
|
||||
}
|
||||
case SQLITE_BLOB: {
|
||||
char *zText = 0;
|
||||
int nBlob = sqlite3_value_bytes(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 ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
@ -722,12 +730,13 @@ static void hexFunc(
|
||||
const unsigned char *pBlob;
|
||||
char *zHex, *z;
|
||||
assert( argc==1 );
|
||||
pBlob = sqlite3_value_blob(argv[0]);
|
||||
n = sqlite3_value_bytes(argv[0]);
|
||||
if( n*2+1>SQLITE_MAX_LENGTH ){
|
||||
sqlite3_result_error_toobig(context);
|
||||
return;
|
||||
}
|
||||
pBlob = sqlite3_value_blob(argv[0]);
|
||||
assert( pBlob==sqlite3_value_blob(argv[0]) ); /* No encoding change */
|
||||
z = zHex = sqlite3_malloc(n*2 + 1);
|
||||
if( zHex==0 ) return;
|
||||
for(i=0; i<n; i++, pBlob++){
|
||||
@ -776,15 +785,18 @@ 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;
|
||||
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]);
|
||||
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]);
|
||||
if( zRep==0 ) return;
|
||||
nRep = sqlite3_value_bytes(argv[2]);
|
||||
assert( zRep==sqlite3_value_text(argv[2]) );
|
||||
nOut = nStr + 1;
|
||||
assert( nOut<SQLITE_MAX_LENGTH );
|
||||
zOut = sqlite3_malloc((int)nOut);
|
||||
@ -840,9 +852,10 @@ 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]);
|
||||
assert( zIn==sqlite3_value_text(argv[0]) );
|
||||
if( argc==1 ){
|
||||
static const unsigned char lenOne[] = { 1 };
|
||||
static const unsigned char *azOne[] = { (u8*)" " };
|
||||
|
@ -38,9 +38,9 @@ const void *sqlite3_value_blob(sqlite3_value *pVal){
|
||||
Mem *p = (Mem*)pVal;
|
||||
if( p->flags & (MEM_Blob|MEM_Str) ){
|
||||
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;
|
||||
}else{
|
||||
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
|
||||
header {C/C++ Interface For SQLite Version 3}
|
||||
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
|
||||
the column index is out of range, the result is undefined.
|
||||
|
||||
If the result is a BLOB then the sqlite3_column_bytes() routine returns
|
||||
the number of bytes in that BLOB. No type conversions occur.
|
||||
If the result is a string (or a number since a number can be converted
|
||||
into a string) then sqlite3_column_bytes() converts
|
||||
the value into a UTF-8 string and returns
|
||||
the number of bytes in the resulting string. The value returned does
|
||||
not include the \\000 terminator at the end of the string. The
|
||||
sqlite3_column_bytes16() routine converts the value into a UTF-16
|
||||
encoding and returns the number of bytes (not characters) in the
|
||||
resulting string. The \\u0000 terminator is not included in this count.
|
||||
If the result is a BLOB or UTF-8 string then the sqlite3_column_bytes()
|
||||
routine returns the number of bytes in that BLOB or string.
|
||||
If the result is a UTF-16 string, then sqlite3_column_bytes() converts
|
||||
the string to UTF-8 and then returns the number of bytes.
|
||||
If the result is a numeric value then sqlite3_column_bytes() uses
|
||||
sqlite3_snprintf() to convert that value to a UTF-8 string and returns
|
||||
the number of bytes in that string.
|
||||
The value returned does
|
||||
not include the \\000 terminator at the end of the string.
|
||||
|
||||
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
|
||||
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
|
||||
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
|
||||
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().
|
||||
The safest and easiest to remember policy is to invoke these routines
|
||||
in one of the following ways:
|
||||
|
||||
<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 {} {
|
||||
|
Loading…
x
Reference in New Issue
Block a user