diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/test1.c | 28 | ||||
-rw-r--r-- | src/vdbe.c | 141 | ||||
-rw-r--r-- | src/vdbeInt.h | 63 |
3 files changed, 119 insertions, 113 deletions
diff --git a/src/test1.c b/src/test1.c index 0d3823c09..e695cce5f 100644 --- a/src/test1.c +++ b/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.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" @@ -696,30 +696,6 @@ static int test_register_func( } /* -** 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 ** ** Finalize a statement handle. @@ -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; } diff --git a/src/vdbe.c b/src/vdbe.c index 3b1d5d060..7cc4288b0 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -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; @@ -240,11 +240,23 @@ static int encToFlags(u8 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,44 +589,34 @@ 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 ** not a blob or NULL. If the value is a blob, then just return a pointer @@ -641,14 +645,33 @@ 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 ); diff --git a/src/vdbeInt.h b/src/vdbeInt.h index e1f5b4e9b..733b333f6 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -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. -** -** The first 5 values determine the data type(s). Null and Blob must -** occur alone. But Str, Int, and Real can occur together. +/* One or more of the following flags are set to indicate the valid +** representations of the value stored in the Mem struct. ** -** The next 3 utf entries determine the text representation for strings. -** These values are only meaningful if the type is Str. +** 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 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. +** 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. +** */ #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 */ + +/* 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 */ -#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 */ + +/* 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 |