]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Improve text-to-integer conversion in boundary cases. The
authordrh <drh@noemail.net>
Fri, 26 Jan 2018 18:37:34 +0000 (18:37 +0000)
committerdrh <drh@noemail.net>
Fri, 26 Jan 2018 18:37:34 +0000 (18:37 +0000)
sqlite3Atoi64() function always returns the minimum or maximum integer
if the magnitude of the text value is too large.  Trailing whitespace is
now ignored.

FossilOrigin-Name: ace0644a1a2a42a3ea42d44f00a31915b8a7e56c9ba90f90a6c02001f89f9c86

manifest
manifest.uuid
src/util.c
test/cast.test

index 9b84aa5a52b6d42d9d74746792e62eae4e654e21..c964e1482519f40d60671ac544670b491b9a0f19 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Reorganize\szipfile.c\scode\sto\smake\sit\seasier\sto\sadd\ssupport\sfor\sin-memory\szip\narchive\sprocessing.
-D 2018-01-25T20:50:46.467
+C Improve\stext-to-integer\sconversion\sin\sboundary\scases.\s\sThe\nsqlite3Atoi64()\sfunction\salways\sreturns\sthe\sminimum\sor\smaximum\sinteger\nif\sthe\smagnitude\sof\sthe\stext\svalue\sis\stoo\slarge.\s\sTrailing\swhitespace\sis\nnow\signored.
+D 2018-01-26T18:37:34.351
 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1
 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea
 F Makefile.in 7a3f714b4fcf793108042b7b0a5c720b0b310ec84314d61ba7f3f49f27e550ea
@@ -554,7 +554,7 @@ F src/treeview.c eae35972ff44f67064de2eaf35f04afe94e7aea3271a8b3bcebb3f954880fec
 F src/trigger.c a34539c69433276d37b0da9a89c117726ff2d292c0902895af1f393a983cd3a1
 F src/update.c a90a32ffc0100265b0693dbbdbe490756447af181f5ea2c138cce515b08c8795
 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5
-F src/util.c ef4a5f904d942e660abade7fbf3e6bdb402dabe9e7c27f3361ecf40b945538b5
+F src/util.c 8628fe1daa9f5db9fa3a70d6fcfd828b73e839feafe7d7faecd7073be56eaec2
 F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739
 F src/vdbe.c 0e13b8c33a9ecf236b3045f190fb58933049582307b621cbd924b6582a2b705f
 F src/vdbe.h 134beb7a12a6213c00eba58febaede33447cc4441bc568a0d9c144b33fc3720a
@@ -673,7 +673,7 @@ F test/capi3b.test efb2b9cfd127efa84433cd7a2d72ce0454ae0dc4
 F test/capi3c.test 7ebed1d8fa2f3190149d556fe8cff5a006be62af437c5c4640db614470126098
 F test/capi3d.test 485048dc5cd07bc68011e4917ad035ad6047ab82
 F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe
-F test/cast.test 4c275cbdc8202d6f9c54a3596701719868ac7dc3
+F test/cast.test 5ceb920718d280b61163500a7d29e0e0a86458b1cbd92d96f962c9d970aa3857
 F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef
 F test/check.test 33a698e8c63613449d85d624a38ef669bf20331daabebe3891c9405dd6df463a
 F test/close.test 799ea4599d2f5704b0a30f477d17c2c760d8523fa5d0c8be4a7df2a8cad787d8
@@ -1702,8 +1702,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93
 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc
 F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e
 F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0
-P 6ab42934e2c4957b5d8927bf4434a9db07ab6078987a6a2d25f35cc468d21203
-R 7248e9fa39da1851c7faf3b8da443f98
-T +closed 469694857a5301e1da8cf067017d400403f3b12882d4265cefb3fd185c536305
-U dan
-Z 84871d5400876eca8ff4f985699fe3ef
+P 30b9258294e3028ef4ea467e332e013995509544e9a23c8bbf5168772a7e895d
+R a3a69d646870f53631d68482ffc811f2
+U drh
+Z ebcc0484dfae31c55e47d329daf31900
index ae4e3440613b8b11e33e8c85eaf75de1c1e75277..5fee1327fd4c826304a510f2557a5e62f5812242 100644 (file)
@@ -1 +1 @@
-30b9258294e3028ef4ea467e332e013995509544e9a23c8bbf5168772a7e895d
\ No newline at end of file
+ace0644a1a2a42a3ea42d44f00a31915b8a7e56c9ba90f90a6c02001f89f9c86
\ No newline at end of file
index 456317cfa9282586288baba1ebd4eaca54e7009d..9954d709df61ff5a3fe9edcf0fcf15c291eb29e5 100644 (file)
@@ -595,7 +595,7 @@ static int compare2pow63(const char *zNum, int incr){
 ** Returns:
 **
 **     0    Successful transformation.  Fits in a 64-bit signed integer.
-**     1    Excess text after the integer value
+**     1    Excess non-space text after the integer value
 **     2    Integer too large for a 64-bit signed integer or is malformed
 **     3    Special case of 9223372036854775808
 **
@@ -638,47 +638,51 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){
   for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
     u = u*10 + c - '0';
   }
-  if( u>LARGEST_INT64 ){
-    *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
-  }else if( neg ){
+  testcase( i==18*incr );
+  testcase( i==19*incr );
+  testcase( i==20*incr );
+  if( neg ){
     *pNum = -(i64)u;
   }else{
     *pNum = (i64)u;
   }
-  testcase( i==18 );
-  testcase( i==19 );
-  testcase( i==20 );
-  if( &zNum[i]<zEnd              /* Extra bytes at the end */
-   || (i==0 && zStart==zNum)     /* No digits */
+  rc = 0;
+  if( (i==0 && zStart==zNum)     /* No digits */
    || nonNum                     /* UTF16 with high-order bytes non-zero */
   ){
     rc = 1;
-  }else{
-    rc = 0;
+  }else if( &zNum[i]<zEnd ){     /* Extra bytes at the end */
+    int jj = i;
+    do{
+      if( !sqlite3Isspace(zNum[jj]) ){
+        rc = 1;          /* Extra non-space text after the integer */
+        break;
+      }
+      jj += incr;
+    }while( &zNum[jj]<zEnd );
   }
-  if( i>19*incr ){                /* Too many digits */
-    /* zNum is empty or contains non-numeric text or is longer
-    ** than 19 digits (thus guaranteeing that it is too large) */
-    return 2;
-  }else if( i<19*incr ){
+  if( i<19*incr ){
     /* Less than 19 digits, so we know that it fits in 64 bits */
     assert( u<=LARGEST_INT64 );
     return rc;
   }else{
     /* zNum is a 19-digit numbers.  Compare it against 9223372036854775808. */
-    c = compare2pow63(zNum, incr);
+    c = i>19*incr ? 1 : compare2pow63(zNum, incr);
     if( c<0 ){
       /* zNum is less than 9223372036854775808 so it fits */
       assert( u<=LARGEST_INT64 );
       return rc;
-    }else if( c>0 ){
-      /* zNum is greater than 9223372036854775808 so it overflows */
-      return 2;
     }else{
-      /* zNum is exactly 9223372036854775808.  Fits if negative.  The
-      ** special case 2 overflow if positive */
-      assert( u-1==LARGEST_INT64 );
-      return neg ? rc : 3;
+      *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
+      if( c>0 ){
+        /* zNum is greater than 9223372036854775808 so it overflows */
+        return 2;
+      }else{
+        /* zNum is exactly 9223372036854775808.  Fits if negative.  The
+        ** special case 2 overflow if positive */
+        assert( u-1==LARGEST_INT64 );
+        return neg ? rc : 3;
+      }
     }
   }
 }
index f47f4bb2bf3fce09682d5231f814a90086139708..f43aa48560055cf32a463310969d40b33825f423 100644 (file)
@@ -343,4 +343,49 @@ do_test cast-4.4 {
   }
 } {0 abc 0.0 abc}
 
+# Added 2018-01-26
+#
+# EVIDENCE-OF: R-48741-32454 If the prefix integer is greater than
+# +9223372036854775807 then the result of the cast is exactly
+# +9223372036854775807.
+do_execsql_test cast-5.1 {
+  SELECT CAST('9223372036854775808' AS integer);
+  SELECT CAST('  +000009223372036854775808' AS integer);
+  SELECT CAST('12345678901234567890123' AS INTEGER);
+} {9223372036854775807 9223372036854775807 9223372036854775807}
+
+# EVIDENCE-OF: R-06028-16857 Similarly, if the prefix integer is less
+# than -9223372036854775808 then the result of the cast is exactly
+# -9223372036854775808.
+do_execsql_test cast-5.2 {
+  SELECT CAST('-9223372036854775808' AS integer);
+  SELECT CAST('-9223372036854775809' AS integer);
+  SELECT CAST('-12345678901234567890123' AS INTEGER);
+} {-9223372036854775808 -9223372036854775808 -9223372036854775808}
+
+# EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks
+# like a floating point value with an exponent, the exponent will be
+# ignored because it is no part of the integer prefix.
+# EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)"
+# results in 123, not in 12300000.
+do_execsql_test case-5.3 {
+  SELECT CAST('123e+5' AS INTEGER);
+  SELECT CAST('123e+5' AS NUMERIC);
+} {123 12300000.0}
+
+
+# The following does not have anything to do with the CAST operator,
+# but it does deal with affinity transformations.
+#
+do_execsql_test case-6.1 {
+  DROP TABLE IF EXISTS t1;
+  CREATE TABLE t1(a NUMERIC);
+  INSERT INTO t1 VALUES
+     ('9000000000000000001'),
+     ('9000000000000000001 '),
+     (' 9000000000000000001'),
+     (' 9000000000000000001 ');
+  SELECT * FROM t1;
+} {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001}
+
 finish_test