From 6a6124e27ab44367fbba755ea0d8c0e348d549cc Mon Sep 17 00:00:00 2001 From: drh Date: Sun, 27 Jun 2004 01:56:33 +0000 Subject: [PATCH] Fix a bug in the handling of Mems inside of vdbe.c. (CVS 1745) FossilOrigin-Name: ad65c6e24e15966d5fd15d60f81487ff97788da4 --- manifest | 20 +++++------ manifest.uuid | 2 +- src/vdbe.c | 94 ++++++++++++++++++++----------------------------- src/vdbeInt.h | 2 ++ src/vdbeapi.c | 12 ++----- src/vdbemem.c | 78 ++++++++++++++++++++++++++++++---------- test/capi3.test | 4 +-- 7 files changed, 116 insertions(+), 96 deletions(-) diff --git a/manifest b/manifest index 52b4c002cd..c59d3256c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Coverage\stesting\sof\spragma.c.\s(CVS\s1744) -D 2004-06-26T19:35:30 +C Fix\sa\sbug\sin\sthe\shandling\sof\sMems\sinside\sof\svdbe.c.\s(CVS\s1745) +D 2004-06-27T01:56:33 F Makefile.in cb7a9889c38723f72b2506c4236ff30a05ff172b F Makefile.linux-gcc a9e5a0d309fa7c38e7c14d3ecf7690879d3a5457 F README f1de682fbbd94899d50aca13d387d1b3fd3be2dd @@ -73,12 +73,12 @@ F src/update.c b66b1896c9da54678ba3eff2bf0b4d291a95986a F src/utf.c a8fb39c94ae4ef6606d5216b6f05d9b86f6901b2 F src/util.c 43d0289d49f43c66847ebbeddfb85a2a0d1ddd2d F src/vacuum.c 353c7f69dbeb6738434d81798465cc0698844640 -F src/vdbe.c 423b55e65501ef2b60d8dedabe8d76d06ea62d99 +F src/vdbe.c b750a731c90567b77ed6e0cd455ac868953d3a72 F src/vdbe.h 2d87155e31e84bb00cdc48cc1ce6987a3a484250 -F src/vdbeInt.h 22ab717b69074fe7a28f64e35a39bd436ad9d150 -F src/vdbeapi.c d3659f3f2982e79c06ab8e338604a39e0ea0d2d3 +F src/vdbeInt.h d83fd7389838453d8392915c21f432014afc99cf +F src/vdbeapi.c e92bda928f2fe93a9a77a62bd95642563bbcdea1 F src/vdbeaux.c e7201e3f129439bc64d2ff79b54001adc2c95539 -F src/vdbemem.c d37e4033f7350e542f715c061bffe23feb51bc9e +F src/vdbemem.c e8ae1f56ad16d5b01119e8dc1d25e913e06c3128 F src/where.c 6507074d8ce3f78e7a4cd33f667f11e62020553e F test/all.test d591e074013248176402a16a0fb6fc82d241bad5 F test/attach.test 3acdffccbf5f78b07746771b9490758718e28856 @@ -96,7 +96,7 @@ F test/btree5.test 8e5ff32c02e685d36516c6499add9375fe1377f2 F test/btree6.test a5ede6bfbbb2ec8b27e62813612c0f28e8f3e027 F test/btree7.test 429b96cfef5b51a7d512cfb4b5b3e453384af293 F test/capi2.test fe61f341e953f73c29bacfcbdaf688cd7b0e0d38 -F test/capi3.test 6528034f21c4e8e404032124cb58b14ce934598c +F test/capi3.test ac53507f69b14fe026634afa09e6512f678f161d F test/collate1.test 2ee4fa3a47a652ccf56c5ddf65dcc44d9bad82ef F test/collate2.test c1a3b41f761b28853c5696037f92de928f93233b F test/collate3.test e60b428e07ec945492ba90ff1c895902ee3a8a50 @@ -229,7 +229,7 @@ F www/tclsqlite.tcl 19191cf2a1010eaeff74c51d83fd5f5a4d899075 F www/vdbe.tcl 59288db1ac5c0616296b26dce071c36cb611dfe9 F www/version3.tcl 563ba3ac02f64da27ab17f3edbe8e56bfd0293fb F www/whentouse.tcl a8335bce47cc2fddb07f19052cb0cb4d9129a8e4 -P b69b4fe8adff83a26e3566613bea8b477a26e8a4 -R 72fd52c0e274fc83fa1945dfd7a6deb8 +P 0f9c0f0aa9188c46c65cb92203687f37884f685a +R 890a4b373e4b15aa9e98bea1cb54b3e0 U drh -Z 03157110b37f81d3fef2f16d6fba5e75 +Z bd1af074bc92b88e71778888aba3c921 diff --git a/manifest.uuid b/manifest.uuid index 53cf3f0628..555b422f75 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f9c0f0aa9188c46c65cb92203687f37884f685a \ No newline at end of file +ad65c6e24e15966d5fd15d60f81487ff97788da4 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 37f9657ed1..25b4ff15ef 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.389 2004/06/26 08:38:25 danielk1977 Exp $ +** $Id: vdbe.c,v 1.390 2004/06/27 01:56:33 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -115,17 +115,15 @@ int sqlite3_interrupt_count = 0; ** Any prior string or real representation is invalidated. ** NULLs are converted into 0. */ -#define Integerify(P, enc) \ - if((P)->flags!=MEM_Int){ sqlite3VdbeMemIntegerify(P); } +#define Integerify(P) sqlite3VdbeMemIntegerify(P) /* -** Get a valid Real representation for the given stack element. +** Convert P so that it has type MEM_Real. ** -** Any prior string or integer representation is retained. +** Any prior string or integer representation is invalidated. ** NULLs are converted into 0.0. */ -#define Realify(P,enc) \ - if(((P)->flags&MEM_Real)==0){ sqlite3VdbeMemRealify(P); } +#define Realify(P) sqlite3VdbeMemRealify(P) /* ** Argument pMem points at a memory cell that will be passed to a @@ -304,9 +302,9 @@ static void applyAffinity(Mem *pRec, char affinity, u8 enc){ sqlite3VdbeMemNulTerminate(pRec); if( pRec->flags&MEM_Str && sqlite3IsNumber(pRec->z, &realnum, enc) ){ if( realnum ){ - Realify(pRec, enc); + Realify(pRec); }else{ - Integerify(pRec, enc); + Integerify(pRec); } } } @@ -686,7 +684,8 @@ case OP_Integer: { pTos->z = pOp->p3; pTos->n = strlen(pTos->z); pTos->enc = SQLITE_UTF8; - Integerify(pTos, 0); + pTos->i = sqlite3VdbeIntValue(pTos); + pTos->flags |= MEM_Int; } break; } @@ -701,7 +700,8 @@ case OP_Real: { pTos->z = pOp->p3; pTos->n = strlen(pTos->z); pTos->enc = SQLITE_UTF8; - Realify(pTos, 0); + pTos->r = sqlite3VdbeRealValue(pTos); + pTos->flags |= MEM_Real; break; } @@ -1162,10 +1162,8 @@ case OP_Remainder: { pTos->flags = MEM_Int; }else{ double a, b; - Realify(pTos, db->enc); - Realify(pNos, db->enc); - a = pTos->r; - b = pNos->r; + a = sqlite3VdbeRealValue(pTos); + b = sqlite3VdbeRealValue(pNos); switch( pOp->opcode ){ case OP_Add: b += a; break; case OP_Subtract: b -= a; break; @@ -1339,10 +1337,8 @@ case OP_ShiftRight: { pTos->flags = MEM_Null; break; } - Integerify(pTos, db->enc); - Integerify(pNos, db->enc); - a = pTos->i; - b = pNos->i; + a = sqlite3VdbeIntValue(pTos); + b = sqlite3VdbeIntValue(pNos); switch( pOp->opcode ){ case OP_BitAnd: a &= b; break; case OP_BitOr: a |= b; break; @@ -1350,13 +1346,6 @@ 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); @@ -1374,7 +1363,7 @@ case OP_ShiftRight: { */ case OP_AddImm: { assert( pTos>=p->aStack ); - Integerify(pTos, db->enc); + Integerify(pTos); pTos->i += pOp->p1; break; } @@ -1402,7 +1391,7 @@ case OP_ForceInt: { if( pTos->flags & MEM_Int ){ v = pTos->i + (pOp->p1!=0); }else{ - Realify(pTos, db->enc); + Realify(pTos); v = (int)pTos->r; if( pTos->r>(double)v ) v++; if( pOp->p1 && pTos->r==(double)v ) v++; @@ -1446,7 +1435,7 @@ case OP_MustBeInt: { if( !sqlite3IsNumber(pTos->z, 0, db->enc) ){ goto mismatch; } - Realify(pTos, db->enc); + Realify(pTos); v = (int)pTos->r; r = (double)v; if( r!=pTos->r ){ @@ -1609,13 +1598,13 @@ case OP_Or: { if( pTos->flags & MEM_Null ){ v1 = 2; }else{ - Integerify(pTos, db->enc); + Integerify(pTos); v1 = pTos->i==0; } if( pNos->flags & MEM_Null ){ v2 = 2; }else{ - Integerify(pNos, db->enc); + Integerify(pNos); v2 = pNos->i==0; } if( pOp->opcode==OP_And ){ @@ -1666,8 +1655,7 @@ case OP_AbsValue: { }else if( pTos->flags & MEM_Null ){ /* Do nothing */ }else{ - Realify(pTos, db->enc); - Release(pTos); + Realify(pTos); if( pOp->opcode==OP_Negative || pTos->r<0.0 ){ pTos->r = -pTos->r; } @@ -1685,8 +1673,8 @@ case OP_AbsValue: { case OP_Not: { assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ - Integerify(pTos, db->enc); - Release(pTos); + Integerify(pTos); + assert( (pTos->flags & MEM_Dyn)==0 ); pTos->i = !pTos->i; pTos->flags = MEM_Int; break; @@ -1701,8 +1689,8 @@ case OP_Not: { case OP_BitNot: { assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ - Integerify(pTos, db->enc); - Release(pTos); + Integerify(pTos); + assert( (pTos->flags & MEM_Dyn)==0 ); pTos->i = ~pTos->i; pTos->flags = MEM_Int; break; @@ -1744,16 +1732,9 @@ case OP_IfNot: { if( pTos->flags & MEM_Null ){ c = pOp->p1; }else{ - Integerify(pTos, db->enc); - c = pTos->i; + c = sqlite3VdbeIntValue(pTos); if( pOp->opcode==OP_IfNot ) c = !c; } - /* 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; @@ -2144,7 +2125,7 @@ case OP_MakeRecord: { if( addRowid ){ pRowid = &pTos[0-nField]; assert( pRowid>=p->aStack ); - Integerify(pRowid, db->enc); + Integerify(pRowid); serial_type = sqlite3VdbeSerialType(pRowid); nData += sqlite3VdbeSerialTypeLen(serial_type); nHdr += sqlite3VarintLen(serial_type); @@ -2360,10 +2341,10 @@ case OP_SetCookie: { assert( pOp->p1>=0 && pOp->p1nDb ); assert( db->aDb[pOp->p1].pBt!=0 ); assert( pTos>=p->aStack ); - Integerify(pTos, db->enc); + Integerify(pTos); /* See note about index shifting on OP_ReadCookie */ rc = sqlite3BtreeUpdateMeta(db->aDb[pOp->p1].pBt, 1+pOp->p2, (int)pTos->i); - Release(pTos); + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; break; } @@ -2447,8 +2428,9 @@ case OP_OpenWrite: { Cursor *pCur; assert( pTos>=p->aStack ); - Integerify(pTos, db->enc); + Integerify(pTos); iDb = pTos->i; + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; assert( iDb>=0 && iDbnDb ); pX = db->aDb[iDb].pBt; @@ -2456,8 +2438,9 @@ case OP_OpenWrite: { wrFlag = pOp->opcode==OP_OpenWrite; if( p2<=0 ){ assert( pTos>=p->aStack ); - Integerify(pTos, db->enc); + Integerify(pTos); p2 = pTos->i; + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; if( p2<2 ){ sqlite3SetString(&p->zErrMsg, "root page number less than 2", (char*)0); @@ -2657,12 +2640,12 @@ case OP_MoveGt: { if( pC->intKey ){ i64 iKey; assert( !pOp->p3 ); - Integerify(pTos, db->enc); + Integerify(pTos); iKey = intToKey(pTos->i); if( pOp->p2==0 && pOp->opcode==OP_MoveGe ){ pC->movetoTarget = iKey; pC->deferredMoveto = 1; - Release(pTos); + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; break; } @@ -2801,8 +2784,9 @@ case OP_IsUnique: { /* Pop the value R off the top of the stack */ assert( pNos>=p->aStack ); - Integerify(pTos, db->enc); + Integerify(pTos); R = pTos->i; + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; assert( i>=0 && i<=p->nCursor ); pCx = p->apCsr[i]; @@ -3851,9 +3835,9 @@ case OP_ListWrite: { pKeylist->pNext = p->pList; p->pList = pKeylist; } - Integerify(pTos, db->enc); + Integerify(pTos); pKeylist->aKey[pKeylist->nUsed++] = pTos->i; - Release(pTos); + assert( (pTos->flags & MEM_Dyn)==0 ); pTos--; break; } diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 946f9f716e..9ccb4d4272 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -391,7 +391,9 @@ void sqlite3VdbeMemSetNull(Mem*); int sqlite3VdbeMemMakeWriteable(Mem*); int sqlite3VdbeMemDynamicify(Mem*); int sqlite3VdbeMemStringify(Mem*, int); +i64 sqlite3VdbeIntValue(Mem*); int sqlite3VdbeMemIntegerify(Mem*); +double sqlite3VdbeRealValue(Mem*); int sqlite3VdbeMemRealify(Mem*); int sqlite3VdbeMemFromBtree(BtCursor*,int,int,int,Mem*); void sqlite3VdbeMemRelease(Mem *p); diff --git a/src/vdbeapi.c b/src/vdbeapi.c index ca488315c7..57b1b87766 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -43,19 +43,13 @@ int sqlite3_value_bytes16(sqlite3_value *pVal){ return 0; } double sqlite3_value_double(sqlite3_value *pVal){ - Mem *pMem = (Mem *)pVal; - sqlite3VdbeMemRealify(pMem); - return pMem->r; + return sqlite3VdbeRealValue((Mem*)pVal); } int sqlite3_value_int(sqlite3_value *pVal){ - Mem *pMem = (Mem *)pVal; - sqlite3VdbeMemIntegerify(pMem); - return (int)pVal->i; + return sqlite3VdbeIntValue((Mem*)pVal); } sqlite_int64 sqlite3_value_int64(sqlite3_value *pVal){ - Mem *pMem = (Mem *)pVal; - sqlite3VdbeMemIntegerify(pMem); - return pVal->i; + return sqlite3VdbeIntValue((Mem*)pVal); } const unsigned char *sqlite3_value_text(sqlite3_value *pVal){ return (const char *)sqlite3ValueText(pVal, SQLITE_UTF8); diff --git a/src/vdbemem.c b/src/vdbemem.c index 860ed831d1..55b0fbb9ff 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -207,50 +207,76 @@ void sqlite3VdbeMemRelease(Mem *p){ } /* -** Convert the Mem to have representation MEM_Int only. All -** prior representations are invalidated. NULL is converted into 0. +** Return some kind of integer value which is the best we can do +** at representing the value that *pMem describes as an integer. +** If pMem is an integer, then the value is exact. If pMem is +** a floating-point then the value returned is the integer part. +** If pMem is a string or blob, then we make an attempt to convert +** it into a integer and return that. If pMem is NULL, return 0. +** +** If pMem is a string, its encoding might be changed. */ -int sqlite3VdbeMemIntegerify(Mem *pMem){ +i64 sqlite3VdbeIntValue(Mem *pMem){ int flags = pMem->flags; if( flags & MEM_Int ){ - /* Do nothing */ + return pMem->i; }else if( flags & MEM_Real ){ - pMem->i = (i64)pMem->r; + return (i64)pMem->r; }else if( flags & (MEM_Str|MEM_Blob) ){ + i64 value; if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) || sqlite3VdbeMemNulTerminate(pMem) ){ return SQLITE_NOMEM; } assert( pMem->z ); - sqlite3atoi64(pMem->z, &pMem->i); + sqlite3atoi64(pMem->z, &value); + return value; }else{ - pMem->i = 0; + return 0; } - pMem->flags |= MEM_Int; +} + +/* +** Convert pMem to type integer. Invalidate any prior representations. +*/ +int sqlite3VdbeMemIntegerify(Mem *pMem){ + pMem->i = sqlite3VdbeIntValue(pMem); + sqlite3VdbeMemRelease(pMem); + pMem->flags = MEM_Int; return SQLITE_OK; } /* -** Add MEM_Real to the set of representations for pMem. Prior -** prior representations other than MEM_Null retained. NULL is -** converted into 0.0. +** Return the best representation of pMem that we can get into a +** double. If pMem is already a double or an integer, return its +** value. If it is a string or blob, try to convert it to a double. +** If it is a NULL, return 0.0. */ -int sqlite3VdbeMemRealify(Mem *pMem){ +double sqlite3VdbeRealValue(Mem *pMem){ if( pMem->flags & MEM_Real ){ - /* Do nothing */ - }else if( (pMem->flags & MEM_Int) && pMem->type!=SQLITE_TEXT ){ - pMem->r = pMem->i; + return pMem->r; + }else if( pMem->flags & MEM_Int ){ + return (double)pMem->i; }else if( pMem->flags & (MEM_Str|MEM_Blob) ){ if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8) || sqlite3VdbeMemNulTerminate(pMem) ){ return SQLITE_NOMEM; } assert( pMem->z ); - pMem->r = sqlite3AtoF(pMem->z, 0); + return sqlite3AtoF(pMem->z, 0); }else{ - pMem->r = 0.0; + return 0.0; } - pMem->flags |= MEM_Real; +} + +/* +** Convert pMem so that it is of type MEM_Real. Invalidate any +** prior representations. +*/ +int sqlite3VdbeMemRealify(Mem *pMem){ + pMem->r = sqlite3VdbeRealValue(pMem); + sqlite3VdbeMemRelease(pMem); + pMem->flags = MEM_Real; return SQLITE_OK; } @@ -599,6 +625,9 @@ void sqlite3VdbeMemSanity(Mem *pMem, u8 db_enc){ /* MEM_Null excludes all other types */ assert( (pMem->flags&(MEM_Str|MEM_Int|MEM_Real|MEM_Blob))==0 || (pMem->flags&MEM_Null)==0 ); + if( (pMem->flags & (MEM_Int|MEM_Real))==(MEM_Int|MEM_Real) ){ + assert( pMem->r==pMem->i ); + } } #endif @@ -623,6 +652,9 @@ const void *sqlite3ValueText(sqlite3_value* pVal, u8 enc){ return (const void *)(pVal->z); } +/* +** Create a new sqlite3_value object. +*/ sqlite3_value* sqlite3ValueNew(){ Mem *p = sqliteMalloc(sizeof(*p)); if( p ){ @@ -632,6 +664,9 @@ sqlite3_value* sqlite3ValueNew(){ return p; } +/* +** Change the string value of an sqlite3_value object +*/ void sqlite3ValueSetStr( sqlite3_value *v, int n, @@ -642,12 +677,19 @@ void sqlite3ValueSetStr( if( v ) sqlite3VdbeMemSetStr((Mem *)v, z, n, enc, xDel); } +/* +** Free an sqlite3_value object +*/ void sqlite3ValueFree(sqlite3_value *v){ if( !v ) return; sqlite3ValueSetStr(v, 0, 0, SQLITE_UTF8, SQLITE_STATIC); sqliteFree(v); } +/* +** Return the number of bytes in the sqlite3_value object assuming +** that it uses the encoding "enc" +*/ int sqlite3ValueBytes(sqlite3_value *pVal, u8 enc){ Mem *p = (Mem*)pVal; if( (p->flags & MEM_Blob)!=0 || sqlite3ValueText(pVal, enc) ){ diff --git a/test/capi3.test b/test/capi3.test index 8b73ee2938..87d2df8911 100644 --- a/test/capi3.test +++ b/test/capi3.test @@ -11,7 +11,7 @@ # This file implements regression tests for SQLite library. The # focus of this script testing the callback-free C/C++ API. # -# $Id: capi3.test,v 1.12 2004/06/19 03:33:57 danielk1977 Exp $ +# $Id: capi3.test,v 1.13 2004/06/27 01:56:33 drh Exp $ # set testdir [file dirname $argv0] @@ -397,5 +397,3 @@ do_test capi3-6.4 { } {SQLITE_OK} finish_test - -