Remove the blob(), text() and numeric() functions added in (2524) and
replace them with the standard CAST operator.
Ticket #1287. (CVS 2527)

FossilOrigin-Name: 17631785f9ee8ab280c82677eb53886912e085bc
diff --git a/src/build.c b/src/build.c
index e0a6e59..d9d5bb4 100644
--- a/src/build.c
+++ b/src/build.c
@@ -22,7 +22,7 @@
 **     COMMIT
 **     ROLLBACK
 **
-** $Id: build.c,v 1.328 2005/06/24 03:53:06 drh Exp $
+** $Id: build.c,v 1.329 2005/06/25 18:42:14 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -902,11 +902,11 @@
 ** If none of the substrings in the above table are found,
 ** SQLITE_AFF_NUMERIC is returned.
 */
-static char sqlite3AffinityType(const char *zType, int nType){
+char sqlite3AffinityType(const Token *pType){
   u32 h = 0;
   char aff = SQLITE_AFF_NUMERIC;
-  const unsigned char *zIn = zType;
-  const unsigned char *zEnd = (zIn+nType);
+  const unsigned char *zIn = pType->z;
+  const unsigned char *zEnd = &pType->z[pType->n];
 
   while( zIn!=zEnd ){
     h = (h<<8) + sqlite3UpperToLower[*zIn];
@@ -938,21 +938,17 @@
 ** that contains the typename of the column and store that string
 ** in zType.
 */ 
-void sqlite3AddColumnType(Parse *pParse, Token *pFirst, Token *pLast){
+void sqlite3AddColumnType(Parse *pParse, Token *pType){
   Table *p;
-  int i, j;
-  int n;
-  char *z;
-  const unsigned char *zIn;
-
+  int i;
   Column *pCol;
+
   if( (p = pParse->pNewTable)==0 ) return;
   i = p->nCol-1;
   if( i<0 ) return;
   pCol = &p->aCol[i];
-  zIn = pFirst->z;
-  n = pLast->n + (pLast->z - zIn);
   assert( pCol->zType==0 );
+#if 0
   z = pCol->zType = sqliteMallocRaw(n+1);
   if( z==0 ) return;
   for(i=j=0; i<n; i++){
@@ -961,7 +957,9 @@
     z[j++] = c;
   }
   z[j] = 0;
-  pCol->affinity = sqlite3AffinityType(z, n);
+#endif
+  pCol->zType = sqlite3NameFromToken(pType);
+  pCol->affinity = sqlite3AffinityType(pType);
 }
 
 /*
diff --git a/src/date.c b/src/date.c
index 5207569..35c0bf6 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.44 2005/03/21 00:43:44 drh Exp $
+** $Id: date.c,v 1.45 2005/06/25 18:42:14 drh Exp $
 **
 ** NOTES:
 **
@@ -124,11 +124,7 @@
 ** Read text from z[] and convert into a floating point number.  Return
 ** the number of digits converted.
 */
-static int getValue(const char *z, double *pR){
-  const char *zEnd;
-  *pR = sqlite3AtoF(z, &zEnd);
-  return zEnd - z;
-}
+#define getValue sqlite3AtoF
 
 /*
 ** Parse a timezone extension on the end of a date-time.
@@ -320,7 +316,7 @@
     p->validJD = 1;
     return 0;
   }else if( sqlite3IsNumber(zDate, 0, SQLITE_UTF8) ){
-    p->rJD = sqlite3AtoF(zDate, 0);
+    getValue(zDate, &p->rJD);
     p->validJD = 1;
     return 0;
   }
diff --git a/src/expr.c b/src/expr.c
index 4f21800..efac977 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.207 2005/06/22 08:48:06 drh Exp $
+** $Id: expr.c,v 1.208 2005/06/25 18:42:14 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -34,12 +34,18 @@
 ** SELECT * FROM t1 WHERE (select a from t1);
 */
 char sqlite3ExprAffinity(Expr *pExpr){
-  if( pExpr->op==TK_AS ){
+  int op = pExpr->op;
+  if( op==TK_AS ){
     return sqlite3ExprAffinity(pExpr->pLeft);
   }
-  if( pExpr->op==TK_SELECT ){
+  if( op==TK_SELECT ){
     return sqlite3ExprAffinity(pExpr->pSelect->pEList->a[0].pExpr);
   }
+#ifndef SQLITE_OMIT_CAST
+  if( op==TK_CAST ){
+    return sqlite3AffinityType(&pExpr->token);
+  }
+#endif
   return pExpr->affinity;
 }
 
@@ -51,7 +57,7 @@
   CollSeq *pColl = 0;
   if( pExpr ){
     pColl = pExpr->pColl;
-    if( pExpr->op==TK_AS && !pColl ){
+    if( (pExpr->op==TK_AS || pExpr->op==TK_CAST) && !pColl ){
       return sqlite3ExprCollSeq(pParse, pExpr->pLeft);
     }
   }
@@ -1427,6 +1433,22 @@
       sqlite3VdbeAddOp(v, OP_MemLoad, pExpr->iTable, 0);
       break;
     }
+#ifndef SQLITE_OMIT_CAST
+    case TK_CAST: {
+      /* Expressions of the form:   CAST(pLeft AS token) */
+      int aff, op;
+      sqlite3ExprCode(pParse, pExpr->pLeft);
+      aff = sqlite3AffinityType(&pExpr->token);
+      switch( aff ){
+        case SQLITE_AFF_INTEGER:   op = OP_ToInt;      break;
+        case SQLITE_AFF_NUMERIC:   op = OP_ToNumeric;  break;
+        case SQLITE_AFF_TEXT:      op = OP_ToText;     break;
+        case SQLITE_AFF_NONE:      op = OP_ToBlob;     break;
+      }
+      sqlite3VdbeAddOp(v, op, 0, 0);
+      break;
+    }
+#endif /* SQLITE_OMIT_CAST */
     case TK_LT:
     case TK_LE:
     case TK_GT:
diff --git a/src/func.c b/src/func.c
index d13ba43..7e8fead 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.99 2005/06/22 10:53:59 drh Exp $
+** $Id: func.c,v 1.100 2005/06/25 18:42:14 drh Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -78,92 +78,6 @@
   sqlite3_result_text(context, z, -1, SQLITE_STATIC);
 }
 
-/*
-** Convert the argument to a numeric type.
-*/
-static void numericFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
-){
-  const char *z = 0;
-  switch( sqlite3_value_type(argv[0]) ){
-    case SQLITE_NULL: {
-      sqlite3_result_int(context, 0);
-      break;
-    }
-    case SQLITE_INTEGER:
-    case SQLITE_FLOAT: {
-      sqlite3_result_value(context, argv[0]);
-      break;
-    }
-    case SQLITE_TEXT:
-    case SQLITE_BLOB: {
-      z = sqlite3_value_text(argv[0]);
-      while( *z && *z!='.' ){ z++; }
-      if( *z ){
-        sqlite3_result_double(context, sqlite3_value_double(argv[0]));
-      }else{
-        sqlite3_result_int64(context, sqlite3_value_int64(argv[0]));
-      }
-      break;
-    }
-  }
-}
-
-/*
-** Convert the argument to TEXT
-*/
-static void textFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
-){
-  switch( sqlite3_value_type(argv[0]) ){
-    case SQLITE_NULL: {
-      sqlite3_result_text(context, "", 0, SQLITE_STATIC);
-      break;
-    }
-    case SQLITE_BLOB:
-    case SQLITE_INTEGER:
-    case SQLITE_FLOAT: {
-      sqlite3_result_text(context, sqlite3_value_text(argv[0]),
-          sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT);
-      break;
-    }
-    case SQLITE_TEXT: {
-      sqlite3_result_value(context, argv[0]);
-      break;
-    }
-  }
-}
-
-/*
-** Convert the argument to TEXT
-*/
-static void blobFunc(
-  sqlite3_context *context,
-  int argc,
-  sqlite3_value **argv
-){
-  switch( sqlite3_value_type(argv[0]) ){
-    case SQLITE_NULL: {
-      sqlite3_result_blob(context, "", 0, SQLITE_STATIC);
-      break;
-    }
-    case SQLITE_TEXT:
-    case SQLITE_INTEGER:
-    case SQLITE_FLOAT: {
-      sqlite3_result_blob(context, sqlite3_value_text(argv[0]),
-          sqlite3_value_bytes(argv[0]), SQLITE_TRANSIENT);
-      break;
-    }
-    case SQLITE_BLOB: {
-      sqlite3_result_value(context, argv[0]);
-      break;
-    }
-  }
-}
 
 /*
 ** Implementation of the length() function
@@ -1058,9 +972,6 @@
     { "last_insert_rowid",  0, 1, SQLITE_UTF8,    0, last_insert_rowid },
     { "changes",            0, 1, SQLITE_UTF8,    0, changes    },
     { "total_changes",      0, 1, SQLITE_UTF8,    0, total_changes },
-    { "text",               1, 0, SQLITE_UTF8,    0, textFunc      },
-    { "numeric",            1, 0, SQLITE_UTF8,    0, numericFunc   },
-    { "blob",               1, 0, SQLITE_UTF8,    0, blobFunc      },
 #ifdef SQLITE_SOUNDEX
     { "soundex",            1, 0, SQLITE_UTF8, 0, soundexFunc},
 #endif
diff --git a/src/parse.y b/src/parse.y
index 1f7c8af..bcb0014 100644
--- a/src/parse.y
+++ b/src/parse.y
@@ -14,12 +14,23 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.172 2005/05/23 17:26:51 drh Exp $
+** @(#) $Id: parse.y,v 1.173 2005/06/25 18:42:14 drh Exp $
 */
+
+// All token codes are small integers with #defines that begin with "TK_"
 %token_prefix TK_
+
+// The type of the data attached to each token is Token.  This is also the
+// default type for non-terminals.
+//
 %token_type {Token}
 %default_type {Token}
+
+// The generated parser function takes a 4th argument as follows:
 %extra_argument {Parse *pParse}
+
+// This code runs whenever there is a syntax error
+//
 %syntax_error {
   if( pParse->zErrMsg==0 ){
     if( TOKEN.z[0] ){
@@ -29,7 +40,14 @@
     }
   }
 }
+
+// The name of the generated procedure that implements the parser
+// is as follows:
 %name sqlite3Parser
+
+// The following text is included near the beginning of the C source
+// code file that implements the parser.
+//
 %include {
 #include "sqliteInt.h"
 #include "parse.h"
@@ -126,9 +144,10 @@
 columnlist ::= columnlist COMMA column.
 columnlist ::= column.
 
-// About the only information used for a column is the name of the
-// column.  The type is always just "text".  But the code will accept
-// an elaborate typename.  Perhaps someday we'll do something with it.
+// A "column" is a complete description of a single column in a
+// CREATE TABLE statement.  This includes the column name, its
+// datatype, and other keywords such as PRIMARY KEY, UNIQUE, REFERENCES,
+// NOT NULL and so forth.
 //
 column(A) ::= columnid(X) type carglist. {
   A.z = X.z;
@@ -151,7 +170,7 @@
 // This obviates the need for the "id" nonterminal.
 //
 %fallback ID
-  ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CONFLICT
+  ABORT AFTER ASC ATTACH BEFORE BEGIN CASCADE CAST CONFLICT
   DATABASE DEFERRED DESC DETACH EACH END EXCLUSIVE EXPLAIN FAIL FOR
   IGNORE IMMEDIATE INITIALLY INSTEAD LIKE_KW MATCH KEY
   OF OFFSET PRAGMA RAISE REPLACE RESTRICT ROW STATEMENT
@@ -198,17 +217,32 @@
 nm(A) ::= STRING(X).     {A = X;}
 nm(A) ::= JOIN_KW(X).    {A = X;}
 
+// A typetoken is really one or more tokens that form a type name such
+// as can be found after the column name in a CREATE TABLE statement.
+// Multiple tokens are concatenated to form the value of the typetoken.
+//
+%type typetoken {Token}
 type ::= .
-type ::= typename(X).                    {sqlite3AddColumnType(pParse,&X,&X);}
-type ::= typename(X) LP signed RP(Y).    {sqlite3AddColumnType(pParse,&X,&Y);}
-type ::= typename(X) LP signed COMMA signed RP(Y).
-                                         {sqlite3AddColumnType(pParse,&X,&Y);}
+type ::= typetoken(X).                   {sqlite3AddColumnType(pParse,&X);}
+typetoken(A) ::= typename(X).   {A = X;}
+typetoken(A) ::= typename(X) LP signed RP(Y). {
+  A.z = X.z;
+  A.n = &Y.z[Y.n] - X.z;
+}
+typetoken(A) ::= typename(X) LP signed COMMA signed RP(Y). {
+  A.z = X.z;
+  A.n = &Y.z[Y.n] - X.z;
+}
 %type typename {Token}
 typename(A) ::= ids(X).             {A = X;}
 typename(A) ::= typename(X) ids(Y). {A.z=X.z; A.n=Y.n+(Y.z-X.z);}
 %type signed {int}
 signed(A) ::= plus_num(X).    { A = atoi(X.z); }
 signed(A) ::= minus_num(X).   { A = -atoi(X.z); }
+
+// "carglist" is a list of additional constraints that come after the
+// column name and column type in a CREATE TABLE statement.
+//
 carglist ::= carglist carg.
 carglist ::= .
 carg ::= CONSTRAINT nm ccons.
@@ -619,6 +653,12 @@
   Expr *pExpr = A = sqlite3Expr(TK_VARIABLE, 0, 0, pToken);
   sqlite3ExprAssignVarNumber(pParse, pExpr);
 }
+%ifndef SQLITE_OMIT_CAST
+expr(A) ::= CAST(X) LP expr(E) AS typetoken(T) RP(Y). {
+  A = sqlite3Expr(TK_CAST, E, 0, &T);
+  sqlite3ExprSpan(A,&X,&Y);
+}
+%endif // SQLITE_OMIT_CAST
 expr(A) ::= ID(X) LP exprlist(Y) RP(E). {
   A = sqlite3ExprFunction(Y, &X);
   sqlite3ExprSpan(A,&X,&E);
diff --git a/src/sqliteInt.h b/src/sqliteInt.h
index 966090d..cac864c 100644
--- a/src/sqliteInt.h
+++ b/src/sqliteInt.h
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.387 2005/06/12 21:35:52 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.388 2005/06/25 18:42:14 drh Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -1369,7 +1369,7 @@
 void sqlite3AddColumn(Parse*,Token*);
 void sqlite3AddNotNull(Parse*, int);
 void sqlite3AddPrimaryKey(Parse*, ExprList*, int, int);
-void sqlite3AddColumnType(Parse*,Token*,Token*);
+void sqlite3AddColumnType(Parse*,Token*);
 void sqlite3AddDefaultValue(Parse*,Expr*);
 void sqlite3AddCollateType(Parse*, const char*, int);
 void sqlite3EndTable(Parse*,Token*,Token*,Select*);
@@ -1508,7 +1508,7 @@
 int sqlite3FixExpr(DbFixer*, Expr*);
 int sqlite3FixExprList(DbFixer*, ExprList*);
 int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
-double sqlite3AtoF(const char *z, const char **);
+int sqlite3AtoF(const char *z, double*);
 char *sqlite3_snprintf(int,char*,const char*,...);
 int sqlite3GetInt32(const char *, int*);
 int sqlite3FitsIn64Bits(const char *);
@@ -1563,6 +1563,7 @@
 void sqlite3AlterBeginAddColumn(Parse *, SrcList *);
 const char *sqlite3TestErrorName(int);
 CollSeq *sqlite3GetCollSeq(sqlite3*, CollSeq *, const char *, int);
+char sqlite3AffinityType(const Token*);
 
 #ifdef SQLITE_SSE
 #include "sseInt.h"
diff --git a/src/test1.c b/src/test1.c
index 7315991..dd7e06c 100644
--- a/src/test1.c
+++ b/src/test1.c
@@ -13,7 +13,7 @@
 ** is not included in the SQLite library.  It is used for automated
 ** testing of the SQLite library.
 **
-** $Id: test1.c,v 1.144 2005/06/12 22:01:43 drh Exp $
+** $Id: test1.c,v 1.145 2005/06/25 18:42:14 drh Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -2794,6 +2794,12 @@
   Tcl_SetVar2(interp, "sqlite_options", "bloblit", "1", TCL_GLOBAL_ONLY);
 #endif
 
+#ifdef SQLITE_OMIT_CAST
+  Tcl_SetVar2(interp, "sqlite_options", "cast", "0", TCL_GLOBAL_ONLY);
+#else
+  Tcl_SetVar2(interp, "sqlite_options", "cast", "1", TCL_GLOBAL_ONLY);
+#endif
+
 #ifdef SQLITE_OMIT_COMPLETE
   Tcl_SetVar2(interp, "sqlite_options", "complete", "0", TCL_GLOBAL_ONLY);
 #else
diff --git a/src/util.c b/src/util.c
index 2379412..80fc41d 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.137 2005/06/14 16:04:06 drh Exp $
+** $Id: util.c,v 1.138 2005/06/25 18:42:15 drh Exp $
 */
 #include "sqliteInt.h"
 #include <stdarg.h>
@@ -565,8 +565,9 @@
 ** of "." depending on how locale is set.  But that would cause problems
 ** for SQL.  So this routine always uses "." regardless of locale.
 */
-double sqlite3AtoF(const char *z, const char **pzEnd){
+int sqlite3AtoF(const char *z, double *pResult){
   int sign = 1;
+  const char *zBegin = z;
   LONGDOUBLE_TYPE v1 = 0.0;
   if( *z=='-' ){
     sign = -1;
@@ -613,8 +614,8 @@
       v1 *= scale;
     }
   }
-  if( pzEnd ) *pzEnd = z;
-  return sign<0 ? -v1 : v1;
+  *pResult = sign<0 ? -v1 : v1;
+  return z - zBegin;
 }
 
 /*
diff --git a/src/vdbe.c b/src/vdbe.c
index 4d01241..1530511 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.471 2005/06/24 03:53:06 drh Exp $
+** $Id: vdbe.c,v 1.472 2005/06/25 18:42:15 drh Exp $
 */
 #include "sqliteInt.h"
 #include "os.h"
@@ -1379,6 +1379,94 @@
   break;
 }
 
+#ifndef SQLITE_OMIT_CAST
+/* Opcode: ToInt * * *
+**
+** Force the value on the top of the stack to be an integer.  If
+** The value is currently a real number, drop its fractional part.
+** If the value is text or blob, try to convert it to an integer using the
+** equivalent of atoi() and store 0 if no such conversion is possible.
+**
+** A NULL value is not changed by this routine.  It remains NULL.
+*/
+case OP_ToInt: {                  /* no-push */
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;
+  assert( MEM_Str==(MEM_Blob>>3) );
+  pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+  applyAffinity(pTos, SQLITE_AFF_INTEGER, db->enc);
+  sqlite3VdbeMemIntegerify(pTos);
+  break;
+}
+
+/* Opcode: ToNumeric * * *
+**
+** Force the value on the top of the stack to be numeric (either an
+** integer or a floating-point number.
+** If the value is text or blob, try to convert it to an using the
+** equivalent of atoi() or atof() and store 0 if no such conversion 
+** is possible.
+**
+** A NULL value is not changed by this routine.  It remains NULL.
+*/
+case OP_ToNumeric: {                  /* no-push */
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;
+  assert( MEM_Str==(MEM_Blob>>3) );
+  pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+  applyAffinity(pTos, SQLITE_AFF_NUMERIC, db->enc);
+  if( (pTos->flags & (MEM_Int|MEM_Real))==0 ){
+    sqlite3VdbeMemRealify(pTos);
+  }else{
+    sqlite3VdbeMemRelease(pTos);
+  }
+  assert( (pTos->flags & MEM_Dyn)==0 );
+  pTos->flags &= (MEM_Int|MEM_Real);
+  break;
+}
+
+/* Opcode: ToText * * *
+**
+** Force the value on the top of the stack to be text.
+** If the value is numeric, convert it to an using the
+** equivalent of printf().  Blob values are unchanged and
+** are afterwards simply interpreted as text.
+**
+** A NULL value is not changed by this routine.  It remains NULL.
+*/
+case OP_ToText: {                  /* no-push */
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;
+  assert( MEM_Str==(MEM_Blob>>3) );
+  pTos->flags |= (pTos->flags&MEM_Blob)>>3;
+  applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
+  assert( pTos->flags & MEM_Str );
+  pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Blob);
+  break;
+}
+
+/* Opcode: ToBlob * * *
+**
+** Force the value on the top of the stack to be a BLOB.
+** If the value is numeric, convert it to a string first.
+** Strings are simply reinterpreted as blobs with no change
+** to the underlying data.
+**
+** A NULL value is not changed by this routine.  It remains NULL.
+*/
+case OP_ToBlob: {                  /* no-push */
+  assert( pTos>=p->aStack );
+  if( pTos->flags & MEM_Null ) break;
+  if( (pTos->flags & MEM_Blob)==0 ){
+    applyAffinity(pTos, SQLITE_AFF_TEXT, db->enc);
+    assert( pTos->flags & MEM_Str );
+    pTos->flags |= MEM_Blob;
+  }
+  pTos->flags &= ~(MEM_Int|MEM_Real|MEM_Str);
+  break;
+}
+#endif /* SQLITE_OMIT_CAST */
+
 /* Opcode: Eq P1 P2 P3
 **
 ** Pop the top two elements from the stack.  If they are equal, then
@@ -2154,6 +2242,7 @@
     pTos->flags = MEM_Blob | MEM_Dyn;
     pTos->xDel = 0;
   }
+  pTos->enc = SQLITE_UTF8;  /* In case the blob is ever converted to text */
 
   /* If a NULL was encountered and jumpIfNull is non-zero, take the jump. */
   if( jumpIfNull && containsNull ){
@@ -3289,6 +3378,7 @@
   }else{
     pTos->flags = MEM_Null;
   }
+  pTos->enc = SQLITE_UTF8;  /* In case the blob is ever cast to text */
   break;
 }
 
diff --git a/src/vdbemem.c b/src/vdbemem.c
index f08671f..37113b9 100644
--- a/src/vdbemem.c
+++ b/src/vdbemem.c
@@ -256,12 +256,14 @@
   }else if( pMem->flags & MEM_Int ){
     return (double)pMem->i;
   }else if( pMem->flags & (MEM_Str|MEM_Blob) ){
+    double val = 0.0;
     if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
        || sqlite3VdbeMemNulTerminate(pMem) ){
       return SQLITE_NOMEM;
     }
     assert( pMem->z );
-    return sqlite3AtoF(pMem->z, 0);
+    sqlite3AtoF(pMem->z, &val);
+    return val;
   }else{
     return 0.0;
   }
@@ -406,6 +408,7 @@
   switch( enc ){
     case 0:
       pMem->flags |= MEM_Blob;
+      pMem->enc = SQLITE_UTF8;
       break;
 
     case SQLITE_UTF8: