diff --git a/manifest b/manifest index 7ed53265d2..18b7cb43ee 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Begin\schanging\sthe\svdbe\sso\sall\sstack\svalues\suse\sthe\sdatabase\sencoding.\s(CVS\s1444) -D 2004-05-23T13:30:58 +C Have\sthe\svdbe\shandle\sstrings\sin\sthe\ssame\sencoding\sas\sthe\sdatabase.\s(CVS\s1445) +D 2004-05-24T07:04:26 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -28,11 +28,11 @@ F src/btree.c 51dfa34da5f42762b228d7360cf3273ee403bce8 F src/btree.h b65140b5ae891f30d2a39e64b9f0343225553545 F src/build.c 35cbeb439b49cca5eb5e8a1de010a5194f4523e8 F src/copy.c 4d2038602fd0549d80c59bda27d96f13ea9b5e29 -F src/date.c 0eb0a89960bb45c7f7e768748605a7a97b0c8064 +F src/date.c fd6a46498449db9c4ff5d45544d9a9b8ba9d8cd5 F src/delete.c 2e1dda38345416a1ea1c0a6468589a7472334dac F src/encode.c a876af473d1d636faa3dca51c7571f2e007eea37 F src/expr.c 5b283e68bd6df365b7c2ad10bd04cc54c2b4b07c -F src/func.c cfbb7096efb58e2857e3b312a8958a12774b625a +F src/func.c 333bbc06cc281f4dbded5dfc4faa1457764bc1b3 F src/hash.c 440c2f8cb373ee1b4e13a0988489c7cd95d55b6f F src/hash.h 762d95f1e567664d1eafc1687de755626be962fb F src/insert.c e510d62d23b4de4d901e7ccbbe7833b7fb3b9570 @@ -53,9 +53,9 @@ F src/pragma.c e14dd3b06cedeadcc027f0b6706b2f53d456a46e F src/printf.c ef750e8e2398ca7e8b58be991075f08c6a7f0e53 F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c 7d77a8bed7eeac23216d42fc1be006fb4352fcdc -F src/shell.c 657623c2a3df126538d41842c2146cadbd52b154 +F src/shell.c ed4d237b3e52a0a42512bfcc53530e46de20c28f F src/sqlite.h.in 69393dbaa5b11853685ae656d1bef6a98b808bbb -F src/sqliteInt.h 823411100924138073aa542af4aae8bd5eede4a3 +F src/sqliteInt.h e1191166ac9055d6c99c97771d3f35212ef2cff2 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c f241854328ee2b06006efded270d84799159f760 F src/test1.c b5f2f9f9d866c8a586b8d47c5999d2cbefaac686 @@ -67,12 +67,12 @@ F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847 F src/trigger.c 11afe9abfba13a2ba142944c797c952e162d117f F src/update.c 1a5e9182596f3ea8c7a141e308a3d2a7e5689fee F src/utf.c 441c5918ee3777cd8e9611cbb810312ed314737d -F src/util.c 5cbeb452da09cfc7248de9948c15b14d840723f7 +F src/util.c 4c0adcbc9ce6678dd046931253e45d623c6d279f F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad -F src/vdbe.c b40ff0912ddfae65d9a90ca38302b74a04c6ee76 +F src/vdbe.c d5d15429c0be735d325d53d0dadbb2197a9f405d F src/vdbe.h 391d5642a83af686f35c228fcd36cb4456d68f44 F src/vdbeInt.h 6c2444a60fc030b275dc0cff407cdaa79d84ce86 -F src/vdbeaux.c 60fa2357fc12dec128d9606e5b84cec836aa7e40 +F src/vdbeaux.c 7f0c4ad22d5e61465d509467e2535293b468373a F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 @@ -202,7 +202,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P 18e690e405710c9a8010340c01754bbfa3231fe9 -R a90f19b4bed57bb3a6862d24faf34718 +P f47de3a933b51b37629a0ca2e492a534a12e7339 +R 0d8b15870c4105fdf982c7cf1ceb6e90 U danielk1977 -Z 72938d5d6b2f4afcbbfc88e30cdfc1f0 +Z 680dc16bbdc1913b8e540b4d62c8fcee diff --git a/manifest.uuid b/manifest.uuid index d76215f2da..862ff40b86 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f47de3a933b51b37629a0ca2e492a534a12e7339 \ No newline at end of file +b7155db2b13aa3ca5f6c68e948d9e8740ebcac47 \ No newline at end of file diff --git a/src/date.c b/src/date.c index 824f2732eb..d2d7418eae 100644 --- a/src/date.c +++ b/src/date.c @@ -16,7 +16,7 @@ ** sqlite3RegisterDateTimeFunctions() found at the bottom of the file. ** All other code has file scope. ** -** $Id: date.c,v 1.19 2004/05/14 11:00:53 danielk1977 Exp $ +** $Id: date.c,v 1.20 2004/05/24 07:04:26 danielk1977 Exp $ ** ** NOTES: ** @@ -321,7 +321,7 @@ static int parseDateOrTime(const char *zDate, DateTime *p){ return 0; } return 1; - }else if( sqlite3IsNumber(zDate, 0) ){ + }else if( sqlite3IsNumber(zDate, 0, TEXT_Utf8) ){ p->rJD = sqlite3AtoF(zDate, 0); p->validJD = 1; return 0; diff --git a/src/func.c b/src/func.c index 3f623aaac3..4e8606717c 100644 --- a/src/func.c +++ b/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.48 2004/05/16 11:15:38 danielk1977 Exp $ +** $Id: func.c,v 1.49 2004/05/24 07:04:26 danielk1977 Exp $ */ #include #include @@ -295,7 +295,7 @@ static void quoteFunc(sqlite_func *context, int argc, const char **argv){ if( argc<1 ) return; if( argv[0]==0 ){ sqlite3_set_result_string(context, "NULL", 4); - }else if( sqlite3IsNumber(argv[0], 0) ){ + }else if( sqlite3IsNumber(argv[0], 0, TEXT_Utf8) ){ sqlite3_set_result_string(context, argv[0], -1); }else{ int i,j,n; diff --git a/src/shell.c b/src/shell.c index cf9e80d927..5c0a37a8f4 100644 --- a/src/shell.c +++ b/src/shell.c @@ -12,7 +12,7 @@ ** This file contains code to implement the "sqlite" command line ** utility for accessing SQLite databases. ** -** $Id: shell.c,v 1.97 2004/05/22 09:21:21 danielk1977 Exp $ +** $Id: shell.c,v 1.98 2004/05/24 07:04:26 danielk1977 Exp $ */ #include #include @@ -80,7 +80,7 @@ static char continuePrompt[20]; /* Continuation prompt. default: " ...> " */ /* ** Determines if a string is a number of not. */ -extern int sqlite3IsNumber(const char*, int*); +extern int sqlite3IsNumber(const char*, int*, unsigned char); /* ** This routine reads a line of text from standard input, stores @@ -392,7 +392,7 @@ static int callback(void *pArg, int nArg, char **azArg, char **azCol){ char *zSep = i>0 ? ",": ""; if( azArg[i]==0 ){ fprintf(p->out,"%sNULL",zSep); - }else if( sqlite3IsNumber(azArg[i], 0) ){ + }else if( sqlite3IsNumber(azArg[i], 0, 1) ){ fprintf(p->out,"%s%s",zSep, azArg[i]); }else{ if( zSep[0] ) fprintf(p->out,"%s",zSep); diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 18859cb8b6..1c99bd80ee 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.247 2004/05/23 13:30:58 danielk1977 Exp $ +** @(#) $Id: sqliteInt.h,v 1.248 2004/05/24 07:04:26 danielk1977 Exp $ */ #include "config.h" #include "sqlite.h" @@ -326,10 +326,10 @@ struct Db { /* ** Possible values for the Db.textEnc field. */ -#define TEXT_Utf8 1 -#define TEXT_Utf16le 2 -#define TEXT_Utf16be 3 -/* #define TEXT_Utf16 4 */ +#define TEXT_Utf8 1 +#define TEXT_Utf16le 2 +#define TEXT_Utf16be 3 +#define TEXT_Utf16 (SQLITE3_BIGENDIAN?TEXT_Utf16be:TEXT_Utf16le) /* ** Each database is an instance of the following structure. @@ -1177,7 +1177,7 @@ extern int always_code_trigger_setup; int sqlite3StrICmp(const char *, const char *); int sqlite3StrNICmp(const char *, const char *, int); int sqlite3HashNoCase(const char *, int); -int sqlite3IsNumber(const char*, int*); +int sqlite3IsNumber(const char*, int*, u8); int sqlite3Compare(const char *, const char *); int sqlite3SortCompare(const char *, const char *); void sqlite3RealToSortable(double r, char *); @@ -1368,7 +1368,7 @@ char sqlite3CompareAffinity(Expr *pExpr, char aff2); char const *sqlite3AffinityString(char affinity); int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity); char sqlite3ExprAffinity(Expr *pExpr); -int sqlite3atoi64(const char*, i64*); +int sqlite3atoi64(const char*, i64*, u8); void sqlite3Error(sqlite *, int, const char*,...); int sqlite3utfTranslate(const void *, int , u8 , void **, int *, u8); u8 sqlite3UtfReadBom(const void *zData, int nData); diff --git a/src/util.c b/src/util.c index b2bcf92bb5..b3744e23c7 100644 --- a/src/util.c +++ b/src/util.c @@ -14,7 +14,7 @@ ** This file contains functions for allocating memory, comparing ** strings, and stuff like that. ** -** $Id: util.c,v 1.87 2004/05/20 11:00:52 danielk1977 Exp $ +** $Id: util.c,v 1.88 2004/05/24 07:04:26 danielk1977 Exp $ */ #include "sqliteInt.h" #include @@ -564,25 +564,27 @@ int sqlite3StrNICmp(const char *zLeft, const char *zRight, int N){ ** ** Am empty string is considered non-numeric. */ -int sqlite3IsNumber(const char *z, int *realnum){ - if( *z=='-' || *z=='+' ) z++; +int sqlite3IsNumber(const char *z, int *realnum, u8 enc){ + int incr = (enc==TEXT_Utf8?1:2); + if( enc==TEXT_Utf16be ) z++; + if( *z=='-' || *z=='+' ) z += incr; if( !isdigit(*z) ){ return 0; } - z++; + z += incr; if( realnum ) *realnum = 0; - while( isdigit(*z) ){ z++; } + while( isdigit(*z) ){ z += incr; } if( *z=='.' ){ - z++; + z += incr; if( !isdigit(*z) ) return 0; - while( isdigit(*z) ){ z++; } + while( isdigit(*z) ){ z += incr; } if( realnum ) *realnum = 1; } if( *z=='e' || *z=='E' ){ - z++; - if( *z=='+' || *z=='-' ) z++; + z += incr; + if( *z=='+' || *z=='-' ) z += incr; if( !isdigit(*z) ) return 0; - while( isdigit(*z) ){ z++; } + while( isdigit(*z) ){ z += incr; } if( realnum ) *realnum = 1; } return *z==0; @@ -663,23 +665,27 @@ double sqlite3AtoF(const char *z, const char **pzEnd){ ** 32-bit numbers. At that time, it was much faster than the ** atoi() library routine in RedHat 7.2. */ -int sqlite3atoi64(const char *zNum, i64 *pNum){ +int sqlite3atoi64(const char *zNum, i64 *pNum, u8 enc){ i64 v = 0; int neg; int i, c; + int incr = (enc==TEXT_Utf8?1:2); + if( enc==TEXT_Utf16be ) zNum++; if( *zNum=='-' ){ neg = 1; - zNum++; + zNum += incr; }else if( *zNum=='+' ){ neg = 0; - zNum++; + zNum += incr; }else{ neg = 0; } - for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ + for(i=0; (c=zNum[i])>='0' && c<='9'; i += incr){ v = v*10 + c - '0'; } *pNum = neg ? -v : v; + + /* FIX ME: Handle overflow of strings in UTF-16 here */ return c==0 && i>0 && (i<19 || (i==19 && memcmp(zNum,"9223372036854775807",19)<=0)); } @@ -738,7 +744,7 @@ int sqlite3FitsIn64Bits(const char *zNum){ */ int sqlite3GetInt64(const char *zNum, i64 *pValue){ if( sqlite3FitsIn64Bits(zNum) ){ - sqlite3atoi64(zNum, pValue); + sqlite3atoi64(zNum, pValue, TEXT_Utf8); return 1; } return 0; @@ -765,8 +771,8 @@ int sqlite3Compare(const char *atext, const char *btext){ }else if( btext==0 ){ return 1; } - isNumA = sqlite3IsNumber(atext, 0); - isNumB = sqlite3IsNumber(btext, 0); + isNumA = sqlite3IsNumber(atext, 0, TEXT_Utf8); + isNumB = sqlite3IsNumber(btext, 0, TEXT_Utf8); if( isNumA ){ if( !isNumB ){ result = -1; @@ -857,8 +863,8 @@ int sqlite3SortCompare(const char *a, const char *b){ res = strcmp(&a[1],&b[1]); if( res ) break; }else{ - isNumA = sqlite3IsNumber(&a[1], 0); - isNumB = sqlite3IsNumber(&b[1], 0); + isNumA = sqlite3IsNumber(&a[1], 0, TEXT_Utf8); + isNumB = sqlite3IsNumber(&b[1], 0, TEXT_Utf8); if( isNumA ){ double rA, rB; if( !isNumB ){ diff --git a/src/vdbe.c b/src/vdbe.c index 2954b287eb..b25e1b3a96 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.321 2004/05/23 13:30:58 danielk1977 Exp $ +** $Id: vdbe.c,v 1.322 2004/05/24 07:04:27 danielk1977 Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -97,71 +97,12 @@ static int Recordify(Mem *pMem){ } #endif -/* -** Convert the given stack entity into a string if it isn't one -** already. -*/ -#define Stringify(P) if(!((P)->flags&(MEM_Str|MEM_Blob))){hardStringify(P);} -static int hardStringify(Mem *pStack){ - int fg = pStack->flags; - if( fg & MEM_Real ){ - sqlite3_snprintf(sizeof(pStack->zShort),pStack->zShort,"%.15g",pStack->r); - }else if( fg & MEM_Int ){ - sqlite3_snprintf(sizeof(pStack->zShort),pStack->zShort,"%lld",pStack->i); - }else{ - pStack->zShort[0] = 0; - } - pStack->z = pStack->zShort; - pStack->n = strlen(pStack->zShort)+1; - pStack->flags = MEM_Str | MEM_Short | MEM_Term | MEM_Utf8; - return 0; -} - /* ** Release the memory associated with the given stack level. This ** leaves the Mem.flags field in an inconsistent state. */ #define Release(P) if((P)->flags&MEM_Dyn){ sqliteFree((P)->z); } -/* -** Convert the given stack entity into a integer if it isn't one -** already. -** -** Any prior string or real representation is invalidated. -** NULLs are converted into 0. -*/ -#define Integerify(P) if(((P)->flags&MEM_Int)==0){ hardIntegerify(P); } -static void hardIntegerify(Mem *pStack){ - if( pStack->flags & MEM_Real ){ - pStack->i = (int)pStack->r; - Release(pStack); - }else if( pStack->flags & MEM_Str ){ - sqlite3atoi64(pStack->z, &pStack->i); - Release(pStack); - }else{ - pStack->i = 0; - } - pStack->flags = MEM_Int; -} - -/* -** Get a valid Real representation for the given stack element. -** -** Any prior string or integer representation is retained. -** NULLs are converted into 0.0. -*/ -#define Realify(P) if(((P)->flags&MEM_Real)==0){ hardRealify(P); } -static void hardRealify(Mem *pStack){ - if( pStack->flags & MEM_Str ){ - pStack->r = sqlite3AtoF(pStack->z, 0); - }else if( pStack->flags & MEM_Int ){ - pStack->r = pStack->i; - }else{ - pStack->r = 0.0; - } - pStack->flags |= MEM_Real; -} - /* ** Parmameter "flags" is the value of the flags for a string Mem object. ** Return one of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be, depending @@ -199,8 +140,8 @@ static int encToFlags(u8 enc){ ** for the database encoding "enc" (one of TEXT_Utf8, TEXT_Utf16le or ** TEXT_Utf16be). */ -#define SetEncodingFlags(pMem, enc) (pMem->flags = \ -(pMem->flags & ~(MEM_Utf8|MEM_Utf16le|MEM_Utf16be)) | encToFlags(enc)) +#define SetEncodingFlags(pMem, enc) ((pMem)->flags = \ +((pMem->flags & ~(MEM_Utf8|MEM_Utf16le|MEM_Utf16be))) | encToFlags(enc)) /* ** If pMem is a string object, this routine sets the encoding of the string @@ -222,7 +163,7 @@ int SetEncoding(Mem *pMem, int flags){ u8 enc2; /* Required string encoding (TEXT_Utf* value) */ /* If this is not a string, do nothing. */ - if( !(pMem->flags&MEM_Str) || pMem->flags&MEM_Int || pMem->flags&MEM_Real ){ + if( !(pMem->flags&MEM_Str) ){ return SQLITE_OK; } @@ -235,7 +176,7 @@ int SetEncoding(Mem *pMem, int flags){ */ char *z; int n; - int rc = sqlite3utfTranslate(pMem->z, pMem->n, enc1, (void **)&z, &n, enc2); + int rc = sqlite3utfTranslate(pMem->z,pMem->n,enc1,(void **)&z,&n,enc2); if( rc!=SQLITE_OK ){ return rc; } @@ -305,6 +246,95 @@ int SetEncoding(Mem *pMem, int flags){ return SQLITE_OK; } +/* +** Convert the given stack entity into a integer if it isn't one +** already. +** +** Any prior string or real representation is invalidated. +** NULLs are converted into 0. +*/ +#define Integerify(P, enc) \ +if(((P)->flags&MEM_Int)==0){ hardIntegerify(P, enc); } +static void hardIntegerify(Mem *pStack, u8 enc){ + pStack->i = 0; + if( pStack->flags & MEM_Real ){ + pStack->i = (int)pStack->r; + Release(pStack); + }else if( pStack->flags & MEM_Str ){ + if( pStack->z ){ + sqlite3atoi64(pStack->z, &pStack->i, enc); + } + } + pStack->flags = MEM_Int; +} + +/* +** Get a valid Real representation for the given stack element. +** +** Any prior string or integer representation is retained. +** NULLs are converted into 0.0. +*/ +#define Realify(P,enc) if(((P)->flags&MEM_Real)==0){ hardRealify(P,enc); } +static void hardRealify(Mem *pStack, u8 enc){ + if( pStack->flags & MEM_Str ){ + SetEncodingFlags(pStack, enc); + SetEncoding(pStack, MEM_Utf8|MEM_Term); + pStack->r = sqlite3AtoF(pStack->z, 0); + }else if( pStack->flags & MEM_Int ){ + pStack->r = pStack->i; + }else{ + pStack->r = 0.0; + } +/* pStack->flags |= MEM_Real; */ + pStack->flags = MEM_Real; +} + + +/* +** 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)) +static int hardStringify(Mem *pStack, u8 enc){ + int rc = SQLITE_OK; + int fg = pStack->flags; + + assert( !(fg&(MEM_Str|MEM_Blob)) ); + assert( fg&(MEM_Int|MEM_Real|MEM_Null) ); + + if( fg & MEM_Null ){ + /* A NULL value is converted to a zero length string */ + pStack->zShort[0] = 0; + pStack->zShort[1] = 0; + pStack->flags = MEM_Str | MEM_Short | MEM_Term; + pStack->z = pStack->zShort; + pStack->n = (enc==TEXT_Utf8?1:2); + }else{ + /* For a Real or Integer, use sqlite3_snprintf() to produce the UTF-8 + ** string representation of the value. Then, if the required encoding + ** is UTF-16le or UTF-16be do a translation. + ** + ** FIX ME: It would be better if sqlite3_snprintf() could do UTF-16. + */ + if( fg & MEM_Real ){ + sqlite3_snprintf(NBFS, pStack->zShort, "%.15g", pStack->r); + }else if( fg & MEM_Int ){ + sqlite3_snprintf(NBFS, pStack->zShort, "%lld", pStack->i); + } + pStack->n = strlen(pStack->zShort) + 1; + pStack->z = pStack->zShort; + pStack->flags = MEM_Str | MEM_Short | MEM_Term; + + /* Flip the string to UTF-16 if required */ + SetEncodingFlags(pStack, TEXT_Utf8); + rc = SetEncoding(pStack, encToFlags(enc)|MEM_Term); + } + + return rc; +} + + /* ** Convert the given stack entity into a string that has been obtained ** from sqliteMalloc(). This is different from Stringify() above in that @@ -312,12 +342,13 @@ int SetEncoding(Mem *pMem, int flags){ ** will fit but this routine always mallocs for space. ** Return non-zero if we run out of memory. */ -#define Dynamicify(P) (((P)->flags & MEM_Dyn)==0 ? hardDynamicify(P):0) -static int hardDynamicify(Mem *pStack){ +#define Dynamicify(P, enc) \ +(((P)->flags & MEM_Dyn)==0 ? hardDynamicify(P, enc):0) +static int hardDynamicify(Mem *pStack, u8 enc){ int fg = pStack->flags; char *z; if( (fg & MEM_Str)==0 ){ - hardStringify(pStack); + hardStringify(pStack, enc); } assert( (fg & MEM_Dyn)==0 ); z = sqliteMallocRaw( pStack->n ); @@ -328,6 +359,31 @@ static int hardDynamicify(Mem *pStack){ return 0; } +/* +** An ephemeral string value (signified by the MEM_Ephem flag) contains +** a pointer to a dynamically allocated string where some other entity +** is responsible for deallocating that string. Because the stack entry +** does not control the string, it might be deleted without the stack +** entry knowing it. +** +** This routine converts an ephemeral string into a dynamically allocated +** string that the stack entry itself controls. In other words, it +** converts an MEM_Ephem string into an MEM_Dyn string. +*/ +#define Deephemeralize(P) \ + if( ((P)->flags&MEM_Ephem)!=0 && hardDeephem(P) ){ goto no_mem;} +static int hardDeephem(Mem *pStack){ + char *z; + assert( (pStack->flags & MEM_Ephem)!=0 ); + z = sqliteMallocRaw( pStack->n ); + if( z==0 ) return 1; + memcpy(z, pStack->z, pStack->n); + pStack->z = z; + pStack->flags &= ~MEM_Ephem; + pStack->flags |= MEM_Dyn; + return 0; +} + /* ** Advance the virtual machine to the next output row. ** @@ -470,30 +526,39 @@ const unsigned char *sqlite3_column_data(sqlite3_stmt *pStmt, int i){ } pVal = &pVm->pTos[(1-vals)+i]; - SetEncodingFlags(pVal, pVm->db->enc); return sqlite3_value_data((sqlite3_value *)pVal); } +/* +** pVal is a Mem* cast to an sqlite_value* value. Return a pointer to +** the nul terminated UTF-8 string representation if the value is +** not a blob or NULL. If the value is a blob, then just return a pointer +** to the blob of data. If it is a NULL, return a NULL pointer. +** +** This function may translate the encoding of the string stored by +** pVal. The MEM_Utf8, MEM_Utf16le and MEM_Utf16be flags must be set +** correctly when this function is called. If a translation occurs, +** the flags are set to reflect the new encoding of the string. +** +** If a translation fails because of a malloc() failure, a NULL pointer +** is returned. +*/ const unsigned char *sqlite3_value_data(sqlite3_value* pVal){ if( pVal->flags&MEM_Null ){ + /* For a NULL return a NULL Pointer */ return 0; } - if( !(pVal->flags&MEM_Blob) ){ - if( pVal->flags&MEM_Str && !(pVal->flags&MEM_Utf8) ){ - char *z = 0; - int n; - u8 enc = flagsToEnc(pVal->flags); - if( sqlite3utfTranslate(pVal->z,pVal->n,enc,(void **)&z,&n,TEXT_Utf8) ){ - return 0; - } - Release(pVal); - pVal->z = z; - pVal->n = n; - SetEncodingFlags(pVal, TEXT_Utf8); - }else{ - Stringify(pVal); - } + + if( pVal->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); } + return pVal->z; } @@ -513,20 +578,43 @@ const void *sqlite3_column_data16(sqlite3_stmt *pStmt, int i){ } 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 +** to the blob of data. If it is a NULL, return a NULL pointer. +** +** The byte-order of the returned string data is the machines native byte +** order. +** +** This function may translate the encoding of the string stored by +** pVal. The MEM_Utf8, MEM_Utf16le and MEM_Utf16be flags must be set +** correctly when this function is called. If a translation occurs, +** the flags are set to reflect the new encoding of the string. +** +** If a translation fails because of a malloc() failure, a NULL pointer +** is returned. +*/ +const void *sqlite3_value_data16(sqlite3_value* pVal){ if( pVal->flags&MEM_Null ){ + /* For a NULL return a NULL Pointer */ return 0; } - if( !(pVal->flags&MEM_Blob) ){ - Stringify(pVal); - if( SQLITE3_BIGENDIAN ){ - /* SetEncoding(pVal, MEM_Utf16be|MEM_Term); */ - }else{ - /* SetEncoding(pVal, MEM_Utf16le|MEM_Term); */ - } + if( pVal->flags&MEM_Str ){ + /* If there is already a string representation, make sure it is in + ** encoded in UTF-16 machine byte order. + */ + 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); } - return pVal->z; + return (const void *)(pVal->z); } /* @@ -573,7 +661,7 @@ long long int sqlite3_column_int(sqlite3_stmt *pStmt, int i){ } pVal = &pVm->pTos[(1-vals)+i]; - Integerify(pVal); + Integerify(pVal, pVm->db->enc); return pVal->i; } @@ -593,7 +681,7 @@ double sqlite3_column_float(sqlite3_stmt *pStmt, int i){ } pVal = &pVm->pTos[(1-vals)+i]; - Realify(pVal); + Realify(pVal, pVm->db->enc); return pVal->r; } @@ -717,6 +805,273 @@ const void *sqlite3_column_decltype16(sqlite3_stmt *pStmt, int i){ return columnName16(pStmt, i, 1); } +/* +** Unbind the value bound to variable $i in virtual machine p. This is the +** the same as binding a NULL value to the column. If the "i" parameter is +** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. +** +** The error code stored in database p->db is overwritten with the return +** value in any case. +*/ +static int vdbeUnbind(Vdbe *p, int i){ + Mem *pVar; + if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){ + sqlite3Error(p->db, SQLITE_MISUSE, 0); + return SQLITE_MISUSE; + } + if( i<1 || i>p->nVar ){ + sqlite3Error(p->db, SQLITE_RANGE, 0); + return SQLITE_RANGE; + } + i--; + pVar = &p->apVar[i]; + if( pVar->flags&MEM_Dyn ){ + sqliteFree(pVar->z); + } + pVar->flags = MEM_Null; + sqlite3Error(p->db, SQLITE_OK, 0); + return SQLITE_OK; +} + +/* +** This routine is used to bind text or blob data to an SQL variable (a ?). +** It may also be used to bind a NULL value, by setting zVal to 0. Any +** existing value is unbound. +** +** The error code stored in p->db is overwritten with the return value in +** all cases. +*/ +static int vdbeBindBlob( + Vdbe *p, /* Virtual machine */ + int i, /* Var number to bind (numbered from 1 upward) */ + const char *zVal, /* Pointer to blob of data */ + int bytes, /* Number of bytes to copy */ + int copy, /* True to copy the memory, false to copy a pointer */ + int flags /* Valid combination of MEM_Blob, MEM_Str, MEM_Term */ +){ + Mem *pVar; + int rc; + + rc = vdbeUnbind(p, i); + if( rc!=SQLITE_OK ){ + return rc; + } + pVar = &p->apVar[i-1]; + + if( zVal ){ + pVar->n = bytes; + pVar->flags = flags; + if( !copy ){ + pVar->z = (char *)zVal; + pVar->flags |= MEM_Static; + }else{ + if( bytes>NBFS ){ + pVar->z = (char *)sqliteMalloc(bytes); + if( !pVar->z ){ + sqlite3Error(p->db, SQLITE_NOMEM, 0); + return SQLITE_NOMEM; + } + pVar->flags |= MEM_Dyn; + }else{ + pVar->z = pVar->zShort; + pVar->flags |= MEM_Short; + } + memcpy(pVar->z, zVal, bytes); + } + } + + return SQLITE_OK; +} + +/* +** Bind a 64 bit integer to an SQL statement variable. +*/ +int sqlite3_bind_int64(sqlite3_stmt *p, int i, long long int iValue){ + int rc; + Vdbe *v = (Vdbe *)p; + rc = vdbeUnbind(v, i); + if( rc==SQLITE_OK ){ + Mem *pVar = &v->apVar[i-1]; + pVar->flags = MEM_Int; + pVar->i = iValue; + } + return rc; +} + +/* +** Bind a 32 bit integer to an SQL statement variable. +*/ +int sqlite3_bind_int32(sqlite3_stmt *p, int i, int iValue){ + return sqlite3_bind_int64(p, i, (long long int)iValue); +} + +/* +** Bind a double (real) to an SQL statement variable. +*/ +int sqlite3_bind_double(sqlite3_stmt *p, int i, double iValue){ + int rc; + Vdbe *v = (Vdbe *)p; + rc = vdbeUnbind(v, i); + if( rc==SQLITE_OK ){ + Mem *pVar = &v->apVar[i-1]; + pVar->flags = MEM_Real; + pVar->r = iValue; + } + return SQLITE_OK; +} + +/* +** Bind a NULL value to an SQL statement variable. +*/ +int sqlite3_bind_null(sqlite3_stmt* p, int i){ + return vdbeUnbind((Vdbe *)p, i); +} + +/* +** Bind a UTF-8 text value to an SQL statement variable. +*/ +int sqlite3_bind_text( + sqlite3_stmt *pStmt, + int i, + const char *zData, + int nData, + int eCopy +){ + Mem *pVar; + Vdbe *p = (Vdbe *)pStmt; + int rc = SQLITE_OK; + u8 db_enc = p->db->enc; /* Text encoding of the database */ + + /* Unbind any previous variable value */ + rc = vdbeUnbind(p, i); + if( rc==SQLITE_OK ){ + pVar = &p->apVar[i-1]; + + if( !zData ){ + /* If zData is NULL, then bind an SQL NULL value */ + pVar->flags = MEM_Null; + }else{ + if( zData && nData<0 ){ + nData = strlen(zData) + 1; + } + pVar->z = (char *)zData; + pVar->n = nData; + pVar->flags = MEM_Utf8|MEM_Str|(zData[nData-1]?0:MEM_Term); + if( !eCopy || db_enc!=TEXT_Utf8 ){ + pVar->flags |= MEM_Static; + rc = SetEncoding(pVar, encToFlags(db_enc)|MEM_Term); + }else{ + pVar->flags |= MEM_Ephem; + Deephemeralize(pVar); + } + } + } + + sqlite3Error(p->db, rc, 0); + return rc; + +no_mem: + sqlite3Error(p->db, SQLITE_NOMEM, 0); + return SQLITE_NOMEM; +} + +/* +** Bind a UTF-16 text value to an SQL statement variable. +*/ +int sqlite3_bind_text16( + sqlite3_stmt *pStmt, + int i, + const void *zData, + int nData, + int eCopy +){ + Vdbe *p = (Vdbe *)pStmt; + Mem *pVar; + u8 db_enc = p->db->enc; /* Text encoding of the database */ + u8 txt_enc; + int null_term = 0; + int rc; + + rc = vdbeUnbind(p, i); + if( rc!=SQLITE_OK ){ + return rc; + } + pVar = &p->apVar[i-1]; + + /* If zData is NULL, then bind an SQL NULL value */ + if( !zData ){ + pVar->flags = MEM_Null; + return SQLITE_OK; + } + + if( db_enc==TEXT_Utf8 ){ + /* If the database encoding is UTF-8, then do a translation. */ + pVar->z = sqlite3utf16to8(zData, nData, SQLITE3_BIGENDIAN); + if( !pVar->z ) return SQLITE_NOMEM; + pVar->n = strlen(pVar->z)+1; + pVar->flags = MEM_Str|MEM_Term|MEM_Dyn; + return SQLITE_OK; + } + + /* There may or may not be a byte order mark at the start of the UTF-16. + ** Either way set 'txt_enc' to the TEXT_Utf16* value indicating the + ** actual byte order used by this string. If the string does happen + ** to contain a BOM, then move zData so that it points to the first + ** byte after the BOM. + */ + txt_enc = sqlite3UtfReadBom(zData, nData); + if( txt_enc ){ + zData = (void *)(((u8 *)zData) + 2); + }else{ + txt_enc = SQLITE3_BIGENDIAN?TEXT_Utf16be:TEXT_Utf16le; + } + + if( nData<0 ){ + nData = sqlite3utf16ByteLen(zData, -1) + 2; + null_term = 1; + }else if( nData>1 && !((u8*)zData)[nData-1] && !((u8*)zData)[nData-2] ){ + null_term = 1; + } + + if( db_enc==txt_enc && !eCopy ){ + /* If the byte order of the string matches the byte order of the + ** database and the eCopy parameter is not set, then the string can + ** be used without making a copy. + */ + pVar->z = (char *)zData; + pVar->n = nData; + pVar->flags = MEM_Str|MEM_Static|(null_term?MEM_Term:0); + }else{ + /* Make a copy. Swap the byte order if required */ + pVar->n = nData + (null_term?0:2); + pVar->z = sqliteMalloc(pVar->n); + pVar->flags = MEM_Str|MEM_Dyn|MEM_Term; + if( db_enc==txt_enc ){ + memcpy(pVar->z, zData, nData); + }else{ + swab(zData, pVar->z, nData); + } + pVar->z[pVar->n-1] = '\0'; + pVar->z[pVar->n-2] = '\0'; + } + + return SQLITE_OK; +} + +/* +** Bind a blob value to an SQL statement variable. +*/ +int sqlite3_bind_blob( + sqlite3_stmt *p, + int i, + const void *zData, + int nData, + int eCopy +){ + return vdbeBindBlob((Vdbe *)p, i, zData, nData, eCopy, MEM_Blob); +} + + /* ** Insert a new aggregate element and make it the element that ** has focus. @@ -759,31 +1114,6 @@ static AggElem *_AggInFocus(Agg *p){ return pElem ? sqliteHashData(pElem) : 0; } -/* -** An ephemeral string value (signified by the MEM_Ephem flag) contains -** a pointer to a dynamically allocated string where some other entity -** is responsible for deallocating that string. Because the stack entry -** does not control the string, it might be deleted without the stack -** entry knowing it. -** -** This routine converts an ephemeral string into a dynamically allocated -** string that the stack entry itself controls. In other words, it -** converts an MEM_Ephem string into an MEM_Dyn string. -*/ -#define Deephemeralize(P) \ - if( ((P)->flags&MEM_Ephem)!=0 && hardDeephem(P) ){ goto no_mem;} -static int hardDeephem(Mem *pStack){ - char *z; - assert( (pStack->flags & MEM_Ephem)!=0 ); - z = sqliteMallocRaw( pStack->n ); - if( z==0 ) return 1; - memcpy(z, pStack->z, pStack->n); - pStack->z = z; - pStack->flags &= ~MEM_Ephem; - pStack->flags |= MEM_Dyn; - return 0; -} - /* ** Pop the stack N times. */ @@ -888,7 +1218,7 @@ static int expandCursorArraySize(Vdbe *p, int mxCursor){ ** SQLITE_AFF_INTEGER ** */ -static void applyAffinity(Mem *pRec, char affinity){ +static void applyAffinity(Mem *pRec, char affinity, u8 enc){ switch( affinity ){ case SQLITE_AFF_INTEGER: case SQLITE_AFF_NUMERIC: @@ -898,11 +1228,11 @@ static void applyAffinity(Mem *pRec, char affinity){ ** it looks like a number. */ int realnum; - if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum) ){ + if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum, enc) ){ if( realnum ){ - Realify(pRec); + Realify(pRec, enc); }else{ - Integerify(pRec); + Integerify(pRec, enc); } } } @@ -924,7 +1254,7 @@ static void applyAffinity(Mem *pRec, char affinity){ ** representation. */ if( 0==(pRec->flags&MEM_Str) && (pRec->flags&(MEM_Real|MEM_Int)) ){ - Stringify(pRec); + Stringify(pRec, enc); } pRec->flags &= ~(MEM_Real|MEM_Int); @@ -997,8 +1327,8 @@ void prettyPrintMem(Mem *pMem, char *zBuf, int nBuf){ zBuf[k++] = '['; for(j=0; j<15 && jn; j++){ u8 c = pMem->z[j]; - if( c==0 && j==pMem->n-1 ) break; /* + if( c==0 && j==pMem->n-1 ) break; zBuf[k++] = "0123456789ABCDEF"[c>>4]; zBuf[k++] = "0123456789ABCDEF"[c&0xf]; */ @@ -1359,7 +1689,7 @@ case OP_String: { */ if( op==OP_Real ){ assert( z ); - assert( sqlite3IsNumber(z, 0) ); + assert( sqlite3IsNumber(z, 0, TEXT_Utf8) ); pTos->r = sqlite3AtoF(z, 0); pTos->flags = MEM_Real; }else if( op==OP_Integer ){ @@ -1600,6 +1930,7 @@ case OP_ColumnName: { ** 3rd parameter. */ case OP_Callback: { +#if 0 int i; char **azArgv = p->zArgv; Mem *pCol; @@ -1610,16 +1941,25 @@ case OP_Callback: { if( pCol->flags & MEM_Null ){ azArgv[i] = 0; }else{ - Stringify(pCol); + Stringify(pCol, db->enc); azArgv[i] = pCol->z; } } - p->resOnStack = 1; azArgv[i] = 0; p->azResColumn = azArgv; - p->nCallback++; +#endif + + int i; assert( p->nResColumn==pOp->p1 ); + + for(i=0; ip1; i++){ + Mem *pVal = &pTos[0-i]; + SetEncodingFlags(pVal, db->enc); + } + + p->resOnStack = 1; + p->nCallback++; p->popStack = pOp->p1; p->pc = pc + 1; p->pTos = pTos; @@ -1643,55 +1983,83 @@ case OP_Concat: { int nByte; int nField; int i, j; - char *zSep; - int nSep; Mem *pTerm; + Mem zSep; /* Memory cell containing the seperator string, if any */ + int termLen; /* Bytes in the terminator character for this encoding */ + termLen = (db->enc==TEXT_Utf8?1:2); + + /* FIX ME: Eventually, P3 will be in database native encoding. But for + ** now it is always UTF-8. So set up zSep to hold the native encoding of + ** P3. + */ + if( pOp->p3 ){ + zSep.z = pOp->p3; + zSep.n = strlen(zSep.z)+1; + zSep.flags = MEM_Str|MEM_Static|MEM_Utf8|MEM_Term; + SetEncoding(&zSep, encToFlags(db->enc)|MEM_Term); + }else{ + zSep.flags = MEM_Null; + zSep.n = 0; + } + + /* Loop through the stack elements to see how long the result will be. */ nField = pOp->p1; - zSep = pOp->p3; - if( zSep==0 ) zSep = ""; - nSep = strlen(zSep); - assert( &pTos[1-nField] >= p->aStack ); - nByte = 1 - nSep; pTerm = &pTos[1-nField]; + nByte = termLen + (nField-1)*(zSep.n - ((zSep.flags&MEM_Term)?termLen:0)); for(i=0; iflags & MEM_Null ){ + assert( pOp->p2==0 || (pTerm->flags&MEM_Str) ); + if( pTerm->flags&MEM_Null ){ nByte = -1; break; - }else{ - Stringify(pTerm); - nByte += pTerm->n - 1 + nSep; } + Stringify(pTerm, db->enc); + nByte += (pTerm->n - ((pTerm->flags&MEM_Term)?termLen:0)); } + if( nByte<0 ){ + /* If nByte is less than zero, then there is a NULL value on the stack. + ** In this case just pop the values off the stack (if required) and + ** push on a NULL. + */ if( pOp->p2==0 ){ popStack(&pTos, nField); } pTos++; pTos->flags = MEM_Null; - break; - } - zNew = sqliteMallocRaw( nByte ); - if( zNew==0 ) goto no_mem; - j = 0; - pTerm = &pTos[1-nField]; - for(i=j=0; iflags & MEM_Str ); - memcpy(&zNew[j], pTerm->z, pTerm->n-1); - j += pTerm->n-1; - if( nSep>0 && in-((pTerm->flags&MEM_Term)?termLen:0); + assert( pTerm->flags & MEM_Str ); + memcpy(&zNew[j], pTerm->z, n); + j += n; + if( ip2==0 ){ + popStack(&pTos, nField); + } + pTos++; + pTos->n = nByte; + pTos->flags = MEM_Str|MEM_Dyn|MEM_Term|encToFlags(db->enc); + pTos->z = zNew; } - zNew[j] = 0; - if( pOp->p2==0 ){ - popStack(&pTos, nField); - } - pTos++; - pTos->n = nByte; - pTos->flags = MEM_Str|MEM_Dyn|MEM_Utf8|MEM_Term; - pTos->z = zNew; break; } @@ -1779,8 +2147,8 @@ case OP_Remainder: { pTos->flags = MEM_Int; }else{ double a, b; - Realify(pTos); - Realify(pNos); + Realify(pTos, db->enc); + Realify(pNos, db->enc); a = pTos->r; b = pNos->r; switch( pOp->opcode ){ @@ -1836,8 +2204,12 @@ case OP_Function: { for(i=0; iflags & MEM_Null ){ azArgv[i] = 0; + }else if( !(pArg->flags&MEM_Str) ){ + Stringify(pArg, TEXT_Utf8); + azArgv[i] = pArg->z; }else{ - Stringify(pArg); + SetEncodingFlags(pArg, db->enc); + SetEncoding(pArg, MEM_Utf8|MEM_Term); azArgv[i] = pArg->z; } } @@ -1863,6 +2235,12 @@ case OP_Function: { (pTos->flags & MEM_Str)!=0 ? pTos->z : "user function error", (char*)0); rc = SQLITE_ERROR; } + + if( pTos->flags&MEM_Str ){ + SetEncodingFlags(pTos, TEXT_Utf8); + SetEncoding(pTos, encToFlags(db->enc)|MEM_Term); + } + break; } @@ -1908,8 +2286,8 @@ case OP_ShiftRight: { pTos->flags = MEM_Null; break; } - Integerify(pTos); - Integerify(pNos); + Integerify(pTos, db->enc); + Integerify(pNos, db->enc); a = pTos->i; b = pNos->i; switch( pOp->opcode ){ @@ -1919,8 +2297,14 @@ case OP_ShiftRight: { case OP_ShiftRight: a >>= b; break; default: /* CANT HAPPEN */ break; } + /* FIX ME: Because constant P3 values sometimes need to be translated, + ** the following assert() can fail. When P3 is always in the native text + ** encoding, this assert() will be valid again. Until then, the Release() + ** is neeed instead. assert( (pTos->flags & MEM_Dyn)==0 ); assert( (pNos->flags & MEM_Dyn)==0 ); + */ + Release(pTos); pTos--; Release(pTos); pTos->i = a; @@ -1937,7 +2321,7 @@ case OP_ShiftRight: { */ case OP_AddImm: { assert( pTos>=p->aStack ); - Integerify(pTos); + Integerify(pTos, db->enc); pTos->i += pOp->p1; break; } @@ -1955,8 +2339,8 @@ case OP_AddImm: { case OP_ForceInt: { int v; assert( pTos>=p->aStack ); - if( (pTos->flags & (MEM_Int|MEM_Real))==0 - && ((pTos->flags & MEM_Str)==0 || sqlite3IsNumber(pTos->z, 0)==0) ){ + if( (pTos->flags & (MEM_Int|MEM_Real))==0 && ((pTos->flags & MEM_Str)==0 + || sqlite3IsNumber(pTos->z, 0, db->enc)==0) ){ Release(pTos); pTos--; pc = pOp->p2 - 1; @@ -1965,7 +2349,7 @@ case OP_ForceInt: { if( pTos->flags & MEM_Int ){ v = pTos->i + (pOp->p1!=0); }else{ - Realify(pTos); + Realify(pTos, db->enc); v = (int)pTos->r; if( pTos->r>(double)v ) v++; if( pOp->p1 && pTos->r==(double)v ) v++; @@ -2000,12 +2384,12 @@ case OP_MustBeInt: { pTos->i = i; }else if( pTos->flags & MEM_Str ){ i64 v; - if( !sqlite3atoi64(pTos->z, &v) ){ + if( !sqlite3atoi64(pTos->z, &v, db->enc) ){ double r; - if( !sqlite3IsNumber(pTos->z, 0) ){ + if( !sqlite3IsNumber(pTos->z, 0, db->enc) ){ goto mismatch; } - Realify(pTos); + Realify(pTos, db->enc); v = (int)pTos->r; r = (double)v; if( r!=pTos->r ){ @@ -2119,8 +2503,8 @@ case OP_Ge: { affinity = (pOp->p1>>8)&0xFF; if( affinity=='\0' ) affinity = 'n'; - applyAffinity(pNos, affinity); - applyAffinity(pTos, affinity); + applyAffinity(pNos, affinity, db->enc); + applyAffinity(pTos, affinity, db->enc); assert( pOp->p3type==P3_COLLSEQ || pOp->p3==0 ); res = sqlite3MemCompare(pNos, pTos, (CollSeq*)pOp->p3); @@ -2167,13 +2551,13 @@ case OP_Or: { if( pTos->flags & MEM_Null ){ v1 = 2; }else{ - Integerify(pTos); + Integerify(pTos, db->enc); v1 = pTos->i==0; } if( pNos->flags & MEM_Null ){ v2 = 2; }else{ - Integerify(pNos); + Integerify(pNos, db->enc); v2 = pNos->i==0; } if( pOp->opcode==OP_And ){ @@ -2224,7 +2608,7 @@ case OP_AbsValue: { }else if( pTos->flags & MEM_Null ){ /* Do nothing */ }else{ - Realify(pTos); + Realify(pTos, db->enc); Release(pTos); if( pOp->opcode==OP_Negative || pTos->r<0.0 ){ pTos->r = -pTos->r; @@ -2243,7 +2627,7 @@ case OP_AbsValue: { case OP_Not: { assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ - Integerify(pTos); + Integerify(pTos, db->enc); Release(pTos); pTos->i = !pTos->i; pTos->flags = MEM_Int; @@ -2259,7 +2643,7 @@ case OP_Not: { case OP_BitNot: { assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ - Integerify(pTos); + Integerify(pTos, db->enc); Release(pTos); pTos->i = ~pTos->i; pTos->flags = MEM_Int; @@ -2302,11 +2686,17 @@ case OP_IfNot: { if( pTos->flags & MEM_Null ){ c = pOp->p1; }else{ - Integerify(pTos); + Integerify(pTos, db->enc); c = pTos->i; if( pOp->opcode==OP_IfNot ) c = !c; } - assert( (pTos->flags & MEM_Dyn)==0 ); + /* FIX ME: Because constant P3 values sometimes need to be translated, + ** the following assert() can fail. When P3 is always in the native text + ** encoding, this assert() will be valid again. Until then, the Release() + ** is neeed instead. + assert( (pTos->flags & MEM_Dyn)==0 ); + */ + Release(pTos); pTos--; if( c ) pc = pOp->p2-1; break; @@ -2369,25 +2759,44 @@ case OP_Class: { struct { int mask; char * zClass; + char * zClass16; } classes[] = { - {MEM_Null, "NULL"}, - {MEM_Int, "INTEGER"}, - {MEM_Real, "REAL"}, - {MEM_Str, "TEXT"}, - {MEM_Blob, "BLOB"} + {MEM_Null, "NULL", "\0N\0U\0L\0L\0\0\0"}, + {MEM_Int, "INTEGER", "\0I\0N\0T\0E\0G\0E\0R\0\0\0"}, + {MEM_Real, "REAL", "\0R\0E\0A\0L\0\0\0"}, + {MEM_Str, "TEXT", "\0T\0E\0X\0T\0\0\0"}, + {MEM_Blob, "BLOB", "\0B\0L\0O\0B\0\0\0"} }; Release(pTos); - pTos->flags = MEM_Str|MEM_Static|MEM_Utf8|MEM_Term; + pTos->flags = MEM_Str|MEM_Static|MEM_Term; for(i=0; i<5; i++){ if( classes[i].mask&flags ){ - pTos->z = classes[i].zClass; + switch( db->enc ){ + case TEXT_Utf8: + pTos->z = classes[i].zClass; + break; + case TEXT_Utf16be: + pTos->z = classes[i].zClass16; + break; + case TEXT_Utf16le: + pTos->z = &(classes[i].zClass16[1]); + break; + default: + assert(0); + } break; } } assert( i<5 ); - pTos->n = strlen(classes[i].zClass); + + if( db->enc==TEXT_Utf8 ){ + pTos->n = strlen(pTos->z) + 1; + }else{ + pTos->n = sqlite3utf16ByteLen(pTos->z, -1) + 2; + } + break; } @@ -2663,7 +3072,7 @@ case OP_MakeRecord: { for(pRec=pData0; pRec<=pTos; pRec++){ u64 serial_type; if( zAffinity ){ - applyAffinity(pRec, zAffinity[pRec-pData0]); + applyAffinity(pRec, zAffinity[pRec-pData0], db->enc); } serial_type = sqlite3VdbeSerialType(pRec); nBytes += sqlite3VdbeSerialTypeLen(serial_type); @@ -2783,7 +3192,7 @@ case OP_MakeIdxKey: { for(pRec=pData0; pRec<=pTos; pRec++){ u64 serial_type; if( zAffinity ){ - applyAffinity(pRec, zAffinity[pRec-pData0]); + applyAffinity(pRec, zAffinity[pRec-pData0], db->enc); } if( pRec->flags&MEM_Null ){ containsNull = 1; @@ -2800,7 +3209,7 @@ case OP_MakeIdxKey: { if( addRowid ){ pRec = &pTos[0-nField]; assert( pRec>=p->aStack ); - Integerify(pRec); + Integerify(pRec, db->enc); rowid = pRec->i; nByte += sqlite3VarintLen(rowid); nByte++; @@ -3020,7 +3429,7 @@ case OP_SetCookie: { assert( pOp->p1>=0 && pOp->p1nDb ); assert( db->aDb[pOp->p1].pBt!=0 ); assert( pTos>=p->aStack ); - Integerify(pTos); + Integerify(pTos, db->enc); /* See note about index shifting on OP_ReadCookie */ rc = sqlite3BtreeUpdateMeta(db->aDb[pOp->p1].pBt, 1+pOp->p2, (int)pTos->i); Release(pTos); @@ -3108,7 +3517,7 @@ case OP_OpenWrite: { Cursor *pCur; assert( pTos>=p->aStack ); - Integerify(pTos); + Integerify(pTos, db->enc); iDb = pTos->i; pTos--; assert( iDb>=0 && iDbnDb ); @@ -3117,7 +3526,7 @@ case OP_OpenWrite: { wrFlag = pOp->opcode==OP_OpenWrite; if( p2<=0 ){ assert( pTos>=p->aStack ); - Integerify(pTos); + Integerify(pTos, db->enc); p2 = pTos->i; pTos--; if( p2<2 ){ @@ -3334,7 +3743,7 @@ case OP_MoveGt: { if( pC->intKey ){ i64 iKey; assert( !pOp->p3 ); - Integerify(pTos); + Integerify(pTos, db->enc); iKey = intToKey(pTos->i); if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ pC->movetoTarget = iKey; @@ -3347,7 +3756,7 @@ case OP_MoveGt: { pC->lastRecno = pTos->i; pC->recnoIsValid = res==0; }else{ - Stringify(pTos); + Stringify(pTos, db->enc); sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); pC->recnoIsValid = 0; } @@ -3428,7 +3837,7 @@ case OP_Found: { if( (pC = p->apCsr[i])->pCursor!=0 ){ int res, rx; assert( pC->intKey==0 ); - Stringify(pTos); + Stringify(pTos, db->enc); rx = sqlite3BtreeMoveto(pC->pCursor, pTos->z, pTos->n, &res); alreadyExists = rx==SQLITE_OK && res==0; pC->deferredMoveto = 0; @@ -3477,7 +3886,7 @@ case OP_IsUnique: { /* Pop the value R off the top of the stack */ assert( pNos>=p->aStack ); - Integerify(pTos); + Integerify(pTos, db->enc); R = pTos->i; pTos--; assert( i>=0 && i<=p->nCursor ); @@ -3492,7 +3901,7 @@ case OP_IsUnique: { /* Make sure K is a string and make zKey point to K */ - Stringify(pNos); + Stringify(pNos, db->enc); zKey = pNos->z; nKey = pNos->n; @@ -3731,7 +4140,7 @@ case OP_PutStrKey: { i64 nKey; i64 iKey; if( pOp->opcode==OP_PutStrKey ){ - Stringify(pNos); + Stringify(pNos, db->enc); nKey = pNos->n; zKey = pNos->z; }else{ @@ -4380,7 +4789,7 @@ case OP_IdxGE: { if( (pCrsr = (pC = p->apCsr[i])->pCursor)!=0 ){ int res, rc; - Stringify(pTos); + Stringify(pTos, db->enc); assert( pC->deferredMoveto==0 ); *pC->pIncrKey = pOp->p3!=0; assert( pOp->p3==0 || pOp->opcode!=OP_IdxGT ); @@ -4558,11 +4967,15 @@ case OP_IntegrityCk: { if( z ) sqliteFree(z); pTos->z = "ok"; pTos->n = 3; - pTos->flags = MEM_Utf8 | MEM_Str | MEM_Static; + pTos->flags = MEM_Str | MEM_Static; }else{ pTos->z = z; pTos->n = strlen(z) + 1; - pTos->flags = MEM_Utf8 | MEM_Str | MEM_Dyn; + pTos->flags = MEM_Str | MEM_Dyn; + } + if( db->enc!=TEXT_Utf8 ){ + SetEncodingFlags(pTos, TEXT_Utf8); + SetEncoding(pTos, encToFlags(db->enc)|MEM_Term); } sqliteFree(aRoot); break; @@ -4586,7 +4999,7 @@ case OP_ListWrite: { pKeylist->pNext = p->pList; p->pList = pKeylist; } - Integerify(pTos); + Integerify(pTos, db->enc); pKeylist->aKey[pKeylist->nUsed++] = pTos->i; Release(pTos); pTos--; @@ -4733,7 +5146,7 @@ case OP_SortPut: { Mem *pNos = &pTos[-1]; Sorter *pSorter; assert( pNos>=p->aStack ); - if( Dynamicify(pTos) || Dynamicify(pNos) ) goto no_mem; + if( Dynamicify(pTos, db->enc) || Dynamicify(pNos, db->enc) ) goto no_mem; pSorter = sqliteMallocRaw( sizeof(Sorter) ); if( pSorter==0 ) goto no_mem; pSorter->pNext = p->pSort; @@ -4987,6 +5400,7 @@ case OP_FileColumn: { pTos->n = strlen(z) + 1; pTos->z = z; pTos->flags = MEM_Utf8 | MEM_Str | MEM_Ephem | MEM_Term; + SetEncoding(pTos, encToFlags(db->enc)|MEM_Term); }else{ pTos->flags = MEM_Null; } @@ -5143,7 +5557,9 @@ case OP_AggFunc: { if( pRec->flags & MEM_Null ){ azArgv[i] = 0; }else{ - Stringify(pRec); + Stringify(pRec, db->enc); + SetEncodingFlags(pRec, db->enc); + SetEncoding(pRec, MEM_Utf8|MEM_Term); azArgv[i] = pRec->z; } } @@ -5186,7 +5602,7 @@ case OP_AggFocus: { int nKey; assert( pTos>=p->aStack ); - Stringify(pTos); + Stringify(pTos, db->enc); zKey = pTos->z; nKey = pTos->n; pElem = sqlite3HashFind(&p->agg.hash, zKey, nKey); @@ -5223,6 +5639,8 @@ case OP_AggSet: { }else if( pMem->flags & MEM_Short ){ pMem->z = pMem->zShort; } + SetEncodingFlags(pMem, db->enc); + SetEncoding(pMem, MEM_Utf8|MEM_Term); Release(pTos); pTos--; break; @@ -5247,6 +5665,10 @@ case OP_AggGet: { pTos->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); pTos->flags |= MEM_Ephem; } + if( pTos->flags&MEM_Str ){ + SetEncodingFlags(pTos, TEXT_Utf8); + SetEncoding(pTos, encToFlags(db->enc)|MEM_Term); + } break; } diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 4e40f2e54f..53ed63093d 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1059,242 +1059,6 @@ int sqlite3VdbeFinalize(Vdbe *p, char **pzErrMsg){ return rc; } -/* -** Unbind the value bound to variable $i in virtual machine p. This is the -** the same as binding a NULL value to the column. If the "i" parameter is -** out of range, then SQLITE_RANGE is returned. Othewise SQLITE_OK. -** -** The error code stored in database p->db is overwritten with the return -** value in any case. -*/ -static int vdbeUnbind(Vdbe *p, int i){ - Mem *pVar; - if( p->magic!=VDBE_MAGIC_RUN || p->pc!=0 ){ - sqlite3Error(p->db, SQLITE_MISUSE, 0); - return SQLITE_MISUSE; - } - if( i<1 || i>p->nVar ){ - sqlite3Error(p->db, SQLITE_RANGE, 0); - return SQLITE_RANGE; - } - i--; - pVar = &p->apVar[i]; - if( pVar->flags&MEM_Dyn ){ - sqliteFree(pVar->z); - } - pVar->flags = MEM_Null; - sqlite3Error(p->db, SQLITE_OK, 0); - return SQLITE_OK; -} - -/* -** This routine is used to bind text or blob data to an SQL variable (a ?). -** It may also be used to bind a NULL value, by setting zVal to 0. Any -** existing value is unbound. -** -** The error code stored in p->db is overwritten with the return value in -** all cases. -*/ -static int vdbeBindBlob( - Vdbe *p, /* Virtual machine */ - int i, /* Var number to bind (numbered from 1 upward) */ - const char *zVal, /* Pointer to blob of data */ - int bytes, /* Number of bytes to copy */ - int copy, /* True to copy the memory, false to copy a pointer */ - int flags /* Valid combination of MEM_Blob, MEM_Str, MEM_Term */ -){ - Mem *pVar; - int rc; - - rc = vdbeUnbind(p, i); - if( rc!=SQLITE_OK ){ - return rc; - } - pVar = &p->apVar[i-1]; - - if( zVal ){ - pVar->n = bytes; - pVar->flags = flags; - if( !copy ){ - pVar->z = (char *)zVal; - pVar->flags |= MEM_Static; - }else{ - if( bytes>NBFS ){ - pVar->z = (char *)sqliteMalloc(bytes); - if( !pVar->z ){ - sqlite3Error(p->db, SQLITE_NOMEM, 0); - return SQLITE_NOMEM; - } - pVar->flags |= MEM_Dyn; - }else{ - pVar->z = pVar->zShort; - pVar->flags |= MEM_Short; - } - memcpy(pVar->z, zVal, bytes); - } - } - - return SQLITE_OK; -} - -/* -** Bind a 64 bit integer to an SQL statement variable. -*/ -int sqlite3_bind_int64(sqlite3_stmt *p, int i, long long int iValue){ - int rc; - Vdbe *v = (Vdbe *)p; - rc = vdbeUnbind(v, i); - if( rc==SQLITE_OK ){ - Mem *pVar = &v->apVar[i-1]; - pVar->flags = MEM_Int; - pVar->i = iValue; - } - return rc; -} - -/* -** Bind a 32 bit integer to an SQL statement variable. -*/ -int sqlite3_bind_int32(sqlite3_stmt *p, int i, int iValue){ - return sqlite3_bind_int64(p, i, (long long int)iValue); -} - -/* -** Bind a double (real) to an SQL statement variable. -*/ -int sqlite3_bind_double(sqlite3_stmt *p, int i, double iValue){ - int rc; - Vdbe *v = (Vdbe *)p; - rc = vdbeUnbind(v, i); - if( rc==SQLITE_OK ){ - Mem *pVar = &v->apVar[i-1]; - pVar->flags = MEM_Real; - pVar->r = iValue; - } - return SQLITE_OK; -} - -/* -** Bind a NULL value to an SQL statement variable. -*/ -int sqlite3_bind_null(sqlite3_stmt* p, int i){ - return vdbeUnbind((Vdbe *)p, i); -} - -/* -** Bind a UTF-8 text value to an SQL statement variable. -*/ -int sqlite3_bind_text( - sqlite3_stmt *p, - int i, - const char *zData, - int nData, - int eCopy -){ - int flags = MEM_Str|MEM_Utf8; - if( zData ){ - if( nData<0 ){ - nData = strlen(zData)+1; - flags |= MEM_Term; - }else if( !zData[nData-1] ){ - flags |= MEM_Term; - } - } - return vdbeBindBlob((Vdbe *)p, i, zData, nData, eCopy, flags); -} - -/* -** Bind a UTF-16 text value to an SQL statement variable. -*/ -int sqlite3_bind_text16( - sqlite3_stmt *pStmt, - int i, - const void *zData, - int nData, - int eCopy -){ - Vdbe *p = (Vdbe *)pStmt; - Mem *pVar; - u8 db_enc = p->db->enc; /* Text encoding of the database */ - u8 txt_enc; - int null_term = 0; - - int flags; - int rc; - - rc = vdbeUnbind(p, i); - if( rc!=SQLITE_OK ){ - return rc; - } - pVar = &p->apVar[i-1]; - - if( db_enc==TEXT_Utf8 ){ - /* If the database encoding is UTF-8, then do a translation. */ - pVar->z = sqlite3utf16to8(zData, nData, SQLITE3_BIGENDIAN); - if( !pVar->z ) return SQLITE_NOMEM; - pVar->n = strlen(pVar->z)+1; - pVar->flags = MEM_Str|MEM_Term|MEM_Dyn; - return SQLITE_OK; - } - - /* There may or may not be a byte order mark at the start of the UTF-16. - ** Either way set 'txt_enc' to the TEXT_Utf16* value indicating the - ** actual byte order used by this string. If the string does happen - ** to contain a BOM, then move zData so that it points to the first - ** byte after the BOM. - */ - txt_enc = sqlite3UtfReadBom(zData, nData); - if( txt_enc ){ - zData = (void *)(((u8 *)zData) + 2); - }else{ - txt_enc = SQLITE3_BIGENDIAN?TEXT_Utf16be:TEXT_Utf16le; - } - - if( nData<0 ){ - nData = sqlite3utf16ByteLen(zData, -1) + 2; - null_term = 1; - }else if( nData>1 && !((u8*)zData)[nData-1] && !((u8*)zData)[nData-2] ){ - null_term = 1; - } - - if( db_enc==txt_enc && !eCopy ){ - /* If the byte order of the string matches the byte order of the - ** database and the eCopy parameter is not set, then the string can - ** be used without making a copy. - */ - pVar->z = (char *)zData; - pVar->n = nData; - pVar->flags = MEM_Str|MEM_Static|(null_term?MEM_Term:0); - }else{ - /* Make a copy. Swap the byte order if required */ - pVar->n = nData + (null_term?0:2); - pVar->z = sqliteMalloc(pVar->n); - pVar->flags = MEM_Str|MEM_Dyn|MEM_Term; - if( db_enc==txt_enc ){ - memcpy(pVar->z, zData, nData); - }else{ - swab(zData, pVar->z, nData); - } - pVar->z[pVar->n-1] = '\0'; - pVar->z[pVar->n-2] = '\0'; - } - - return SQLITE_OK; -} - -/* -** Bind a blob value to an SQL statement variable. -*/ -int sqlite3_bind_blob( - sqlite3_stmt *p, - int i, - const void *zData, - int nData, - int eCopy -){ - return vdbeBindBlob((Vdbe *)p, i, zData, nData, eCopy, MEM_Blob); -} - /* ** Set the values of all variables. Variable $1 in the original SQL will ** be the string azValue[0]. $2 will have the value azValue[1]. And