]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Rework the text to numeric conversion routines so that they work with either
authordrh <drh@noemail.net>
Thu, 30 Sep 2010 00:50:49 +0000 (00:50 +0000)
committerdrh <drh@noemail.net>
Thu, 30 Sep 2010 00:50:49 +0000 (00:50 +0000)
UTF8 or UTF16 and do not require a NULL terminator.  This allowed text to
numeric conversion without reallocating the string.

FossilOrigin-Name: 14eed3a0e0a45c6f2904a3a134aa27c159916f7b

manifest
manifest.uuid
src/date.c
src/expr.c
src/func.c
src/pragma.c
src/sqliteInt.h
src/test1.c
src/util.c
src/vdbe.c
src/vdbemem.c

index 9ac8249785a0b072a99e940729aed3ddad988b4f..39e52bb94338dd910c395b811b395dd9b88a2993 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,8 @@
-C Add\stest\scases\sto\se_createtable.test.
-D 2010-09-29T18:26:24
+-----BEGIN PGP SIGNED MESSAGE-----
+Hash: SHA1
+
+C Rework\sthe\stext\sto\snumeric\sconversion\sroutines\sso\sthat\sthey\swork\swith\seither\nUTF8\sor\sUTF16\sand\sdo\snot\srequire\sa\sNULL\sterminator.\s\sThis\sallowed\stext\sto\nnumeric\sconversion\swithout\sreallocating\sthe\sstring.
+D 2010-09-30T00:50:50
 F Makefile.arm-wince-mingw32ce-gcc d6df77f1f48d690bd73162294bbba7f59507c72f
 F Makefile.in c599a15d268b1db2aeadea19df2adc3bf2eb6bee
 F Makefile.linux-gcc 91d710bdc4998cb015f39edf3cb314ec4f4d7e23
@@ -125,12 +128,12 @@ F src/build.c 00a327120d81ace6267e714ae8010c997d55de5d
 F src/callback.c a1d1b1c9c85415dff013af033e2fed9c8382d33b
 F src/complete.c dc1d136c0feee03c2f7550bafc0d29075e36deac
 F src/ctime.c 4f3aadad62c6c9f0d4e5a96718516ac4e3c598df
-F src/date.c 5dd8448a0bfea8d31fb14cff487d0c06ff8c8b20
+F src/date.c 1548fdac51377e4e7833251de878b4058c148e1b
 F src/delete.c 7ed8a8c8b5f748ece92df173d7e0f7810c899ebd
-F src/expr.c 1caa723c3ab7a7e35952bc85a6f4a7da3632308f
+F src/expr.c 05dbb04833ea04c28e835bf67295e367ca1c52d8
 F src/fault.c 160a0c015b6c2629d3899ed2daf63d75754a32bb
 F src/fkey.c 17950a28f28b23e8ad3feaac5fc88c324d2f600a
-F src/func.c b5664982355274c264afe90efd7f694d447a594a
+F src/func.c 2b7cf54d2569c2eba42fe81165d1932b546681a3
 F src/global.c 02335177cf6946fe5525c6f0755cf181140debf3
 F src/hash.c 458488dcc159c301b8e7686280ab209f1fb915af
 F src/hash.h 2894c932d84d9f892d4b4023a75e501f83050970
@@ -167,7 +170,7 @@ F src/parse.y 12b7ebd61ea54f0e1b1083ff69cc2c8ce9353d58
 F src/pcache.c 09d38c44ab275db581f7a2f6ff8b9bc7f8c0faaa
 F src/pcache.h c683390d50f856d4cd8e24342ae62027d1bb6050
 F src/pcache1.c e9578a3beac26f229ee558a4e16c863f2498185f
-F src/pragma.c 8b24ce00a93de345b6c3bd1e1e2cfba9f63d2325
+F src/pragma.c 216d12e4546e65ca6cfcd3221e64573889ae8f34
 F src/prepare.c ce4c35a2b1d5fe916e4a46b70d24a6e997d7c4c6
 F src/printf.c 8ae5082dd38a1b5456030c3755ec3a392cd51506
 F src/random.c cd4a67b3953b88019f8cd4ccd81394a8ddfaba50
@@ -177,12 +180,12 @@ F src/select.c cf3013b1953348c7c6ff9636342e87b9fda68466
 F src/shell.c 8517fc1f9c59ae4007e6cc8b9af91ab231ea2056
 F src/sqlite.h.in a5b50e1bc4d4d9a3cc95386747220a839d0c40f7
 F src/sqlite3ext.h 69dfb8116af51b84a029cddb3b35062354270c89
-F src/sqliteInt.h ea31c7867d910c1da9b20adb6614e474011fbae0
+F src/sqliteInt.h 6fb1558f7810dc13406c7629b9ea20ec46b701e8
 F src/sqliteLimit.h a17dcd3fb775d63b64a43a55c54cb282f9726f44
 F src/status.c 496913d4e8441195f6f2a75b1c95993a45b9b30b
 F src/table.c 2cd62736f845d82200acfa1287e33feb3c15d62e
 F src/tclsqlite.c e91019fb6787166abca23a81b16c07fecc2ed751
-F src/test1.c a0f135000894cb5a3d32d23fd74a83939ca854fa
+F src/test1.c 6fbbb504a7d1069415e443ae687d61cab72fa51e
 F src/test2.c 80d323d11e909cf0eb1b6fbb4ac22276483bcf31
 F src/test3.c 056093cfef69ff4227a6bdb9108564dc7f45e4bc
 F src/test4.c 0528360b5025688002a5feb6be906ddce52eaaee
@@ -223,15 +226,15 @@ F src/tokenize.c 604607d6813e9551cf5189d899e0a25c12681080
 F src/trigger.c b8bedb9c0084ceb51a40f54fcca2ce048c8de852
 F src/update.c 227e6cd512108b84f69421fc6c7aa1b83d60d6e0
 F src/utf.c 1baeeac91707a4df97ccc6141ec0f808278af685
-F src/util.c 5f5f4db4e799224713582bb49124827b16aa8e54
+F src/util.c 7a5fb16c0b9a3e4c9fa6c375c8f514bc3bb155b6
 F src/vacuum.c 924bd1bcee2dfb05376f79845bd3b4cec7b54b2f
-F src/vdbe.c 69812aabf486a2d6a5b0960ffd9a47d141442735
+F src/vdbe.c 04cf7c1b0b7a7dc825ddde202307ca15c1115fbb
 F src/vdbe.h 4de0efb4b0fdaaa900cf419b35c458933ef1c6d2
 F src/vdbeInt.h 7f4cf1b2b69bef3a432b1f23dfebef57275436b4
 F src/vdbeapi.c 03cddfa4f85cadf608c0d28ff6b622b7da432446
 F src/vdbeaux.c de0b06b11a25293e820a49159eca9f1c51a64716
 F src/vdbeblob.c 258a6010ba7a82b72b327fb24c55790655689256
-F src/vdbemem.c 8ff4f80a35d51f3690c191ec44778ef4bf949ac0
+F src/vdbemem.c cfb178242f38fb03a44672268afa05716d55e769
 F src/vdbetrace.c 864cef96919323482ebd9986f2132435115e9cc2
 F src/vtab.c 6c90e3e65b2f026fc54703a8f3c917155f419d87
 F src/wal.c 7081f148cb52b0cf2280e6384196402dc58130a3
@@ -869,7 +872,18 @@ F tool/speedtest2.tcl ee2149167303ba8e95af97873c575c3e0fab58ff
 F tool/speedtest8.c 2902c46588c40b55661e471d7a86e4dd71a18224
 F tool/speedtest8inst1.c 293327bc76823f473684d589a8160bde1f52c14e
 F tool/vdbe-compress.tcl d70ea6d8a19e3571d7ab8c9b75cba86d1173ff0f
-P 1ef0dc9328f47506cb2dcd142150e96cb4755216
-R 02e67e0f9fa41ba7fd1a6b2afec8e896
-U dan
-Z d7addcf9b4085ef482cc086b59137f66
+P f34dc54d46d05adf1f52db51442195b3285a26b9
+R 5e9e2523f82be46cc8ebbb892165bffa
+T *bgcolor * #c0ffc0
+T *branch * experimental
+T *sym-experimental *
+T -sym-trunk *
+U drh
+Z 0c6ebf88312d1668689f16e4194172bb
+-----BEGIN PGP SIGNATURE-----
+Version: GnuPG v1.4.6 (GNU/Linux)
+
+iD8DBQFMo97toxKgR168RlERAi5jAJsFDVqJu9wdOQNwlT2y3q2TNuHUGQCdFwrP
+sR9IRwN4k3Y2ZVtzQE0tnsY=
+=6xoC
+-----END PGP SIGNATURE-----
index 99bd7efabfaf835c15792f965b3555281d660c05..59c95200eac2fd8075c92eed9f8eb2934e14e215 100644 (file)
@@ -1 +1 @@
-f34dc54d46d05adf1f52db51442195b3285a26b9
\ No newline at end of file
+14eed3a0e0a45c6f2904a3a134aa27c159916f7b
\ No newline at end of file
index 04ffbe23ce8090e2735ad61aabb01fbdd6556436..b81049aa6531de3158c3f6656024b36011f419c4 100644 (file)
@@ -133,12 +133,6 @@ end_getDigits:
   return cnt;
 }
 
-/*
-** Read text from z[] and convert into a floating point number.  Return
-** the number of digits converted.
-*/
-#define getValue sqlite3AtoF
-
 /*
 ** Parse a timezone extension on the end of a date-time.
 ** The extension is of the form:
@@ -340,7 +334,7 @@ static int parseDateOrTime(
   const char *zDate, 
   DateTime *p
 ){
-  int isRealNum;    /* Return from sqlite3IsNumber().  Not used */
+  double r;
   if( parseYyyyMmDd(zDate,p)==0 ){
     return 0;
   }else if( parseHhMmSs(zDate, p)==0 ){
@@ -348,9 +342,7 @@ static int parseDateOrTime(
   }else if( sqlite3StrICmp(zDate,"now")==0){
     setDateTimeToCurrent(context, p);
     return 0;
-  }else if( sqlite3IsNumber(zDate, &isRealNum, SQLITE_UTF8) ){
-    double r;
-    getValue(zDate, &r);
+  }else if( sqlite3AtoF(zDate, &r, sqlite3Strlen30(zDate), SQLITE_UTF8) ){
     p->iJD = (sqlite3_int64)(r*86400000.0 + 0.5);
     p->validJD = 1;
     return 0;
@@ -571,8 +563,9 @@ static int parseModifier(const char *zMod, DateTime *p){
       ** weekday N where 0==Sunday, 1==Monday, and so forth.  If the
       ** date is already on the appropriate weekday, this is a no-op.
       */
-      if( strncmp(z, "weekday ", 8)==0 && getValue(&z[8],&r)>0
-                 && (n=(int)r)==r && n>=0 && r<7 ){
+      if( strncmp(z, "weekday ", 8)==0
+               && sqlite3AtoF(&z[8], &r, sqlite3Strlen30(&z[8]), SQLITE_UTF8)
+               && (n=(int)r)==r && n>=0 && r<7 ){
         sqlite3_int64 Z;
         computeYMD_HMS(p);
         p->validTZ = 0;
@@ -627,8 +620,11 @@ static int parseModifier(const char *zMod, DateTime *p){
     case '8':
     case '9': {
       double rRounder;
-      n = getValue(z, &r);
-      assert( n>=1 );
+      for(n=1; z[n] && z[n]!=':' && !sqlite3Isspace(z[n]); n++){}
+      if( !sqlite3AtoF(z, &r, n, SQLITE_UTF8) ){
+        rc = 1;
+        break;
+      }
       if( z[n]==':' ){
         /* A modifier of the form (+|-)HH:MM:SS.FFF adds (or subtracts) the
         ** specified number of hours, minutes, seconds, and fractional seconds
index 24746352180bccd62e4dcee63bb3245307f6161b..cf1823d9d848b49f2803cf844d72ac3ea796eaa7 100644 (file)
@@ -555,7 +555,7 @@ void sqlite3ExprAssignVarNumber(Parse *pParse, Expr *pExpr){
     /* Wildcard of the form "?nnn".  Convert "nnn" to an integer and
     ** use it as the variable number */
     i64 i;
-    int bOk = sqlite3Atoi64(&z[1], &i);
+    int bOk = sqlite3Atoi64(&z[1], &i, sqlite3Strlen30(&z[1]), SQLITE_UTF8);
     pExpr->iColumn = (ynVar)i;
     testcase( i==0 );
     testcase( i==1 );
@@ -1918,7 +1918,7 @@ static void codeReal(Vdbe *v, const char *z, int negateFlag, int iMem){
   if( ALWAYS(z!=0) ){
     double value;
     char *zV;
-    sqlite3AtoF(z, &value);
+    sqlite3AtoF(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
     assert( !sqlite3IsNaN(value) ); /* The new AtoF never returns NaN */
     if( negateFlag ) value = -value;
     zV = dup8bytes(v, (char*)&value);
@@ -1948,7 +1948,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){
     if( sqlite3FitsIn64Bits(z, negFlag) ){
       i64 value;
       char *zV;
-      sqlite3Atoi64(z, &value);
+      sqlite3Atoi64(z, &value, sqlite3Strlen30(z), SQLITE_UTF8);
       if( negFlag ) value = -value;
       zV = dup8bytes(v, (char*)&value);
       sqlite3VdbeAddOp4(v, OP_Int64, 0, iMem, 0, zV, P4_INT64);
index 6119e4a95620f7b2bb2ebadbd3ad88792226c3a1..8b7086f600e8134c766289a59f8a490ccc184448 100644 (file)
@@ -285,7 +285,7 @@ static void roundFunc(sqlite3_context *context, int argc, sqlite3_value **argv){
       sqlite3_result_error_nomem(context);
       return;
     }
-    sqlite3AtoF(zBuf, &r);
+    sqlite3AtoF(zBuf, &r, sqlite3Strlen30(zBuf), SQLITE_UTF8);
     sqlite3_free(zBuf);
   }
   sqlite3_result_double(context, r);
index 0f3ce3c5245ace75363008c856199203573e6d4b..362e77f29e955ee15130362459936d72ee51ecac 100644 (file)
@@ -587,7 +587,7 @@ void sqlite3Pragma(
     Pager *pPager = sqlite3BtreePager(pDb->pBt);
     i64 iLimit = -2;
     if( zRight ){
-      sqlite3Atoi64(zRight, &iLimit);
+      sqlite3Atoi64(zRight, &iLimit, 1000000, SQLITE_UTF8);
       if( iLimit<-1 ) iLimit = -1;
     }
     iLimit = sqlite3PagerJournalSizeLimit(pPager, iLimit);
index adf6ce8a287cc9c74ec4b75d741af73cc795ddae..dd5d239438e7ead12a7adcce927f494e8922a205 100644 (file)
@@ -2507,7 +2507,6 @@ int sqlite3CantopenError(int);
 ** Internal function prototypes
 */
 int sqlite3StrICmp(const char *, const char *);
-int sqlite3IsNumber(const char*, int*, u8);
 int sqlite3Strlen30(const char*);
 #define sqlite3StrNICmp sqlite3_strnicmp
 
@@ -2827,7 +2826,7 @@ int sqlite3FixSelect(DbFixer*, Select*);
 int sqlite3FixExpr(DbFixer*, Expr*);
 int sqlite3FixExprList(DbFixer*, ExprList*);
 int sqlite3FixTriggerStep(DbFixer*, TriggerStep*);
-int sqlite3AtoF(const char *z, double*);
+int sqlite3AtoF(const char *z, double*, int, u8);
 int sqlite3GetInt32(const char *, int*);
 int sqlite3FitsIn64Bits(const char *, int);
 int sqlite3Utf16ByteLen(const void *pData, int nChar);
@@ -2875,7 +2874,7 @@ void sqlite3TableAffinityStr(Vdbe *, Table *);
 char sqlite3CompareAffinity(Expr *pExpr, char aff2);
 int sqlite3IndexAffinityOk(Expr *pExpr, char idx_affinity);
 char sqlite3ExprAffinity(Expr *pExpr);
-int sqlite3Atoi64(const char*, i64*);
+int sqlite3Atoi64(const char*, i64*, int, u8);
 void sqlite3Error(sqlite3*, int, const char*,...);
 void *sqlite3HexToBlob(sqlite3*, const char *z, int n);
 int sqlite3TwoPartName(Parse *, Token *, Token *, Token **);
index 8e827f07ba82ae1d3d035dff5306e2101f3a55c8..b83263d00bd03616257c91d8809f3fec70850078 100644 (file)
@@ -1235,7 +1235,7 @@ static int sqlite3_mprintf_int64(
     return TCL_ERROR;
   }
   for(i=2; i<5; i++){
-    if( !sqlite3Atoi64(argv[i], &a[i-2]) ){
+    if( !sqlite3Atoi64(argv[i], &a[i-2], 1000000, SQLITE_UTF8) ){
       Tcl_AppendResult(interp, "argument is not a valid 64-bit integer", 0);
       return TCL_ERROR;
     }
index 6b30b311ae35e6075c2f6b220a3d2006efb79230..36689ec1d379feb7247707b31d28820f85638504 100644 (file)
@@ -238,61 +238,19 @@ int sqlite3_strnicmp(const char *zLeft, const char *zRight, int N){
 }
 
 /*
-** Return TRUE if z is a pure numeric string.  Return FALSE and leave
-** *realnum unchanged if the string contains any character which is not
-** part of a number.
-**
-** If the string is pure numeric, set *realnum to TRUE if the string
-** contains the '.' character or an "E+000" style exponentiation suffix.
-** Otherwise set *realnum to FALSE.  Note that just becaue *realnum is
-** false does not mean that the number can be successfully converted into
-** an integer - it might be too big.
-**
-** An empty string is considered non-numeric.
-*/
-int sqlite3IsNumber(const char *z, int *realnum, u8 enc){
-  int incr = (enc==SQLITE_UTF8?1:2);
-  if( enc==SQLITE_UTF16BE ) z++;
-  if( *z=='-' || *z=='+' ) z += incr;
-  if( !sqlite3Isdigit(*z) ){
-    return 0;
-  }
-  z += incr;
-  *realnum = 0;
-  while( sqlite3Isdigit(*z) ){ z += incr; }
-#ifndef SQLITE_OMIT_FLOATING_POINT
-  if( *z=='.' ){
-    z += incr;
-    if( !sqlite3Isdigit(*z) ) return 0;
-    while( sqlite3Isdigit(*z) ){ z += incr; }
-    *realnum = 1;
-  }
-  if( *z=='e' || *z=='E' ){
-    z += incr;
-    if( *z=='+' || *z=='-' ) z += incr;
-    if( !sqlite3Isdigit(*z) ) return 0;
-    while( sqlite3Isdigit(*z) ){ z += incr; }
-    *realnum = 1;
-  }
-#endif
-  return *z==0;
-}
-
-/*
-** The string z[] is an ASCII representation of a real number.
+** The string z[] is an text representation of a real number.
 ** Convert this string to a double.
 **
-** This routine assumes that z[] really is a valid number.  If it
-** is not, the result is undefined.
+** The string z[] is length bytes in length (bytes, not characters) and
+** uses the encoding enc.  The string is not necessarily zero-terminated.
 **
-** This routine is used instead of the library atof() function because
-** the library atof() might want to use "," as the decimal point instead
-** of "." depending on how locale is set.  But that would cause problems
-** for SQL.  So this routine always uses "." regardless of locale.
+** Return TRUE if the result is a valid real number (or integer) and FALSE
+** if the string is empty or contains extraneous text.
 */
-int sqlite3AtoF(const char *z, double *pResult){
+int sqlite3AtoF(const char *z, double *pResult, int length, u8 enc){
 #ifndef SQLITE_OMIT_FLOATING_POINT
-  const char *zBegin = z;
+  int incr = (enc==SQLITE_UTF8?1:2);
+  const char *zEnd = z + length;
   /* sign * significand * (10 ^ (esign * exponent)) */
   int sign = 1;   /* sign of significand */
   i64 s = 0;      /* significand */
@@ -302,57 +260,70 @@ int sqlite3AtoF(const char *z, double *pResult){
   double result;
   int nDigits = 0;
 
+  if( enc==SQLITE_UTF16BE ) z++;
+
   /* skip leading spaces */
-  while( sqlite3Isspace(*z) ) z++;
+  while( z<zEnd && sqlite3Isspace(*z) ) z+=incr;
+  if( z>=zEnd ){
+    *pResult = 0.0;
+    return 0;
+  }
+
   /* get sign of significand */
   if( *z=='-' ){
     sign = -1;
-    z++;
+    z+=incr;
   }else if( *z=='+' ){
-    z++;
+    z+=incr;
   }
+
   /* skip leading zeroes */
-  while( z[0]=='0' ) z++, nDigits++;
+  while( z<zEnd && z[0]=='0' ) z+=incr, nDigits++;
 
   /* copy max significant digits to significand */
-  while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+  while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
     s = s*10 + (*z - '0');
-    z++, nDigits++;
+    z+=incr, nDigits++;
   }
+
   /* skip non-significant significand digits
   ** (increase exponent by d to shift decimal left) */
-  while( sqlite3Isdigit(*z) ) z++, nDigits++, d++;
+  while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++, d++;
+  if( z>=zEnd ) goto do_atof_calc;
 
   /* if decimal point is present */
   if( *z=='.' ){
-    z++;
+    z+=incr;
     /* copy digits from after decimal to significand
     ** (decrease exponent by d to shift decimal right) */
-    while( sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
+    while( z<zEnd && sqlite3Isdigit(*z) && s<((LARGEST_INT64-9)/10) ){
       s = s*10 + (*z - '0');
-      z++, nDigits++, d--;
+      z+=incr, nDigits++, d--;
     }
     /* skip non-significant digits */
-    while( sqlite3Isdigit(*z) ) z++, nDigits++;
+    while( z<zEnd && sqlite3Isdigit(*z) ) z+=incr, nDigits++;
   }
+  if( z>=zEnd ) goto do_atof_calc;
 
   /* if exponent is present */
   if( *z=='e' || *z=='E' ){
-    z++;
+    z+=incr;
+    if( z>=zEnd ) goto do_atof_calc;
     /* get sign of exponent */
     if( *z=='-' ){
       esign = -1;
-      z++;
+      z+=incr;
     }else if( *z=='+' ){
-      z++;
+      z+=incr;
     }
     /* copy digits to exponent */
-    while( sqlite3Isdigit(*z) ){
+    while( z<zEnd && sqlite3Isdigit(*z) ){
       e = e*10 + (*z - '0');
-      z++;
+      z+=incr;
     }
   }
 
+do_atof_calc:
   /* adjust exponent by d, and update sign */
   e = (e*esign) + d;
   if( e<0 ) {
@@ -411,10 +382,10 @@ int sqlite3AtoF(const char *z, double *pResult){
   /* store the result */
   *pResult = result;
 
-  /* return number of characters used */
-  return (int)(z - zBegin);
+  /* return number of bytes used */
+  return z>=zEnd && sqlite3Isdigit(z[-incr]);
 #else
-  return sqlite3Atoi64(z, pResult);
+  return sqlite3Atoi64(z, pResult, length, enc);
 #endif /* SQLITE_OMIT_FLOATING_POINT */
 }
 
@@ -427,15 +398,20 @@ int sqlite3AtoF(const char *z, double *pResult){
 ** in the values of the last digit if the only difference is in the
 ** last digit.  So, for example,
 **
-**      compare2pow63("9223372036854775800")
+**      compare2pow63("9223372036854775800", 1)
 **
 ** will return -8.
 */
-static int compare2pow63(const char *zNum){
-  int c;
-  c = memcmp(zNum,"922337203685477580",18)*10;
+static int compare2pow63(const char *zNum, int incr){
+  int c = 0;
+  int i;
+                    /* 012345678901234567 */
+  const char *pow63 = "922337203685477580";
+  for(i=0; c==0 && i<18; i++){
+    c = (zNum[i*incr]-pow63[i])*10;
+  }
   if( c==0 ){
-    c = zNum[18] - '8';
+    c = zNum[18*incr] - '8';
     testcase( c==(-1) );
     testcase( c==0 );
     testcase( c==(+1) );
@@ -450,46 +426,52 @@ static int compare2pow63(const char *zNum){
 ** or is an integer that is too large to be expressed with 64 bits,
 ** then return false.
 **
-** When this routine was originally written it dealt with only
-** 32-bit numbers.  At that time, it was much faster than the
-** atoi() library routine in RedHat 7.2.
+** length is the number of bytes in the string (bytes, not characters).
+** The string is not necessarily zero-terminated.  The encoding is
+** given by enc.
 */
-int sqlite3Atoi64(const char *zNum, i64 *pNum){
+int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
+  int incr = (enc==SQLITE_UTF8?1:2);
   i64 v = 0;
-  int neg;
-  int i, c;
+  int neg = 0;
+  int i;
+  int c = 0;
   const char *zStart;
-  while( sqlite3Isspace(*zNum) ) zNum++;
+  const char *zEnd = zNum + length;
+  if( enc==SQLITE_UTF16BE ) zNum++;
+  while( zNum<zEnd && sqlite3Isspace(*zNum) ) zNum+=incr;
+  if( zNum>=zEnd ) goto do_atoi_calc;
   if( *zNum=='-' ){
     neg = 1;
-    zNum++;
+    zNum+=incr;
   }else if( *zNum=='+' ){
     neg = 0;
-    zNum++;
+    zNum+=incr;
   }else{
     neg = 0;
   }
+do_atoi_calc:
   zStart = zNum;
-  while( zNum[0]=='0' ){ zNum++; } /* Skip over leading zeros. Ticket #2454 */
-  for(i=0; (c=zNum[i])>='0' && c<='9'; i++){
+  while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
+  for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
     v = v*10 + c - '0';
   }
   *pNum = neg ? -v : v;
   testcase( i==18 );
   testcase( i==19 );
   testcase( i==20 );
-  if( c!=0 || (i==0 && zStart==zNum) || i>19 ){
+  if( (c!=0 && &zNum[i]<zEnd) || (i==0 && zStart==zNum) || i>19*incr ){
     /* zNum is empty or contains non-numeric text or is longer
     ** than 19 digits (thus guaranting that it is too large) */
     return 0;
-  }else if( i<19 ){
+  }else if( i<19*incr ){
     /* Less than 19 digits, so we know that it fits in 64 bits */
     return 1;
   }else{
     /* 19-digit numbers must be no larger than 9223372036854775807 if positive
     ** or 9223372036854775808 if negative.  Note that 9223372036854665808
     ** is 2^63. */
-    return compare2pow63(zNum)<neg;
+    return compare2pow63(zNum, incr)<neg;
   }
 }
 
@@ -532,7 +514,7 @@ int sqlite3FitsIn64Bits(const char *zNum, int negFlag){
     return 0;
   }else{
     /* Compare against 2^63. */
-    return compare2pow63(zNum)<neg;
+    return compare2pow63(zNum, 1)<neg;
   }
 }
 
index 90312cac729f8f21ca0bec8933a8c625f58faf7e..79dfff3ea993d093dbd2da904dc55d4790ccfbda 100644 (file)
@@ -249,31 +249,17 @@ static VdbeCursor *allocateCursor(
 */
 static void applyNumericAffinity(Mem *pRec){
   if( (pRec->flags & (MEM_Real|MEM_Int))==0 ){
-    int realnum;
+    double rValue;
+    i64 iValue;
     u8 enc = pRec->enc;
-    sqlite3VdbeMemNulTerminate(pRec);
-    if( (pRec->flags&MEM_Str) && sqlite3IsNumber(pRec->z, &realnum, enc) ){
-      i64 value;
-      char *zUtf8 = pRec->z;
-#ifndef SQLITE_OMIT_UTF16
-      if( enc!=SQLITE_UTF8 ){
-        assert( pRec->db );
-        zUtf8 = sqlite3Utf16to8(pRec->db, pRec->z, pRec->n, enc);
-        if( !zUtf8 ) return;
-      }
-#endif
-      if( !realnum && sqlite3Atoi64(zUtf8, &value) ){
-        pRec->u.i = value;
-        MemSetTypeFlag(pRec, MEM_Int);
-      }else{
-        sqlite3AtoF(zUtf8, &pRec->r);
-        MemSetTypeFlag(pRec, MEM_Real);
-      }
-#ifndef SQLITE_OMIT_UTF16
-      if( enc!=SQLITE_UTF8 ){
-        sqlite3DbFree(pRec->db, zUtf8);
-      }
-#endif
+    if( (pRec->flags&MEM_Str)==0 ) return;
+    if( sqlite3AtoF(pRec->z, &rValue, pRec->n, enc)==0 ) return;
+    if( sqlite3Atoi64(pRec->z, &iValue, pRec->n, enc) ){
+      pRec->u.i = iValue;
+      pRec->flags |= MEM_Int;
+    }else{
+      pRec->r = rValue;
+      pRec->flags |= MEM_Real;
     }
   }
 }
index 0b7c70d3bd99153ac50979f2299314514760d4bd..bab2ff3c0fc9fe9faf80edcdc246acffbb586b44 100644 (file)
@@ -368,13 +368,9 @@ i64 sqlite3VdbeIntValue(Mem *pMem){
     return doubleToInt64(pMem->r);
   }else if( flags & (MEM_Str|MEM_Blob) ){
     i64 value;
-    pMem->flags |= MEM_Str;
-    if( sqlite3VdbeChangeEncoding(pMem, SQLITE_UTF8)
-       || sqlite3VdbeMemNulTerminate(pMem) ){
-      return 0;
-    }
-    assert( pMem->z );
-    sqlite3Atoi64(pMem->z, &value);
+    assert( pMem->z || pMem->n==0 );
+    testcase( pMem->z==0 );
+    sqlite3Atoi64(pMem->z, &value, pMem->n, pMem->enc);
     return value;
   }else{
     return 0;
@@ -404,7 +400,7 @@ double sqlite3VdbeRealValue(Mem *pMem){
       return (double)0;
     }
     assert( pMem->z );
-    sqlite3AtoF(pMem->z, &val);
+    sqlite3AtoF(pMem->z, &val, pMem->n, SQLITE_UTF8);
     return val;
   }else{
     /* (double)0 In case of SQLITE_OMIT_FLOATING_POINT... */
@@ -485,7 +481,7 @@ int sqlite3VdbeMemNumerify(Mem *pMem){
   if( rc ) return rc;
   rc = sqlite3VdbeMemNulTerminate(pMem);
   if( rc ) return rc;
-  if( sqlite3Atoi64(pMem->z, &pMem->u.i) ){
+  if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, SQLITE_UTF8) ){
     MemSetTypeFlag(pMem, MEM_Int);
   }else{
     pMem->r = sqlite3VdbeRealValue(pMem);