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:
drh 2007-05-15 13:27:07 +00:00
parent 4a919118d3
commit 1f0feef80b
5 changed files with 65 additions and 52 deletions

View File

@ -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

View File

@ -1 +1 @@
6c8ad2790eaede90b3f1ef62614e667178b2a8c4
cf2dd45b58380de7f3e167b5357848d12872caa3

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.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*)" " };

View File

@ -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);

View File

@ -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 {} {