From eb2e176a12238ecfdc1fe02841611ce848c4e038 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 27 May 2004 01:53:56 +0000 Subject: [PATCH] More MEM changes in the vdbe.c. Still will not compile. (CVS 1469) FossilOrigin-Name: dbdd1a7f316e576d0611748ec63c9ef00d4c10db --- main.mk | 13 +- manifest | 34 ++-- manifest.uuid | 2 +- src/sqliteInt.h | 4 +- src/utf.c | 14 +- src/util.c | 14 +- src/vdbe.c | 219 +++++------------------ src/vdbeInt.h | 7 + src/vdbeapi.c | 44 +++++ src/vdbeaux.c | 460 ++++-------------------------------------------- src/vdbemem.c | 409 +++++++++++++++++++++++------------------- test/bind.test | 4 +- test/enc2.test | 10 +- 13 files changed, 403 insertions(+), 831 deletions(-) diff --git a/main.mk b/main.mk index 00479d5596..def00e9668 100644 --- a/main.mk +++ b/main.mk @@ -58,8 +58,9 @@ LIBOBJ = attach.o auth.o btree.o build.o copy.o date.o delete.o \ expr.o func.o hash.o insert.o \ main.o opcodes.o os_mac.o os_unix.o os_win.o \ pager.o parse.o pragma.o printf.o random.o \ - select.o table.o tokenize.o trigger.o update.o util.o \ - vacuum.o vdbe.o vdbeaux.o where.o tclsqlite.o utf.o legacy.o + select.o table.o tokenize.o trigger.o update.o util.o vacuum.o \ + vdbe.o vdbeapi.o vdbeaux.o vdbemem.o \ + where.o tclsqlite.o utf.o legacy.o # All of the source code files. # @@ -102,7 +103,9 @@ SRC = \ $(TOP)/src/vacuum.c \ $(TOP)/src/vdbe.c \ $(TOP)/src/vdbe.h \ + $(TOP)/src/vdbeapi.c \ $(TOP)/src/vdbeaux.c \ + $(TOP)/src/vdbemem.c \ $(TOP)/src/vdbeInt.h \ $(TOP)/src/where.c @@ -327,9 +330,15 @@ vacuum.o: $(TOP)/src/vacuum.c $(HDR) vdbe.o: $(TOP)/src/vdbe.c $(VDBEHDR) $(TCCX) -c $(TOP)/src/vdbe.c +vdbeapi.o: $(TOP)/src/vdbeapi.c $(VDBEHDR) + $(TCCX) -c $(TOP)/src/vdbeapi.c + vdbeaux.o: $(TOP)/src/vdbeaux.c $(VDBEHDR) $(TCCX) -c $(TOP)/src/vdbeaux.c +vdbemem.o: $(TOP)/src/vdbemem.c $(VDBEHDR) + $(TCCX) -c $(TOP)/src/vdbemem.c + where.o: $(TOP)/src/where.c $(HDR) $(TCCX) -c $(TOP)/src/where.c diff --git a/manifest b/manifest index 8cd5d8f99a..a5e58214cc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C More\stest\scases\sfor\sthe\snew\squery\sAPI.\s(CVS\s1468) -D 2004-05-27T01:49:51 +C More\sMEM\schanges\sin\sthe\svdbe.c.\s\sStill\swill\snot\scompile.\s(CVS\s1469) +D 2004-05-27T01:53:56 F Makefile.in ab7b0d5118e2da97bac66be8684a1034e3500f5a F Makefile.linux-gcc b86a99c493a5bfb402d1d9178dcdc4bd4b32f906 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -16,7 +16,7 @@ F doc/lemon.html f0f682f50210928c07e562621c3b7e8ab912a538 F doc/report1.txt a031aaf37b185e4fa540223cb516d3bccec7eeac F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 F ltmain.sh f6b283068efa69f06eb8aa1fe4bddfdbdeb35826 -F main.mk bbbe8057c8fac1ec03af0a41f2fac5390dd30386 +F main.mk 466f12b816527d5bb1cf5dac4f23da77a02f99ad F publish.sh 1cd5c982388560fa91eedf6a338e210f713b35c8 F spec.template a38492f1c1dd349fc24cb0565e08afc53045304b F sqlite.1 83f4a9d37bdf2b7ef079a82d54eaf2e3509ee6ea @@ -56,7 +56,7 @@ F src/random.c eff68e3f257e05e81eae6c4d50a51eb88beb4ff3 F src/select.c e90e2a147273cdcdb1ee9e14574ab28f04382e63 F src/shell.c ed4d237b3e52a0a42512bfcc53530e46de20c28f F src/sqlite.h.in 68e165dc4dc2d477c95c76b9ede13eed5fbaabf4 -F src/sqliteInt.h 6b0d8d856c4af325eb5a00d1c32d89aacf432875 +F src/sqliteInt.h dbf4fd06e89cdab13f4f1129d76bf79a38ec2b39 F src/table.c af14284fa36c8d41f6829e3f2819dce07d3e2de2 F src/tclsqlite.c 86daf7bf6ba715bf0f0c7a47beb1d947a15cb868 F src/test1.c ff7cc8729c320aec038e7d9d116bed9eabd642d0 @@ -67,15 +67,15 @@ F src/test5.c 9a1f15133f6955f067c5246e564723b5f23ff221 F src/tokenize.c e7536dd31205d5afb76c1bdc832dea009c7a3847 F src/trigger.c 11afe9abfba13a2ba142944c797c952e162d117f F src/update.c 96461bcf4e946697e83c09c77c7e61b545a2f66e -F src/utf.c 1d38da85bffb928fb0d9f301e7db913a6df486ce -F src/util.c 4c0adcbc9ce6678dd046931253e45d623c6d279f +F src/utf.c 73d70f2764cb34b072e2d7b0f0c23c389cfc1baa +F src/util.c caef24dcf3d7dfb7ac747ed36c080d95457fac71 F src/vacuum.c 8734f89742f246abd91dbd3e087fc153bddbfbad -F src/vdbe.c 4419d3b7e4d56b0c1d973ebf4de40ee5045e612e +F src/vdbe.c 06f02181b5fe39b99cb98714bf36e95005e03ef7 F src/vdbe.h e73f890e0f2a6c42b183d7d6937947930fe4fdeb -F src/vdbeInt.h 8647afb4c3889c827a4c0aa310a54c5ec0ebc934 -F src/vdbeapi.c 36d4c78bc765dc89cac07ff975b26256e0ac90fc -F src/vdbeaux.c 677317be4021eadce96365b16d9deeda9e565bef -F src/vdbemem.c c92c41c80c333b3cd405a08ebfd014d02a9f7b8c +F src/vdbeInt.h d62f70eb935bf056d9eb7dfb9783393274685e1d +F src/vdbeapi.c 56b7de7af5800fbbf79fd953da95ee61c379a387 +F src/vdbeaux.c de2d82e4cf5815595ae74bd5f663042428efb6a8 +F src/vdbemem.c 3474db5cdb19a8aa1b1e8e78189e1e8cda2394aa F src/where.c efe5d25fe18cd7381722457898cd863e84097a0c F test/all.test 569a92a8ee88f5300c057cc4a8f50fbbc69a3242 F test/attach.test cb9b884344e6cfa5e165965d5b1adea679a24c83 @@ -83,7 +83,7 @@ F test/attach2.test 5472d442bb2ef1ee587e0ae7472bb68b52509a38 F test/auth.test 5c4d95cdaf539c0c236e20ce1f71a93e7dde9185 F test/bigfile.test ea904b853ce2d703b16c5ce90e2b54951bc1ae81 F test/bigrow.test 8ab252dba108f12ad64e337b0f2ff31a807ac578 -F test/bind.test 44097e9a885ac851934c2e9b74d2fec36659bca5 +F test/bind.test ef1efd5cf63b27c11acda9a1c0c7403960f12400 F test/btree.test 08e4093c78d2bc1d54e27266f8d17fed14751125 F test/btree2.test aa4a6d05b1ea90b1acaf83ba89039dd302a88635 F test/btree4.test 3797b4305694c7af6828675b0f4b1424b8ca30e4 @@ -97,7 +97,7 @@ F test/crashtest1.c 09c1c7d728ccf4feb9e481671e29dda5669bbcc2 F test/date.test aed5030482ebc02bd8d386c6c86a29f694ab068d F test/delete.test 92256384f1801760180ded129f7427884cf28886 F test/enc.test a55481d45ff493804e8d88357feb4642fc50a6b2 -F test/enc2.test f80bcf14a286f34e54378b9b044c5d93b7679bc1 +F test/enc2.test 669f46b4e298a22fb515cb52c55eb8dca57d8b4a F test/expr.test 8b62f3fcac64fbd5c3d43d7a7984245743dcbe65 F test/fkey1.test d65c824459916249bee501532d6154ddab0b5db7 F test/format3.test 149cc166c97923fa60def047e90dd3fb32bba916 @@ -205,7 +205,7 @@ F www/sqlite.tcl 3c83b08cf9f18aa2d69453ff441a36c40e431604 F www/tclsqlite.tcl b9271d44dcf147a93c98f8ecf28c927307abd6da F www/vdbe.tcl 9b9095d4495f37697fd1935d10e14c6015e80aa1 F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P d72adf0c522b442d5e1663862bdd639c282d4495 -R 2ba0c044593753a501ecb5b9d1ce6722 -U danielk1977 -Z 64c9fdf3b1584f065ec0b7238e3a9f4f +P 74097ecdb0b1e0eec143c5a3f8ca2f0d63d6f38d +R 98aa4ae2a65faf4f8c17b075955c2246 +U drh +Z eb27f7bb480c5083f24dd280c1f9cf51 diff --git a/manifest.uuid b/manifest.uuid index e14ac09a84..698e80ef2b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -74097ecdb0b1e0eec143c5a3f8ca2f0d63d6f38d \ No newline at end of file +dbdd1a7f316e576d0611748ec63c9ef00d4c10db \ No newline at end of file diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e23710e78c..4b4b825f94 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.253 2004/05/26 16:54:45 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.254 2004/05/27 01:53:56 drh Exp $ */ #include "config.h" #include "sqlite.h" @@ -1347,7 +1347,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*, u8); +int sqlite3atoi64(const char*, i64*); 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/utf.c b/src/utf.c index 6f9dff106c..b8e11d8da0 100644 --- a/src/utf.c +++ b/src/utf.c @@ -12,7 +12,7 @@ ** This file contains routines used to translate between UTF-8, ** UTF-16, UTF-16BE, and UTF-16LE. ** -** $Id: utf.c,v 1.10 2004/05/24 12:39:02 danielk1977 Exp $ +** $Id: utf.c,v 1.11 2004/05/27 01:53:56 drh Exp $ ** ** Notes on UTF-8: ** @@ -579,12 +579,10 @@ void sqlite3utf16to16be(void *pData, int N){ ** result is returned in dynamically allocated memory. */ int sqlite3utfTranslate( - const void *zData, - int nData, - u8 enc1, - void **zOut, - int *nOut, - u8 enc2 + const void *zData, int nData, /* Input string */ + u8 enc1, /* Encoding of zData */ + void **zOut, int *nOut, /* Output string */ + u8 enc2 /* Desired encoding of output */ ){ assert( enc1==TEXT_Utf8 || enc1==TEXT_Utf16le || enc1==TEXT_Utf16be ); assert( enc2==TEXT_Utf8 || enc2==TEXT_Utf16le || enc2==TEXT_Utf16be ); @@ -608,5 +606,3 @@ int sqlite3utfTranslate( } return SQLITE_OK; } - - diff --git a/src/util.c b/src/util.c index b3744e23c7..0d1a5b9748 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.88 2004/05/24 07:04:26 danielk1977 Exp $ +** $Id: util.c,v 1.89 2004/05/27 01:53:56 drh Exp $ */ #include "sqliteInt.h" #include @@ -665,27 +665,23 @@ 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, u8 enc){ +int sqlite3atoi64(const char *zNum, i64 *pNum){ 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 += incr; + zNum++; }else if( *zNum=='+' ){ neg = 0; - zNum += incr; + zNum++; }else{ neg = 0; } - for(i=0; (c=zNum[i])>='0' && c<='9'; i += incr){ + for(i=0; (c=zNum[i])>='0' && c<='9'; i++){ 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)); } diff --git a/src/vdbe.c b/src/vdbe.c index c5f75a9daa..dbcab5066b 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.336 2004/05/26 23:25:31 drh Exp $ +** $Id: vdbe.c,v 1.337 2004/05/27 01:53:56 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -69,105 +69,18 @@ int sqlite3_search_count = 0; */ int sqlite3_interrupt_count = 0; -/* -** This macro takes a single parameter, a pointer to a Mem structure. -** It returns the string encoding for the Mem structure, one of TEXT_Utf8 -** TEXT_Utf16le or TEXT_Utf16be. -*/ -#define MemEnc(p) ( \ - ((p)->flags&MEM_Utf16le)?TEXT_Utf16le: \ - ((p)->flags&MEM_Utf16be)?TEXT_Utf16be:TEXT_Utf8) ) - /* ** 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); } -/* -** Parmameter "flags" is the value of the flags for a string Mem object. -** Return one of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be, depending -** on the encoding indicated by the flags value. -*/ -static u8 flagsToEnc(int flags){ - if( flags&MEM_Utf8 ){ - assert( !(flags&(MEM_Utf16be|MEM_Utf16le)) ); - return TEXT_Utf8; - } - if( flags&MEM_Utf16le ){ - assert( !(flags&(MEM_Utf8|MEM_Utf16be)) ); - return TEXT_Utf16le; - } - assert( flags&MEM_Utf16be ); - assert( !(flags&(MEM_Utf8|MEM_Utf16le)) ); - return TEXT_Utf16be; -} - -/* -** Parameter "enc" is one of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be. -** Return the corresponding MEM_Utf* value. -*/ -static int encToFlags(u8 enc){ - switch( enc ){ - case TEXT_Utf8: return MEM_Utf8; - case TEXT_Utf16be: return MEM_Utf16be; - case TEXT_Utf16le: return MEM_Utf16le; - } - assert(0); -} - -/* -** Set the encoding flags of memory cell "pMem" to the correct values -** 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)) -static int SetEncoding(Mem*, int); - /* ** 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; -} + (!((P)->flags&(MEM_Str|MEM_Blob)) && sqlite3VdbeMemStringify(P,enc)) /* ** Convert the given stack entity into a string that has been obtained @@ -176,22 +89,8 @@ static int hardStringify(Mem *pStack, u8 enc){ ** will fit but this routine always mallocs for space. ** Return non-zero if we run out of memory. */ -#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, enc); - } - assert( (fg & MEM_Dyn)==0 ); - z = sqliteMallocRaw( pStack->n ); - if( z==0 ) return 1; - memcpy(z, pStack->z, pStack->n); - pStack->z = z; - pStack->flags |= MEM_Dyn; - return 0; -} +#define Dynamicify(P,enc) sqlite3VdbeMemDynamicify(P) + /* ** An ephemeral string value (signified by the MEM_Ephem flag) contains @@ -205,18 +104,8 @@ static int hardDynamicify(Mem *pStack, u8 enc){ ** 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; -} + if( ((P)->flags&MEM_Ephem)!=0 \ + && sqlite3VdbeMemMakeWriteable(P) ){ goto no_mem;} /* ** Convert the given stack entity into a integer if it isn't one @@ -226,19 +115,7 @@ static int hardDeephem(Mem *pStack){ ** 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; -} + if((P)->flags!=MEM_Int){ sqlite3VdbeMemIntegerify(P); } /* ** Get a valid Real representation for the given stack element. @@ -246,21 +123,8 @@ static void hardIntegerify(Mem *pStack, u8 enc){ ** 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; -} - +#define Realify(P,enc) \ + if(((P)->flags&MEM_Real)==0){ sqlite3VdbeMemRealify(P); } /* @@ -1158,29 +1022,26 @@ case OP_Concat: { int nField; int i, j; 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); + Mem mSep; /* Memory cell containing the seperator string, if any */ /* 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); + mSep.z = pOp->p3; + mSep.n = strlen(mSep.z); + mSep.flags = MEM_Str|MEM_Static|MEM_Term; + mSep.enc = TEXT_Utf8; + sqlite3VdbeChangeEncoding(&mSep, db->enc); }else{ - zSep.flags = MEM_Null; - zSep.n = 0; + mSep.flags = MEM_Null; } /* Loop through the stack elements to see how long the result will be. */ nField = pOp->p1; pTerm = &pTos[1-nField]; - nByte = termLen + (nField-1)*(zSep.n - ((zSep.flags&MEM_Term)?termLen:0)); + nByte = (nField-1)*mSep.n; for(i=0; ip2==0 || (pTerm->flags&MEM_Str) ); if( pTerm->flags&MEM_Null ){ @@ -1188,7 +1049,7 @@ case OP_Concat: { break; } Stringify(pTerm, db->enc); - nByte += (pTerm->n - ((pTerm->flags&MEM_Term)?termLen:0)); + nByte += pTerm->n; } if( nByte<0 ){ @@ -1205,33 +1066,32 @@ case OP_Concat: { /* Otherwise malloc() space for the result and concatenate all the ** stack values. */ - zNew = sqliteMallocRaw( nByte ); + zNew = sqliteMallocRaw( nByte+2 ); if( zNew==0 ) goto no_mem; j = 0; pTerm = &pTos[1-nField]; for(i=j=0; in-((pTerm->flags&MEM_Term)?termLen:0); + int n = pTerm->n; 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->n = j; + pTos->flags = MEM_Str|MEM_Dyn|MEM_Term + pTos->enc = db->enc; + pTos->type = SQLITE3_TEXT; pTos->z = zNew; } break; @@ -1553,12 +1413,16 @@ case OP_MustBeInt: { pTos->i = i; }else if( pTos->flags & MEM_Str ){ i64 v; - if( !sqlite3atoi64(pTos->z, &v, db->enc) ){ + if( sqlite3VdbeChangeEncoding(pTos, TEXT_Utf8) + || sqlite3VdbeNulTerminate(pTos) ){ + goto no_mem; + } + if( !sqlite3atoi64(pTos->z, &v) ){ double r; - if( !sqlite3IsNumber(pTos->z, 0, db->enc) ){ + if( !sqlite3IsNumber(pTos->z, 0, TEXT_Utf8) ){ goto mismatch; } - Realify(pTos, db->enc); + Realify(pTos, TEXT_Utf8); v = (int)pTos->r; r = (double)v; if( r!=pTos->r ){ @@ -1571,6 +1435,7 @@ case OP_MustBeInt: { } Release(pTos); pTos->flags = MEM_Int; + pTos->type = SQLITE3_INTEGER; break; mismatch: @@ -4385,11 +4250,9 @@ case OP_SortNext: { pTos++; pTos->z = pSorter->pData; pTos->n = pSorter->nData; - /* FIX ME: I don't understand this. What does the sorter return? - ** I thought it would be the commented out flags. - */ - /* pTos->flags = MEM_Blob|MEM_Dyn; */ - pTos->flags = MEM_Str|MEM_Dyn|MEM_Utf8|MEM_Term; + pTos->flags = MEM_Blob|MEM_Dyn|MEM_Term; + pTos->enc = 0; + pTos->type = SQLITE3_BLOB; sqliteFree(pSorter->zKey); sqliteFree(pSorter); }else{ diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 599cb341fd..9dc55c24b5 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -356,3 +356,10 @@ int sqlite3VdbeSetEncoding(Mem *, u8); int sqlite3VdbeMemCopy(Mem*, const Mem*); int sqlite3VdbeMemNulTerminate(Mem *); int sqlite3VdbeMemSetStr(Mem*, const char*, int, u8, int); +int sqlite3VdbeMemSetInt64(Mem*, long long int); +int sqlite3VdbeMemSetDouble(Mem*, double); +int sqlite3VdbeMemMakeWriteable(Mem*); +int sqlite3VdbeMemDynamicify(Mem*); +int sqlite3VdbeMemStringify(Mem*); +int sqlite3VdbeMemIntegerify(Mem*); +int sqlite3VdbeMemRealify(Mem*); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index 1a5e86c65f..d21eb17308 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -198,6 +198,50 @@ int sqlite3_step(sqlite3_stmt *pStmt){ return rc; } +/* +** Extract the user data from a sqlite3_context structure and return a +** pointer to it. +*/ +void *sqlite3_user_data(sqlite3_context *p){ + assert( p && p->pFunc ); + return p->pFunc->pUserData; +} + +/* +** Allocate or return the aggregate context for a user function. A new +** context is allocated on the first call. Subsequent calls return the +** same context that was returned on prior calls. +** +** This routine is defined here in vdbe.c because it depends on knowing +** the internals of the sqlite3_context structure which is only defined in +** this source file. +*/ +void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ + assert( p && p->pFunc && p->pFunc->xStep ); + if( p->pAgg==0 ){ + if( nByte<=NBFS ){ + p->pAgg = (void*)p->s.z; + memset(p->pAgg, 0, nByte); + }else{ + p->pAgg = sqliteMalloc( nByte ); + } + } + return p->pAgg; +} + +/* +** Return the number of times the Step function of a aggregate has been +** called. +** +** This routine is defined here in vdbe.c because it depends on knowing +** the internals of the sqlite3_context structure which is only defined in +** this source file. +*/ +int sqlite3_aggregate_count(sqlite3_context *p){ + assert( p && p->pFunc && p->pFunc->xStep ); + return p->cnt; +} + /* ** Return the number of columns in the result set for the statement pStmt. */ diff --git a/src/vdbeaux.c b/src/vdbeaux.c index fd72c25ba5..256ec2b3d0 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -109,7 +109,7 @@ int sqlite3VdbeAddOp(Vdbe *p, int op, int p1, int p2){ /* ** Add an opcode that includes the p3 value. */ -int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3, int p3type){ +int sqlite3VdbeOp3(Vdbe *p, int op, int p1, int p2, const char *zP3,int p3type){ int addr = sqlite3VdbeAddOp(p, op, p1, p2); sqlite3VdbeChangeP3(p, addr, zP3, p3type); return addr; @@ -424,50 +424,6 @@ VdbeOp *sqlite3VdbeGetOp(Vdbe *p, int addr){ return &p->aOp[addr]; } -/* -** Extract the user data from a sqlite3_context structure and return a -** pointer to it. -*/ -void *sqlite3_user_data(sqlite3_context *p){ - assert( p && p->pFunc ); - return p->pFunc->pUserData; -} - -/* -** Allocate or return the aggregate context for a user function. A new -** context is allocated on the first call. Subsequent calls return the -** same context that was returned on prior calls. -** -** This routine is defined here in vdbe.c because it depends on knowing -** the internals of the sqlite3_context structure which is only defined in -** this source file. -*/ -void *sqlite3_aggregate_context(sqlite3_context *p, int nByte){ - assert( p && p->pFunc && p->pFunc->xStep ); - if( p->pAgg==0 ){ - if( nByte<=NBFS ){ - p->pAgg = (void*)p->s.z; - memset(p->pAgg, 0, nByte); - }else{ - p->pAgg = sqliteMalloc( nByte ); - } - } - return p->pAgg; -} - -/* -** Return the number of times the Step function of a aggregate has been -** called. -** -** This routine is defined here in vdbe.c because it depends on knowing -** the internals of the sqlite3_context structure which is only defined in -** this source file. -*/ -int sqlite3_aggregate_count(sqlite3_context *p){ - assert( p && p->pFunc && p->pFunc->xStep ); - return p->cnt; -} - /* ** Compute a string that describes the P3 parameter for an opcode. ** Use zTemp for any required temporary buffer space. @@ -613,23 +569,36 @@ int sqlite3VdbeList( sqlite3SetString(&p->zErrMsg, sqlite3_error_string(p->rc), (char*)0); }else{ Op *pOp = &p->aOp[i]; - p->aStack[0].flags = MEM_Int; - p->aStack[0].i = i; /* Program counter */ - p->aStack[1].flags = MEM_Static|MEM_Str|MEM_Utf8|MEM_Term; - p->aStack[1].z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */ - p->aStack[2].flags = MEM_Int; - p->aStack[2].i = pOp->p1; /* P1 */ - p->aStack[3].flags = MEM_Int; - p->aStack[3].i = pOp->p2; /* P2 */ - p->aStack[4].flags = MEM_Str|MEM_Utf8|MEM_Term; /* P3 */ - p->aStack[4].z = displayP3(pOp, p->aStack[4].zShort, NBFS); - if( p->aStack[4].z==p->aStack[4].zShort ){ - p->aStack[4].flags |= MEM_Short; - }else{ - p->aStack[4].flags |= MEM_Static; - } + Mem *pMem = p->aStack; + pMem->flags = MEM_Int; + pMem->type = SQLITE3_INT; + pMem->i = i; /* Program counter */ + pMem++; + + pMem->flags = MEM_Static|MEM_Str|MEM_Term; + pMem->z = sqlite3OpcodeNames[pOp->opcode]; /* Opcode */ + pMem->n = strlen(pMem->z); + pMem->type = SQLITE3_TEXT; + pMem->enc = TEXT_Utf8; + pMem++; + + pMem->flags = MEM_Int; + pMem->i = pOp->p1; /* P1 */ + pMem->type = SQLITE3_INT; + pMem++; + + pMem->flags = MEM_Int; + pMem->i = pOp->p2; /* P2 */ + pMem->type = SQLITE_INT; + pMem++; + + pMem->flags = MEM_Short|MEM_Str|MEM_Term; /* P3 */ + pMem->z = displayP3(pOp, pMem->zShort, sizeof(pMem->zShort)); + pMem->type = SQLITE_TEXT; + pMem->enc = TEXT_Utf8; + p->nResColumn = 5; - p->pTos = &p->aStack[4]; + p->pTos = pMem; p->rc = SQLITE_OK; p->resOnStack = 1; rc = SQLITE_ROW; @@ -1184,15 +1153,6 @@ u64 sqlite3VdbeSerialType(Mem *pMem){ if( flags&MEM_Str ){ int n = pMem->n; assert( n>=0 ); - if( pMem->flags&MEM_Term ){ - /* If the nul terminated flag is set we have to subtract something - ** from the serial-type. Depending on the encoding there could be - ** one or two 0x00 bytes at the end of the string. Check for these - ** and subtract 2 from serial_ - */ - if( n>0 && !pMem->z[n-1] ) n--; - if( n>0 && !pMem->z[n-1] ) n--; - } return ((n*2) + 13); } if( flags&MEM_Blob ){ @@ -1279,6 +1239,7 @@ int sqlite3VdbeSerialGet( /* NULL */ if( serial_type==6 ){ pMem->flags = MEM_Null; + pMem->type = SQLITE3_NULL; return 0; } @@ -1297,9 +1258,11 @@ int sqlite3VdbeSerialGet( if( serial_type==5 ){ pMem->flags = MEM_Real; pMem->r = *(double*)&v; + pMem->type = SQLITE3_FLOAT; }else{ pMem->flags = MEM_Int; pMem->i = *(i64*)&v; + pMem->type = SQLITE3_INTEGER; } return len; } @@ -1308,136 +1271,16 @@ int sqlite3VdbeSerialGet( assert( serial_type>=12 ); len = sqlite3VdbeSerialTypeLen(serial_type); if( serial_type&0x01 ){ - switch( enc ){ - case TEXT_Utf8: - pMem->flags = MEM_Str|MEM_Utf8|MEM_Term; - break; - case TEXT_Utf16le: - pMem->flags = MEM_Str|MEM_Utf16le|MEM_Term; - break; - case TEXT_Utf16be: - pMem->flags = MEM_Str|MEM_Utf16be|MEM_Term; - break; - assert(0); - } - pMem->n = len+(enc==TEXT_Utf8?1:2); + pMem->flags = MEM_Str | MEM_Ephem; + pMem->n = len; }else{ - pMem->flags = MEM_Blob; + pMem->flags = MEM_Blob | MEM_Ephem; pMem->n = len; } - - if( (pMem->n)>NBFS ){ - pMem->z = sqliteMallocRaw( pMem->n ); - if( !pMem->z ){ - return -1; - } - pMem->flags |= MEM_Dyn; - }else{ - pMem->z = pMem->zShort; - pMem->flags |= MEM_Short; - } - - memcpy(pMem->z, buf, len); - if( pMem->flags&MEM_Str ){ - pMem->z[len] = '\0'; - if( enc!=TEXT_Utf8 ){ - pMem->z[len+1] = '\0'; - } - } - + sqlite3VdbeMemMakeWriteable(pMem); return len; } -/* -** Compare the values contained by the two memory cells, returning -** negative, zero or positive if pMem1 is less than, equal to, or greater -** than pMem2. Sorting order is NULL's first, followed by numbers (integers -** and reals) sorted numerically, followed by text ordered by the collating -** sequence pColl and finally blob's ordered by memcmp(). -** -** Two NULL values are considered equal by this function. -*/ -int sqlite3MemCompare(const Mem *pMem1, const Mem *pMem2, const CollSeq *pColl){ - int rc; - int f1, f2; - int combined_flags; - - /* Interchange pMem1 and pMem2 if the collating sequence specifies - ** DESC order. - */ - f1 = pMem1->flags; - f2 = pMem2->flags; - combined_flags = f1|f2; - - /* If one value is NULL, it is less than the other. If both values - ** are NULL, return 0. - */ - if( combined_flags&MEM_Null ){ - return (f2&MEM_Null) - (f1&MEM_Null); - } - - /* If one value is a number and the other is not, the number is less. - ** If both are numbers, compare as reals if one is a real, or as integers - ** if both values are integers. - */ - if( combined_flags&(MEM_Int|MEM_Real) ){ - if( !(f1&(MEM_Int|MEM_Real)) ){ - return 1; - } - if( !(f2&(MEM_Int|MEM_Real)) ){ - return -1; - } - if( (f1 & f2 & MEM_Int)==0 ){ - double r1, r2; - if( (f1&MEM_Real)==0 ){ - r1 = pMem1->i; - }else{ - r1 = pMem1->r; - } - if( (f2&MEM_Real)==0 ){ - r2 = pMem2->i; - }else{ - r2 = pMem2->r; - } - if( r1r2 ) return 1; - return 0; - }else{ - assert( f1&MEM_Int ); - assert( f2&MEM_Int ); - if( pMem1->i < pMem2->i ) return -1; - if( pMem1->i > pMem2->i ) return 1; - return 0; - } - } - - /* If one value is a string and the other is a blob, the string is less. - ** If both are strings, compare using the collating functions. - */ - if( combined_flags&MEM_Str ){ - if( (f1 & MEM_Str)==0 ){ - return 1; - } - if( (f2 & MEM_Str)==0 ){ - return -1; - } - if( pColl && pColl->xCmp ){ - return pColl->xCmp(pColl->pUser, pMem1->n, pMem1->z, pMem2->n, pMem2->z); - }else{ - /* If no collating sequence is defined, fall through into the - ** blob case below and use memcmp() for the comparison. */ - } - } - - /* Both values must be blobs. Compare using memcmp(). - */ - rc = memcmp(pMem1->z, pMem2->z, (pMem1->n>pMem2->n)?pMem2->n:pMem1->n); - if( rc==0 ){ - rc = pMem1->n - pMem2->n; - } - return rc; -} - /* ** The following is the comparison function for (non-integer) ** keys in the btrees. This function returns negative, zero, or @@ -1703,232 +1546,3 @@ int sqlite3VdbeIdxKeyCompare( } return SQLITE_OK; } - -/* -** Parameter "enc" is one of TEXT_Utf8, TEXT_Utf16le or TEXT_Utf16be. -** Return the corresponding MEM_Utf* value. -*/ -static int encToFlags(u8 enc){ - switch( enc ){ - case TEXT_Utf8: return MEM_Utf8; - case TEXT_Utf16be: return MEM_Utf16be; - case TEXT_Utf16le: return MEM_Utf16le; - } - assert(0); -} -static u8 flagsToEnc(int flags){ - switch( flags&(MEM_Utf8|MEM_Utf16be|MEM_Utf16le) ){ - case MEM_Utf8: return TEXT_Utf8; - case MEM_Utf16le: return TEXT_Utf16le; - case MEM_Utf16be: return TEXT_Utf16be; - } - return 0; -} - -/* -** Delete any previous value and set the value stored in *pMem to NULL. -*/ -void sqlite3VdbeMemSetNull(Mem *pMem){ - if( pMem->flags&MEM_Dyn ){ - sqliteFree(pMem->z); - } - pMem->flags = MEM_Null; -} - -/* -** Delete any previous value and set the value stored in *pMem to val, -** manifest type INTEGER. -*/ -void sqlite3VdbeMemSetInt(Mem *pMem, i64 val){ - MemSetNull(pMem); - pMem->i = val; - pMem->flags = MEM_Int; -} - -/* -** Delete any previous value and set the value stored in *pMem to val, -** manifest type REAL. -*/ -void sqlite3VdbeMemSetReal(Mem *pMem, double val){ - MemSetNull(pMem); - pMem->r = val; - pMem->flags = MEM_Real; -} - -/* -** Copy the contents of memory cell pFrom into pTo. -*/ -int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ - if( pTo->flags&MEM_Dyn ){ - sqliteFree(pTo->z); - } - - memcpy(pTo, pFrom, sizeof(*pFrom)); - if( pTo->flags&MEM_Short ){ - pTo->z = pTo->zShort; - } - else if( pTo->flags&(MEM_Ephem|MEM_Dyn) ){ - pTo->flags = pTo->flags&(~(MEM_Static|MEM_Ephem|MEM_Short|MEM_Dyn)); - if( pTo->n>NBFS ){ - pTo->z = sqliteMalloc(pTo->n); - if( !pTo->z ) return SQLITE_NOMEM; - pTo->flags |= MEM_Dyn; - }else{ - pTo->z = pTo->zShort; - pTo->flags |= MEM_Short; - } - memcpy(pTo->z, pFrom->z, pTo->n); - } - return SQLITE_OK; -} - -int sqlite3VdbeMemSetStr( - Mem *pMem, /* Memory cell to set to string value */ - const char *z, /* String pointer */ - int n, /* Bytes in string, or negative */ - u8 enc, /* Encoding of z */ - int eCopy /* True if this function should make a copy of z */ -){ - Mem tmp; - - if( !z ){ - /* If z is NULL, just set *pMem to contain NULL. */ - MemSetNull(pMem); - return SQLITE_OK; - } - - tmp.z = (char *)z; - if( eCopy ){ - tmp.flags = MEM_Ephem|MEM_Str; - }else{ - tmp.flags = MEM_Static|MEM_Str; - } - tmp.flags |= encToFlags(enc); - tmp.n = n; - switch( enc ){ - case 0: - tmp.flags |= MEM_Blob; - break; - - case TEXT_Utf8: - tmp.flags |= MEM_Utf8; - if( n<0 ) tmp.n = strlen(z)+1; - tmp.flags |= ((tmp.z[tmp.n-1])?0:MEM_Term); - break; - - case TEXT_Utf16le: - case TEXT_Utf16be: - tmp.flags |= (enc==TEXT_Utf16le?MEM_Utf16le:MEM_Utf16be); - if( n<0 ) tmp.n = sqlite3utf16ByteLen(z,-1)+1; - tmp.flags |= ((tmp.z[tmp.n-1]||tmp.z[tmp.n-2])?0:MEM_Term); - break; - - default: - assert(0); - } - return sqlite3VdbeMemCopy(pMem, &tmp); -} - -int sqlite3VdbeMemNulTerminate(Mem *pMem){ - int nulTermLen; - int f = pMem->flags; - - assert( pMem->flags&MEM_Str && !pMem->flags&MEM_Term ); - assert( flagsToEnc(pMem->flags) ); - - nulTermLen = (flagsToEnc(f)==TEXT_Utf8?1:2); - - if( pMem->n+nulTermLen<=NBFS ){ - /* If the string plus the nul terminator will fit in the Mem.zShort - ** buffer, and it is not already stored there, copy it there. - */ - if( !(f&MEM_Short) ){ - memcpy(pMem->z, pMem->zShort, pMem->n); - if( f&MEM_Dyn ){ - sqliteFree(pMem->z); - } - pMem->z = pMem->zShort; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Dyn); - pMem->flags |= MEM_Short; - } - }else{ - /* Otherwise we have to malloc for memory. If the string is already - ** dynamic, use sqliteRealloc(). Otherwise sqliteMalloc() enough - ** space for the string and the nul terminator, and copy the string - ** data there. - */ - if( f&MEM_Dyn ){ - pMem->z = (char *)sqliteRealloc(pMem->z, pMem->n+nulTermLen); - if( !pMem->z ){ - return SQLITE_NOMEM; - } - }else{ - char *z = (char *)sqliteMalloc(pMem->n+nulTermLen); - memcpy(z, pMem->z, pMem->n); - pMem->z = z; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); - pMem->flags |= MEM_Dyn; - } - } - - /* pMem->z now points at the string data, with enough space at the end - ** to insert the nul nul terminator. pMem->n has not yet been updated. - */ - memcpy(&pMem->z[pMem->n], "\0\0", nulTermLen); - pMem->n += nulTermLen; - pMem->flags |= MEM_Term; -} - -/* -** The following ten routines, named sqlite3_result_*(), are used to -** return values or errors from user-defined functions and aggregate -** operations. They are commented in the header file sqlite.h (sqlite.h.in) -*/ -void sqlite3_result(sqlite3_context *pCtx, sqlite3_value *pValue){ - sqlite3VdbeMemCopy(&pCtx->s, pValue); -} -void sqlite3_result_int32(sqlite3_context *pCtx, int iVal){ - MemSetInt(&pCtx->s, iVal); -} -void sqlite3_result_int64(sqlite3_context *pCtx, i64 iVal){ - MemSetInt(&pCtx->s, iVal); -} -void sqlite3_result_double(sqlite3_context *pCtx, double rVal){ - MemSetReal(&pCtx->s, rVal); -} -void sqlite3_result_null(sqlite3_context *pCtx){ - MemSetNull(&pCtx->s); -} -void sqlite3_result_text( - sqlite3_context *pCtx, - const char *z, - int n, - int eCopy -){ - MemSetStr(&pCtx->s, z, n, TEXT_Utf8, eCopy); -} -void sqlite3_result_text16( - sqlite3_context *pCtx, - const void *z, - int n, - int eCopy -){ - MemSetStr(&pCtx->s, z, n, TEXT_Utf16, eCopy); -} -void sqlite3_result_blob( - sqlite3_context *pCtx, - const void *z, - int n, - int eCopy -){ - assert( n>0 ); - MemSetStr(&pCtx->s, z, n, 0, eCopy); -} -void sqlite3_result_error(sqlite3_context *pCtx, const char *z, int n){ - pCtx->isError = 1; - MemSetStr(&pCtx->s, z, n, TEXT_Utf8, 1); -} -void sqlite3_result_error16(sqlite3_context *pCtx, const void *z, int n){ - pCtx->isError = 1; - MemSetStr(&pCtx->s, z, n, TEXT_Utf16, 1); -} diff --git a/src/vdbemem.c b/src/vdbemem.c index 309f21960d..e801a1828a 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -20,131 +20,233 @@ #include #include "vdbeInt.h" -/* -** Given a Mem.flags value, return TEXT_Utf8, TEXT_Utf16le, or TEXT_Utf16be -** as appropriate. -*/ -#define flagsToEnc(F) \ - (((F)&MEM_Utf8)?TEXT_Utf8: \ - ((F)&MEM_Utf16be)?TEXT_Utf16be:TEXT_Utf16le) - /* ** If pMem is a string object, this routine sets the encoding of the string ** (to one of UTF-8 or UTF16) and whether or not the string is ** nul-terminated. If pMem is not a string object, then this routine is ** a no-op. ** -** The second argument, "flags" consists of one of MEM_Utf8, MEM_Utf16le -** or MEM_Utf16be, possible ORed with MEM_Term. If necessary this function -** manipulates the value stored by pMem so that it matches the flags passed -** in "flags". +** The second argument, "desiredEnc" is one of TEXT_Utf8, TEXT_Utf16le +** or TEXT_Utf16be. This routine changes the encoding of pMem to match +** desiredEnc. ** ** SQLITE_OK is returned if the conversion is successful (or not required). ** SQLITE_NOMEM may be returned if a malloc() fails during conversion ** between formats. */ -int sqlite3VdbeSetEncoding(Mem *pMem, int flags){ - u8 enc1; /* Current string encoding (TEXT_Utf* value) */ - u8 enc2; /* Required string encoding (TEXT_Utf* value) */ +int sqlite3VdbeChangeEncoding(Mem *pMem, int desiredEnc){ + u8 oldEnd; /* - /* If this is not a string, do nothing. */ - if( !(pMem->flags&MEM_Str) ){ + /* If this is not a string, or if it is a string but the encoding is + ** already correct, do nothing. */ + if( !(pMem->flags&MEM_Str) || pMem->enc==desiredEnc ){ return SQLITE_OK; } - enc1 = flagsToEnc(pMem->flags); - enc2 = flagsToEnc(flags); - - if( enc1!=enc2 ){ - if( enc1==TEXT_Utf8 || enc2==TEXT_Utf8 ){ - /* If the current encoding does not match the desired encoding, then - ** we will need to do some translation between encodings. - */ - char *z; - int n; - int rc = sqlite3utfTranslate(pMem->z,pMem->n,enc1,(void **)&z,&n,enc2); - if( rc!=SQLITE_OK ){ - return rc; - } + if( pMem->enc==TEXT_Utf8 || desiredEnd==TEXT_Utf8 ){ + /* If the current encoding does not match the desired encoding, then + ** we will need to do some translation between encodings. + */ + char *z; + int n; + int rc = sqlite3utfTranslate(pMem->z, pMem->n, pMem->enc, + (void **)&z, &n, desiredEnd); + if( rc!=SQLITE_OK ){ + return rc; + } - /* Result of sqlite3utfTranslate is currently always dynamically - ** allocated and nul terminated. This might be altered as a performance - ** enhancement later. - */ - pMem->z = z; - pMem->n = n; - pMem->flags = (MEM_Str | MEM_Dyn | MEM_Term | flags); - }else{ - /* Must be translating between UTF-16le and UTF-16be. */ - int i; - if( pMem->flags&MEM_Static ){ - Dynamicify(pMem, enc1); - } - for(i=0; in; i+=2){ - char c = pMem->z[i]; - pMem->z[i] = pMem->z[i+1]; - pMem->z[i+1] = c; - } - SetEncodingFlags(pMem, enc2); + /* Result of sqlite3utfTranslate is currently always dynamically + ** allocated and nul terminated. This might be altered as a performance + ** enhancement later. + */ + pMem->z = z; + pMem->n = n; + pMem->flags &= ~(MEM_Ephem | MEM_Short | MEM_Static); + pMem->flags |= MEM_Str | MEM_Dyn | MEM_Term; + }else{ + /* Must be translating between UTF-16le and UTF-16be. */ + int i; + u8 *pFrom, *pTo; + sqlite3VdbeMemMakeWritable(pMem); + for(i=0, pFrom=pMem->z, pTo=&pMem->z[1]; in; i+=2, pFrom++, pTo++){ + u8 temp = *pFrom; + *pFrom = *pTo; + *pTo = temp; } } - - if( (flags&MEM_Term) && !(pMem->flags&MEM_Term) ){ - /* If we did not do any translation, but currently the string is - ** not nul terminated (and is required to be), then we add the - ** nul terminator now. We never have to do this if we translated - ** the encoding of the string, as the translation functions return - ** nul terminated values. - */ - int f = pMem->flags; - int nulTermLen = 2; /* The number of 0x00 bytes to append */ - if( enc2==MEM_Utf8 ){ - nulTermLen = 1; - } - - if( pMem->n+nulTermLen<=NBFS ){ - /* If the string plus the nul terminator will fit in the Mem.zShort - ** buffer, and it is not already stored there, copy it there. - */ - if( !(f&MEM_Short) ){ - memcpy(pMem->z, pMem->zShort, pMem->n); - if( f&MEM_Dyn ){ - sqliteFree(pMem->z); - } - pMem->z = pMem->zShort; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Dyn); - pMem->flags |= MEM_Short; - } - }else{ - /* Otherwise we have to malloc for memory. If the string is already - ** dynamic, use sqliteRealloc(). Otherwise sqliteMalloc() enough - ** space for the string and the nul terminator, and copy the string - ** data there. - */ - if( f&MEM_Dyn ){ - pMem->z = (char *)sqliteRealloc(pMem->z, pMem->n+nulTermLen); - if( !pMem->z ){ - return SQLITE_NOMEM; - } - }else{ - char *z = (char *)sqliteMallocRaw(pMem->n+nulTermLen); - memcpy(z, pMem->z, pMem->n); - pMem->z = z; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); - pMem->flags |= MEM_Dyn; - } - } - - /* pMem->z now points at the string data, with enough space at the end - ** to insert the nul nul terminator. pMem->n has not yet been updated. - */ - memcpy(&pMem->z[pMem->n], "\0\0", nulTermLen); - pMem->n += nulTermLen; - pMem->flags |= MEM_Term; - } + pMem->enc = desiredEnc; return SQLITE_OK; } +/* +** Make the given Mem object MEM_Dyn. +** +** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. +*/ +int sqlite3VdbeMemMakeDynamicify(Mem *pMem){ + int n; + u8 *z; + if( (pMem->flags & (MEM_Ephem|MEM_Static|MEM_Short))==0 ){ + return SQLITE_OK; + } + assert( (pMem->flags & MEM_Dyn)==0 ); + assert( pMem->flags & (MEM_Str|MEM_Blob) ); + z = sqliteMallocRaw( n+2 ) + if( z==0 ){ + return SQLITE_NOMEM; + } + pMem->flags |= MEM_Dyn|MEM_Term; + memcpy(z, pMem->z, n ); + z[n] = 0; + z[n+1] = 0; + pMem->z = z; + pMem->flags &= ~(MEM_Ephem|MEM_Static|MEM_Short); +} + +/* +** Make the given Mem object either MEM_Short or MEM_Dyn so that bytes +** of the Mem.z[] array can be modified. +** +** Return SQLITE_OK on success or SQLITE_NOMEM if malloc fails. +*/ +int sqlite3VdbeMemMakeWritable(Mem *pMem){ + int n; + u8 *z; + if( (pMem->flags & (MEM_Ephem|MEM_Static))==0 ){ + return SQLITE_OK; + } + assert( (pMem->flags & MEM_Dyn)==0 ); + assert( pMem->flags & (MEM_Str|MEM_Blob) ); + if( (n = pMem->n)+2zShort) ){ + z = pMem->zShort; + pMem->flags |= MEM_Short|MEM_Term; + }else{ + z = sqliteMallocRaw( n+2 ) + if( z==0 ){ + return SQLITE_NOMEM; + } + pMem->flags |= MEM_Dyn|MEM_Term; + } + memcpy(z, pMem->z, n ); + z[n] = 0; + z[n+1] = 0; + pMem->z = z; + pMem->flags &= ~(MEM_Ephem|MEM_Static); +} + +/* +** Make sure the given Mem is \u0000 terminated. +*/ +int sqlite3VdbeMemNulTerminate(Mem *pMem){ + if( (pMem->flags & MEM_Term)!=0 || pMem->flags & (MEM_Str|MEM_Blob))==0 ){ + return SQLITE_OK; /* Nothing to do */ + } + /* Only static or ephemeral strings can be unterminated */ + assert( (pMem->flags & (MEM_Static|MEM_Ephem))!=0 ); + sqlite3VdbeMemMakeWriteable(pMem); +} + +/* +** Add MEM_Str to the set of representations for the given Mem. +** A NULL is converted into an empty string. Numbers are converted +** using sqlite3_snprintf(). Converting a BLOB to a string is a +** no-op. +** +** Existing representations MEM_Int and MEM_Real are *not* invalidated. +** But MEM_Null is. +*/ +int sqlite3VdbeMemStringify(Mem *pMem, int enc){ + int rc = SQLITE_OK; + int fg = pMem->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 */ + u8 *z = pMem->zShort; + z[0] = 0; + z[1] = 0; + pMem->flags = MEM_Str | MEM_Short | MEM_Term; + pMem->z = z; + pMem->n = 0; + pMem->enc = enc; + }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. + */ + u8 *z = pMem->zShort; + if( fg & MEM_Real ){ + sqlite3_snprintf(NBFS, z, "%.15g", pMem->r); + }else{ + assert( fg & MEM_Int ); + sqlite3_snprintf(NBFS, z, "%lld", pMem->i); + } + pMem->n = strlen(z); + pMem->z = n; + pMem->enc = TEXT_Utf8; + pMem->flags |= MEM_Str | MEM_Short | MEM_Term; + sqlite3VdbeMemChangeEncoding(pMem, enc); + } + return rc; +} + +/* +** Convert the Mem to have representation MEM_Int only. All +** prior representations are invalidated. NULL is converted into 0. +*/ +int sqlite3VdbeMemIntegerify(Mem *pMem){ + if( pMem->flags & MEM_Int ){ + /* Do nothing */ + }else if( pMem->flags & MEM_Real ){ + pMem->i = (i64)pMem->r; + }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ + if( sqlite3VdbeChangeEncoding(pMem, TEXT_Utf8) + || sqlite3VdbeNulTerminate(pMem) ){ + return SQLITE_NOMEM; + } + assert( pMem->z ); + sqlite3atoi64(pMem->z, &pMem->i); + }else{ + pMem->i = 0; + } + Release(pMem); + pMem->flags = MEM_Int; + pMem->type = SQLITE3_INTEGER; +} + +/* +** Add MEM_Real to the set of representations for pMem. Prior +** prior representations other than MEM_Null retained. NULL is +** converted into 0.0. +*/ +int sqlite3VdbeMemRealify(Mem *pMem){ + if( pMem->flags & MEM_Int ){ + pMem->r = pMem->r; + pMem->flags |= MEM_Real; + }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ + if( sqlite3VdbeChangeEncoding(pMem, TEXT_Utf8) + || sqlite3VdbeNulTerminate(pMem) ){ + return SQLITE_NOMEM; + } + assert( pMem->z ); + pMem->r = sqlite3AtoF(pMem->z, 0); + Release(pMem); + pMem->flags = MEM_Real; + pMem->type = SQLITE3_INTEGER; + }else{ + pMem->r = 0.0; + pMem->flags = MEM_Real; + pMem->type = SQLITE3_INTEGER; + } +} + +/* +** Release any memory held by the Mem +*/ static void releaseMem(Mem *p){ if( p->flags & MEM_Dyn ){ sqliteFree(p); @@ -157,26 +259,29 @@ static void releaseMem(Mem *p){ void sqlite3VdbeMemSetNull(Mem *pMem){ releaseMem(pMem); pMem->flags = MEM_Null; + pMem->type = SQLITE3_NULL; } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type INTEGER. */ -void sqlite3VdbeMemSetInt(Mem *pMem, i64 val){ +void sqlite3VdbeMemSetInt64(Mem *pMem, i64 val){ releaseMem(pMem); pMem->i = val; pMem->flags = MEM_Int; + pMem->type = SQLITE3_INTEGER; } /* ** Delete any previous value and set the value stored in *pMem to val, ** manifest type REAL. */ -void sqlite3VdbeMemSetReal(Mem *pMem, double val){ +void sqlite3VdbeMemSetDouble(Mem *pMem, double val){ releaseMem(pMem); pMem->r = val; pMem->flags = MEM_Real; + pMem->type = SQLITE3_FLOAT; } /* @@ -184,36 +289,31 @@ void sqlite3VdbeMemSetReal(Mem *pMem, double val){ */ int sqlite3VdbeMemCopy(Mem *pTo, const Mem *pFrom){ releaseMem(pTo); - memcpy(pTo, pFrom, sizeof(*pFrom)); - if( pTo->flags&MEM_Short ){ - pTo->z = pTo->zShort; - }else if( pTo->flags&(MEM_Ephem|MEM_Dyn) ){ - pTo->flags = pTo->flags&(~(MEM_Static|MEM_Ephem|MEM_Short|MEM_Dyn)); - if( pTo->n>NBFS ){ - pTo->z = sqliteMalloc(pTo->n); - if( !pTo->z ) return SQLITE_NOMEM; - pTo->flags |= MEM_Dyn; - }else{ - pTo->z = pTo->zShort; - pTo->flags |= MEM_Short; - } - memcpy(pTo->z, pFrom->z, pTo->n); + memcpy(pTo, pFrom, sizeof(*pFrom)-sizeof(pFrom->zShort)); + if( pTo->flags & (MEM_Str|MEM_Blob) ){ + pTo->flags &= ~(MEM_Dyn|MEM_Static|MEM_Short); + pTo->flags |= MEM_Ephem; + sqlite3VdbeMemMakeWriteable(pTo); } return SQLITE_OK; } +/* +** Change the value of a Mem to be a string or a BLOB. +*/ int sqlite3VdbeMemSetStr( Mem *pMem, /* Memory cell to set to string value */ const char *z, /* String pointer */ int n, /* Bytes in string, or negative */ - u8 enc, /* Encoding of z */ + u8 enc, /* Encoding of z. 0 for BLOBs */ int eCopy /* True if this function should make a copy of z */ ){ Mem tmp; releaseMem(pMem); if( !z ){ - /* If z is NULL, just set *pMem to contain NULL. */ + pMem->flags = MEM_Null; + pMem->type = SQLITE3_NULL; return SQLITE_OK; } @@ -223,7 +323,8 @@ int sqlite3VdbeMemSetStr( }else{ pMem->flags = MEM_Static|MEM_Str; } - pMem->flags |= encToFlags(enc); + pMem->enc = enc; + pMem->type = enc==0 ? SQLITE3_BLOB : SQLITE3_TEXT; pMem->n = n; switch( enc ){ case 0: @@ -231,22 +332,16 @@ int sqlite3VdbeMemSetStr( break; case TEXT_Utf8: - pMem->flags |= MEM_Utf8; if( n<0 ){ - pMem->n = strlen(z)+1; - pMem->flags |= MEM_Term; - }else if( z[pMem->n-1]==0 ){ + pMem->n = strlen(z); pMem->flags |= MEM_Term; } break; case TEXT_Utf16le: case TEXT_Utf16be: - pMem->flags |= (enc==TEXT_Utf16le?MEM_Utf16le:MEM_Utf16be); if( n<0 ){ - pMem->n = sqlite3utf16ByteLen(z,-1)+1; - pMem->flags |= MEM_Term; - }else if( z[pMem->n-1]==0 && z[pMem->n-2]==0 ){ + pMem->n = sqlite3utf16ByteLen(z,-1); pMem->flags |= MEM_Term; } break; @@ -254,57 +349,9 @@ int sqlite3VdbeMemSetStr( default: assert(0); } - Deephemeralize(pMem); -} - -int sqlite3VdbeMemNulTerminate(Mem *pMem){ - int nulTermLen; - int f = pMem->flags; - - assert( pMem->flags&MEM_Str && !pMem->flags&MEM_Term ); - assert( flagsToEnc(pMem->flags) ); - - nulTermLen = (flagsToEnc(f)==TEXT_Utf8?1:2); - - if( pMem->n+nulTermLen<=NBFS ){ - /* If the string plus the nul terminator will fit in the Mem.zShort - ** buffer, and it is not already stored there, copy it there. - */ - if( !(f&MEM_Short) ){ - memcpy(pMem->z, pMem->zShort, pMem->n); - if( f&MEM_Dyn ){ - sqliteFree(pMem->z); - } - pMem->z = pMem->zShort; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Dyn); - pMem->flags |= MEM_Short; - } - }else{ - /* Otherwise we have to malloc for memory. If the string is already - ** dynamic, use sqliteRealloc(). Otherwise sqliteMalloc() enough - ** space for the string and the nul terminator, and copy the string - ** data there. - */ - if( f&MEM_Dyn ){ - pMem->z = (char *)sqliteRealloc(pMem->z, pMem->n+nulTermLen); - if( !pMem->z ){ - return SQLITE_NOMEM; - } - }else{ - char *z = (char *)sqliteMalloc(pMem->n+nulTermLen); - memcpy(z, pMem->z, pMem->n); - pMem->z = z; - pMem->flags &= ~(MEM_Static|MEM_Ephem|MEM_Short); - pMem->flags |= MEM_Dyn; - } + if( eCopy ){ + sqlite3VdbeMemMakeWriteable(pMem); } - - /* pMem->z now points at the string data, with enough space at the end - ** to insert the nul nul terminator. pMem->n has not yet been updated. - */ - memcpy(&pMem->z[pMem->n], "\0\0", nulTermLen); - pMem->n += nulTermLen; - pMem->flags |= MEM_Term; } /* diff --git a/test/bind.test b/test/bind.test index 675905a884..c18e75b489 100644 --- a/test/bind.test +++ b/test/bind.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the sqlite_bind API. # -# $Id: bind.test,v 1.9 2004/05/26 10:11:07 danielk1977 Exp $ +# $Id: bind.test,v 1.10 2004/05/27 01:53:56 drh Exp $ # set testdir [file dirname $argv0] @@ -28,7 +28,7 @@ proc sqlite_step {stmt N VALS COLS} { lappend cols [sqlite3_column_name $stmt $i] } for {set i 0} {$i < [sqlite3_data_count $stmt]} {incr i} { - lappend vals [sqlite3_column_data $stmt $i] + lappend vals [sqlite3_column_text $stmt $i] } return $rc diff --git a/test/enc2.test b/test/enc2.test index 277485ae34..183f91a571 100644 --- a/test/enc2.test +++ b/test/enc2.test @@ -13,7 +13,7 @@ # various suported unicode encodings (UTF-8, UTF-16, UTF-16le and # UTF-16be). # -# $Id: enc2.test,v 1.2 2004/05/26 10:11:07 danielk1977 Exp $ +# $Id: enc2.test,v 1.3 2004/05/27 01:53:56 drh Exp $ set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -91,12 +91,12 @@ do_test $t.6 { do_test $t.7 { set STMT [sqlite3_prepare $DB "SELECT a FROM t1 WHERE c>3;" -1 TAIL] sqlite3_step $STMT - sqlite3_column_data $STMT 0 + sqlite3_column_text $STMT 0 } {four} do_test $t.8 { sqlite3_step $STMT - utf8 [sqlite3_column_data16 $STMT 0] + utf8 [sqlite3_column_text16 $STMT 0] } {five} do_test $t.9 { @@ -123,7 +123,3 @@ foreach enc $encodings { } finish_test - - - -