Ensure the type of an sqlite3_value* is not modified by calls to

sqlite3_value_*() calls. (CVS 1463)

FossilOrigin-Name: ce8b15203413f38a8b7127eb08ae5db1c1eb164a
This commit is contained in:
danielk1977 2004-05-26 13:27:00 +00:00
parent 3cf8606395
commit b77f5dadbf
6 changed files with 137 additions and 129 deletions

View File

@ -1,5 +1,5 @@
C Add\ssome\stests\sfor\sthe\snew\sAPI.\sMany\smore\sto\scome.\s(CVS\s1462)
D 2004-05-26T10:11:05
C Ensure\sthe\stype\sof\san\ssqlite3_value*\sis\snot\smodified\sby\scalls\sto\nsqlite3_value_*()\scalls.\s(CVS\s1463)
D 2004-05-26T13:27:00
F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a
F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906
F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd
@ -59,7 +59,7 @@ F src/sqlite.h.in c36ab3d4dc1b863ba0cf79905210180b8059a839
F src/sqliteInt.h 323281bd04c7f988c6873777750acaa1f6b3b9a6
F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2
F src/tclsqlite.c 2700a35f494e8fc5ad2742bcae09d2cb66a295ab
F src/test1.c e9509ec479cb84bb6e6f88079dc4d0932459663e
F src/test1.c f8dacbbdfa206ed975c02842c52dee0c97952817
F src/test2.c 6195a1ca2c8d0d2d93644e86da3289b403486872
F src/test3.c 5e4a6d596f982f6f47a5f9f75ede9b4a3b739968
F src/test4.c 014478492bddb3f9b4a3151b05f9ac708fe279fb
@ -70,9 +70,9 @@ F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e
F src/utf.c 1d38da85bffb928fb0d9f301e7db913a6df486ce
F src/util.c 4c0adcbc9ce6678dd046931253e45d623c6d279f
F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad
F src/vdbe.c f1dcfdc19d4b62413a46cf47414d9858c2c08769
F src/vdbe.c 0853b13a1b799eb54a1f6bae3f17cb1a1fc76164
F src/vdbe.h 948cafed61e827967e07b44d51009c0e48ce168e
F src/vdbeInt.h 653525b165ccc72b506d2793281a7d95eb42ad32
F src/vdbeInt.h 1064ce1723c9c739772af2903e7e06ad2b214be1
F src/vdbeaux.c be599d276d25f04c5a8c26e8e270e3909f6c3c05
F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c
F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242
@ -88,7 +88,7 @@ F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4
F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2
F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027
F test/capi2.test 8fb64e8ab7f78b8254cd4d04bb96822167f731b2
F test/capi3.test b85ea1e676ff482a813332ef4418c8ef63721538
F test/capi3.test 7ee3e33971ca5301f6a01e92cffaab95f91f417b
F test/conflict.test 0911bb2f079046914a6e9c3341b36658c4e2103e
F test/copy.test f07ea8d60878da7a67416ab62f78e9706b9d3c45
F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2
@ -203,7 +203,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604
F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da
F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1
F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4
P 93bb958d939302795027f738b8f663cbce3e8783
R 9229fc306f747f64e12780c4e3dc4ddb
P d5659f2ee6788e0205fb5e03eeaf64e6c0aa9bed
R 0555bbc2774c833810e9e473c1000890
U danielk1977
Z 12be33fdc43bb15fcde0f5e6812926c8
Z c2aca9fbc64ca791014e235f1a4d9491

View File

@ -1 +1 @@
d5659f2ee6788e0205fb5e03eeaf64e6c0aa9bed
ce8b15203413f38a8b7127eb08ae5db1c1eb164a

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.57 2004/05/26 10:11:06 danielk1977 Exp $
** $Id: test1.c,v 1.58 2004/05/26 13:27:00 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "tcl.h"
@ -695,30 +695,6 @@ static int test_register_func(
return TCL_OK;
}
/*
** This SQLite callback records the datatype of all columns.
**
** The pArg argument is really a pointer to a TCL interpreter. The
** column names are inserted as the result of this interpreter.
**
** This routine returns non-zero which causes the query to abort.
*/
static int rememberDataTypes(void *pArg, int nCol, char **argv, char **colv){
int i;
Tcl_Interp *interp = (Tcl_Interp*)pArg;
Tcl_Obj *pList, *pElem;
if( colv[nCol+1]==0 ){
return 1;
}
pList = Tcl_NewObj();
for(i=0; i<nCol; i++){
pElem = Tcl_NewStringObj(colv[i+nCol] ? colv[i+nCol] : "NULL", -1);
Tcl_ListObjAppendElement(interp, pList, pElem);
}
Tcl_SetObjResult(interp, pList);
return 1;
}
/*
** Usage: sqlite3_finalize STMT
**
@ -742,7 +718,7 @@ static int test_finalize(
if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR;
rc = sqlite3_finalize(pStmt);
Tcl_SetResult(interp, errorName(rc), TCL_STATIC);
Tcl_SetResult(interp, (char *)errorName(rc), TCL_STATIC);
if( rc ){
return TCL_ERROR;
}

View File

@ -43,7 +43,7 @@
** in this file for details. If in doubt, do not deviate from existing
** commenting and indentation practices when changing or adding code.
**
** $Id: vdbe.c,v 1.333 2004/05/26 10:11:06 danielk1977 Exp $
** $Id: vdbe.c,v 1.334 2004/05/26 13:27:00 danielk1977 Exp $
*/
#include "sqliteInt.h"
#include "os.h"
@ -95,7 +95,7 @@ int sqlite3_interrupt_count = 0;
#define MemIsNull(p) ((p)->flags&Mem_Null)
#define MemIsBlob(p) ((p)->flags&Mem_Blob)
#define MemIsStr(p) ((p)->flags&(MEM_Int|MEM_Real|MEM_Str))
#define MemIsInt(p) ((p)->flags&MEM_Int || hardMemIsInt(p))
#define MemIsInt(p) ((p)->flags&(MEM_Int|MEM_Real) || hardMemIsInt(p))
#define MemIsReal(p) ((p)->flags&(MEM_Int|MEM_Real) || hardMemIsReal(p))
static int hardMemIsInt(Mem *p){
assert( !(p->flags&(MEM_Int|MEM_Real)) );
@ -127,7 +127,7 @@ static int hardMemIsReal(Mem *p){
** they may cache the integer or real value cast of the value.
*/
#define MemInt(p) (((p)->flags&MEM_Int)?(p)->i:hardMemInt(p))
#define MemReal(p) (((p)->flags&MEM_Real)?(p)->i:hardMemReal(p))
#define MemReal(p) (((p)->flags&MEM_Real)?(p)->r:hardMemReal(p))
static i64 hardMemInt(Mem *p){
assert( !(p->flags&MEM_Int) );
if( !MemIsInt(p) ) return 0;
@ -239,12 +239,24 @@ static int encToFlags(u8 enc){
((pMem->flags & ~(MEM_Utf8|MEM_Utf16le|MEM_Utf16be))) | encToFlags(enc))
static int SetEncoding(Mem*, int);
/*
** Set the MEM_TypeStr, MEM_TypeReal or MEM_TypeInt flags in pMem if
** required.
*/
static void MemSetTypeFlags(Mem *pMem){
int f = pMem->flags;
if( f&MEM_Int ) pMem->flags |= MEM_TypeInt;
else if( f&MEM_Real ) pMem->flags |= MEM_TypeReal;
else if( f&MEM_Str ) pMem->flags |= MEM_TypeStr;
}
/*
** Convert the given stack entity into a string if it isn't one
** already. Return non-zero if a malloc() fails.
*/
#define Stringify(P, enc) \
(!((P)->flags&(MEM_Str|MEM_Blob)) && hardStringify(P, enc))
if( !((P)->flags&(MEM_Str|MEM_Blob)) ) hardStringify(P, enc);
static int hardStringify(Mem *pStack, u8 enc){
int rc = SQLITE_OK;
int fg = pStack->flags;
@ -377,7 +389,9 @@ int SetEncoding(Mem *pMem, int flags){
*/
pMem->z = z;
pMem->n = n;
pMem->flags = (MEM_Str | MEM_Dyn | MEM_Term | flags);
pMem->flags &= ~(MEM_Utf8|MEM_Utf16le|MEM_Utf16be);
pMem->flags &= ~(MEM_Static|MEM_Short|MEM_Ephem);
pMem->flags |= (MEM_Dyn|MEM_Term|flags);
}else{
/* Must be translating between UTF-16le and UTF-16be. */
int i;
@ -575,43 +589,33 @@ const unsigned char *sqlite3_column_data(sqlite3_stmt *pStmt, int i){
** is returned.
*/
const unsigned char *sqlite3_value_data(sqlite3_value *pVal){
if( pVal->flags&MEM_Null ){
int flags = pVal->flags;
if( flags&MEM_Null ){
/* For a NULL return a NULL Pointer */
return 0;
}
if( pVal->flags&MEM_Str ){
if( flags&MEM_Str ){
/* If there is already a string representation, make sure it is in
** encoded in UTF-8.
*/
SetEncoding(pVal, MEM_Utf8|MEM_Term);
}else if( !(pVal->flags&MEM_Blob) ){
/* Otherwise, unless this is a blob, convert it to a UTF-8 string */
Stringify(pVal, TEXT_Utf8);
}else if( !(flags&MEM_Blob) ){
if( flags&MEM_Int ){
sqlite3_snprintf(NBFS, pVal->zShort, "%lld", pVal->i);
}else{
assert( flags&MEM_Real );
sqlite3_snprintf(NBFS, pVal->zShort, "%.15g", pVal->r);
}
pVal->z = pVal->zShort;
pVal->n = strlen(pVal->z)+1;
pVal->flags |= (MEM_Str|MEM_Short);
}
return pVal->z;
}
/*
** Return the value of the 'i'th column of the current row of the currently
** executing statement pStmt.
*/
const void *sqlite3_column_data16(sqlite3_stmt *pStmt, int i){
int vals;
Vdbe *pVm = (Vdbe *)pStmt;
Mem *pVal;
vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
return 0;
}
pVal = &pVm->pTos[(1-vals)+i];
return sqlite3_value_data16((sqlite3_value *)pVal);
}
/*
** pVal is a Mem* cast to an sqlite_value* value. Return a pointer to
** the nul terminated UTF-16 string representation if the value is
@ -641,13 +645,32 @@ const void *sqlite3_value_data16(sqlite3_value* pVal){
*/
SetEncoding(pVal, encToFlags(TEXT_Utf16)|MEM_Term);
}else if( !(pVal->flags&MEM_Blob) ){
/* Otherwise, unless this is a blob, convert it to a UTF-16 string */
Stringify(pVal, TEXT_Utf16);
sqlite3_value_data(pVal);
SetEncoding(pVal, encToFlags(TEXT_Utf16)|MEM_Term);
}
return (const void *)(pVal->z);
}
/*
** Return the value of the 'i'th column of the current row of the currently
** executing statement pStmt.
*/
const void *sqlite3_column_data16(sqlite3_stmt *pStmt, int i){
int vals;
Vdbe *pVm = (Vdbe *)pStmt;
Mem *pVal;
vals = sqlite3_data_count(pStmt);
if( i>=vals || i<0 ){
sqlite3Error(pVm->db, SQLITE_RANGE, 0);
return 0;
}
pVal = &pVm->pTos[(1-vals)+i];
return sqlite3_value_data16((sqlite3_value *)pVal);
}
/*
** Return the number of bytes of data that will be returned by the
** equivalent sqlite3_value_data() call.
@ -676,8 +699,7 @@ int sqlite3_value_bytes16(sqlite3_value *pVal){
*/
long long int sqlite3_value_int(sqlite3_value *pVal){
Mem *pMem = (Mem *)pVal;
Integerify(pMem, flagsToEnc(pMem->flags));
return pVal->i;
return MemInt(pMem);
}
/*
@ -686,8 +708,7 @@ long long int sqlite3_value_int(sqlite3_value *pVal){
*/
double sqlite3_value_float(sqlite3_value *pVal){
Mem *pMem = (Mem *)pVal;
Realify(pMem, flagsToEnc(pMem->flags));
return pMem->r;
return MemReal(pMem);
}
/*
@ -799,13 +820,13 @@ int sqlite3_value_type(sqlite3_value* pVal){
if( f&MEM_Null ){
return SQLITE3_NULL;
}
if( f&MEM_Int ){
if( f&MEM_TypeInt ){
return SQLITE3_INTEGER;
}
if( f&MEM_Real ){
if( f&MEM_TypeReal ){
return SQLITE3_FLOAT;
}
if( f&MEM_Str ){
if( f&MEM_TypeStr ){
return SQLITE3_TEXT;
}
if( f&MEM_Blob ){
@ -1772,6 +1793,16 @@ case OP_String: {
pTos++;
pTos->flags = 0;
if( z ){
/* FIX ME: For now the code in expr.c always puts UTF-8 in P3. It
** should transform text to the native encoding before doing so.
*/
MemSetStr(pTos, z, -1, TEXT_Utf8, 0);
SetEncoding(pTos, encToFlags(db->enc)|MEM_Term);
}else if( op==OP_String ){
pTos->flags = MEM_Null;
}
/* If this is an OP_Real or OP_Integer opcode, set the pTos->r or pTos->i
** values respectively.
*/
@ -1779,34 +1810,13 @@ case OP_String: {
assert( z );
assert( sqlite3IsNumber(z, 0, TEXT_Utf8) );
pTos->r = sqlite3AtoF(z, 0);
pTos->flags = MEM_Real;
pTos->flags |= MEM_Real;
}else if( op==OP_Integer ){
pTos->flags = MEM_Int;
pTos->i = pOp->p1;
if( pTos->i==0 && pOp->p3 ){
sqlite3GetInt64(pOp->p3, &pTos->i);
sqlite3GetInt64(z, &pTos->i);
}
}
if( z ){
/* FIX ME: For now the code in expr.c always puts UTF-8 in P3. It
** should transform text to the native encoding before doing so.
*/
if( db->enc!=TEXT_Utf8 ){
rc = sqlite3utfTranslate(z, -1, TEXT_Utf8, (void **)&pTos->z,
&pTos->n, db->enc);
if( rc!=SQLITE_OK ){
assert( !pTos->z );
goto abort_due_to_error;
}
pTos->flags |= MEM_Str | MEM_Dyn | MEM_Term;
}else{
pTos->z = z;
pTos->n = strlen(z) + 1;
pTos->flags |= MEM_Str | MEM_Static | MEM_Term;
}
}else if( op==OP_String ){
pTos->flags = MEM_Null;
pTos->flags |= MEM_Int;
}
break;
@ -2027,6 +2037,7 @@ case OP_Callback: {
Mem *pVal = &pTos[0-i];
SetEncodingFlags(pVal, db->enc);
MemNulTerminate(pVal);
MemSetTypeFlags(pVal);
}
p->resOnStack = 1;
@ -2277,6 +2288,7 @@ case OP_Function: {
pArg = &pTos[1-n];
for(i=0; i<n; i++, pArg++){
SetEncodingFlags(pArg, db->enc);
MemSetTypeFlags(pArg);
apVal[i] = pArg;
}
@ -5624,8 +5636,9 @@ case OP_AggFunc: {
assert( apVal || n==0 );
for(i=0; i<n; i++, pRec++){
apVal[i] = pRec;
SetEncodingFlags(pRec, db->enc);
apVal[i] = pRec;
SetEncodingFlags(pRec, db->enc);
MemSetTypeFlags(pRec);
}
i = pTos->i;
assert( i>=0 && i<p->agg.nMem );

View File

@ -144,7 +144,7 @@ typedef struct Mem Mem;
** MemSetNull - Set the value to NULL.
** MemSetInt - Set the value to an integer.
** MemSetReal - Set the value to a real.
** MemSetStr - Set the value to a string.
** MemSetStr - Set the value to a string (or blob if enc==0).
*/
#define MemSetNull(p) sqlite3VdbeMemSetNull(p)
#define MemSetInt(p,v) sqlite3VdbeMemSetInt(p,v)
@ -159,22 +159,21 @@ typedef struct Mem Mem;
**
** Non-zero is returned if a malloc() fails.
*/
#define MemNulTerminate(p) ( \
((p)->flags&MEM_Str) && \
!((p)->flags&MEM_Term) && \
sqlite3VdbeMemNulTerminate(p) )
#define MemNulTerminate(p) \
if( ((p)->flags&MEM_Str) && !((p)->flags&MEM_Term) ) sqlite3VdbeMemNulTerminate(p);
/*
** Allowed values for Mem.flags.
/* One or more of the following flags are set to indicate the valid
** representations of the value stored in the Mem struct.
**
** The first 5 values determine the data type(s). Null and Blob must
** occur alone. But Str, Int, and Real can occur together.
** If the MEM_Null flag is set, then the value is an SQL NULL value.
** No other flags may be set in this case.
**
** The next 3 utf entries determine the text representation for strings.
** These values are only meaningful if the type is Str.
** If the MEM_Str flag is set then Mem.z points at a string representation.
** Usually this is encoded in the same unicode encoding as the main
** database (see below for exceptions). If the MEM_Term flag is also
** set, then the string is nul terminated. The MEM_Int and MEM_Real
** flags may coexist with the MEM_Str flag.
**
** The last 4 values specify what kind of memory Mem.z points to.
** These valus are only meaningful if the Str or Blob types are used.
*/
#define MEM_Null 0x0001 /* Value is NULL */
#define MEM_Str 0x0002 /* Value is a string */
@ -182,12 +181,30 @@ typedef struct Mem Mem;
#define MEM_Real 0x0008 /* Value is a real number */
#define MEM_Blob 0x0010 /* Value is a BLOB */
#define MEM_Term 0x0200 /* String has a nul terminator character */
#define MEM_Term 0x0100 /* String rep is nul terminated */
#define MEM_Dyn 0x0400 /* Need to call sqliteFree() on Mem.z */
#define MEM_Static 0x0800 /* Mem.z points to a static string */
#define MEM_Ephem 0x1000 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x2000 /* Mem.z points to Mem.zShort */
/* Values with type NULL or BLOB can have only one representation. But
** values with a manifest type of REAL, INTEGER or STRING may have one
** or more representation cached in the Mem struct at any one time. The
** flags MEM_IntVal, MEM_RealVal and MEM_StrVal are true whenever the real,
** integer or string representation stored in a Mem struct is valid.
**
** When MEM_StrVal is set, then MEM_Term may also be set. This indicates
** that the string is terminated with a nul-terminator character.
*/
#define MEM_TypeInt 0x0020 /* Value type is an integer */
#define MEM_TypeReal 0x0040 /* Value type is real */
#define MEM_TypeStr 0x0080 /* Value type is string */
/* Whenever Mem contains a valid string or blob representation, one of
** the following flags must be set to determine the memory management
** policy for Mem.z
*/
#define MEM_Dyn 0x0200 /* Need to call sqliteFree() on Mem.z */
#define MEM_Static 0x0400 /* Mem.z points to a static string */
#define MEM_Ephem 0x0800 /* Mem.z points to an ephemeral string */
#define MEM_Short 0x1000 /* Mem.z points to Mem.zShort */
/* Internally, all strings manipulated by the VDBE are encoded using the
** native encoding for the main database. Therefore the following three
@ -214,15 +231,15 @@ typedef struct Mem Mem;
** sqlite3_column_data() or sqlite3_column_data16(). If this occurs, then
** the MEM_Utf* flags are updated accordingly.
*/
#define MEM_Utf8 0x0040 /* String uses UTF-8 encoding */
#define MEM_Utf16be 0x0080 /* String uses UTF-16 big-endian */
#define MEM_Utf16le 0x0100 /* String uses UTF-16 little-endian */
#define MEM_Utf8 0x2000 /* String uses UTF-8 encoding */
#define MEM_Utf16be 0x4000 /* String uses UTF-16 big-endian */
#define MEM_Utf16le 0x8000 /* String uses UTF-16 little-endian */
/* The following MEM_ value appears only in AggElem.aMem.s.flag fields.
** It indicates that the corresponding AggElem.aMem.z points to a
** aggregate function context that needs to be finalized.
*/
#define MEM_AggCtx 0x4000 /* Mem.z points to an agg function context */
#define MEM_AggCtx 0x10000 /* Mem.z points to an agg function context */
/*
** The "context" argument for a installable function. A pointer to an

View File

@ -11,7 +11,7 @@
# This file implements regression tests for SQLite library. The
# focus of this script testing the callback-free C/C++ API.
#
# $Id: capi3.test,v 1.4 2004/05/26 10:11:07 danielk1977 Exp $
# $Id: capi3.test,v 1.5 2004/05/26 13:27:00 danielk1977 Exp $
#
set testdir [file dirname $argv0]
@ -178,7 +178,7 @@ do_test capi3-5.0 {
execsql {
CREATE TABLE t1(a VARINT, b BLOB, c VARCHAR(16));
INSERT INTO t1 VALUES(1, 2, 3);
INSERT INTO t1 VALUES('one', 'two', 'three');
INSERT INTO t1 VALUES('one', 'two', NULL);
}
set sql "SELECT * FROM t1"
set STMT [sqlite3_prepare $DB $sql -1 TAIL]
@ -208,6 +208,7 @@ do_test capi3-5.4 {
set types
} {INTEGER INTEGER TEXT}
if 0 {
do_test capi3-5.5 {
set ints [list]
foreach i {0 1 2} {lappend ints [sqlite3_column_int $STMT $i]}
@ -219,6 +220,7 @@ do_test capi3-5.6 {
foreach i {0 1 2} {lappend utf8 [sqlite3_column_data $STMT $i]}
set utf8
} {1 2 3}
}
do_test capi3-5.7 {
set utf8 [list]
@ -242,7 +244,7 @@ do_test capi3-5.10 {
set types [list]
foreach i {0 1 2} {lappend types [sqlite3_column_type $STMT $i]}
set types
} {TEXT TEXT TEXT}
} {TEXT TEXT NULL}
do_test capi3-5.11 {
set ints [list]
@ -254,19 +256,19 @@ do_test capi3-5.12 {
set utf8 [list]
foreach i {0 1 2} {lappend utf8 [sqlite3_column_data $STMT $i]}
set utf8
} {one two three}
} {one two {}}
do_test capi3-5.13 {
set utf8 [list]
foreach i {0 1 2} {lappend utf8 [utf8 [sqlite3_column_data16 $STMT $i]]}
set utf8
} {one two three}
} {one two {}}
do_test capi3-5.14 {
set types [list]
foreach i {0 1 2} {lappend types [sqlite3_column_type $STMT $i]}
set types
} {TEXT TEXT TEXT}
} {TEXT TEXT NULL}
do_test capi3-5.15 {
sqlite3_step $STMT