]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Fix a bug in the handling of Mems inside of vdbe.c. (CVS 1745)
authordrh <drh@noemail.net>
Sun, 27 Jun 2004 01:56:33 +0000 (01:56 +0000)
committerdrh <drh@noemail.net>
Sun, 27 Jun 2004 01:56:33 +0000 (01:56 +0000)
FossilOrigin-Name: ad65c6e24e15966d5fd15d60f81487ff97788da4

manifest
manifest.uuid
src/vdbe.c
src/vdbeInt.h
src/vdbeapi.c
src/vdbemem.c
test/capi3.test

index 52b4c002cde50fb808487c02dc0c61d95cf630d9..c59d3256c03ca9ed9b07f87b198898d398374afb 100644 (file)
--- 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
index 53cf3f0628c8a5392cb0640955ce52cedb50aa23..555b422f75621dcb0c780f303ff99a952c43a607 100644 (file)
@@ -1 +1 @@
-0f9c0f0aa9188c46c65cb92203687f37884f685a
\ No newline at end of file
+ad65c6e24e15966d5fd15d60f81487ff97788da4
\ No newline at end of file
index 37f9657ed1c2211c4be14b5cf569196bd33d589f..25b4ff15efddd2fde884b6b3a101cb0b544a8bf0 100644 (file)
@@ -43,7 +43,7 @@
 ** in this file for details.  If in doubt, do not deviate from existing
 ** commenting and indentation practices when changing or adding code.
 **
-** $Id: vdbe.c,v 1.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->p1<db->nDb );
   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 && iDb<db->nDb );
   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;
 }
index 946f9f716e9ac4e494d9f0a686af6b1a1467a8ad..9ccb4d42724a958244dbb8781fd13e3ec3a42899 100644 (file)
@@ -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);
index ca488315c7b7e157639e0b31a4a651396761c9ce..57b1b877667ab11847847eac880855b306abb9f4 100644 (file)
@@ -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);
index 860ed831d1c89fea28425636c9fa3ca3536d5975..55b0fbb9ffff357081f81d1e247ab48e93b8a848 100644 (file)
@@ -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) ){
index 8b73ee29386b48b7f02a71341dd693ae09eb613f..87d2df8911b538a243f5e19a44618ec99b32d41d 100644 (file)
@@ -11,7 +11,7 @@
 # This file implements regression tests for SQLite library.  The
 # focus of this script testing the callback-free C/C++ API.
 #
-# $Id: capi3.test,v 1.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
-
-