/ Check-in [ace0644a]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Improve text-to-integer conversion in boundary cases. The sqlite3Atoi64() function always returns the minimum or maximum integer if the magnitude of the text value is too large. Trailing whitespace is now ignored.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256:ace0644a1a2a42a3ea42d44f00a31915b8a7e56c9ba90f90a6c02001f89f9c86
User & Date: drh 2018-01-26 18:37:34
Context
2018-01-26
18:59
If the argument to table function zipfile() is a blob (not text), assume that it contains a zip file image to interpret, not the name of a file on disk. check-in: 029ebcd3 user: dan tags: trunk
18:37
Improve text-to-integer conversion in boundary cases. The sqlite3Atoi64() function always returns the minimum or maximum integer if the magnitude of the text value is too large. Trailing whitespace is now ignored. check-in: ace0644a user: drh tags: trunk
2018-01-25
20:50
Reorganize zipfile.c code to make it easier to add support for in-memory zip archive processing. check-in: 30b92582 user: dan tags: trunk
Changes
Hide Diffs Side-by-Side Diffs Ignore Whitespace Patch

Changes to src/util.c.

   591    591   /*
   592    592   ** Convert zNum to a 64-bit signed integer.  zNum must be decimal. This
   593    593   ** routine does *not* accept hexadecimal notation.
   594    594   **
   595    595   ** Returns:
   596    596   **
   597    597   **     0    Successful transformation.  Fits in a 64-bit signed integer.
   598         -**     1    Excess text after the integer value
          598  +**     1    Excess non-space text after the integer value
   599    599   **     2    Integer too large for a 64-bit signed integer or is malformed
   600    600   **     3    Special case of 9223372036854775808
   601    601   **
   602    602   ** length is the number of bytes in the string (bytes, not characters).
   603    603   ** The string is not necessarily zero-terminated.  The encoding is
   604    604   ** given by enc.
   605    605   */
................................................................................
   634    634       }
   635    635     }
   636    636     zStart = zNum;
   637    637     while( zNum<zEnd && zNum[0]=='0' ){ zNum+=incr; } /* Skip leading zeros. */
   638    638     for(i=0; &zNum[i]<zEnd && (c=zNum[i])>='0' && c<='9'; i+=incr){
   639    639       u = u*10 + c - '0';
   640    640     }
   641         -  if( u>LARGEST_INT64 ){
   642         -    *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
   643         -  }else if( neg ){
          641  +  testcase( i==18*incr );
          642  +  testcase( i==19*incr );
          643  +  testcase( i==20*incr );
          644  +  if( neg ){
   644    645       *pNum = -(i64)u;
   645    646     }else{
   646    647       *pNum = (i64)u;
   647    648     }
   648         -  testcase( i==18 );
   649         -  testcase( i==19 );
   650         -  testcase( i==20 );
   651         -  if( &zNum[i]<zEnd              /* Extra bytes at the end */
   652         -   || (i==0 && zStart==zNum)     /* No digits */
          649  +  rc = 0;
          650  +  if( (i==0 && zStart==zNum)     /* No digits */
   653    651      || nonNum                     /* UTF16 with high-order bytes non-zero */
   654    652     ){
   655    653       rc = 1;
   656         -  }else{
   657         -    rc = 0;
          654  +  }else if( &zNum[i]<zEnd ){     /* Extra bytes at the end */
          655  +    int jj = i;
          656  +    do{
          657  +      if( !sqlite3Isspace(zNum[jj]) ){
          658  +        rc = 1;          /* Extra non-space text after the integer */
          659  +        break;
          660  +      }
          661  +      jj += incr;
          662  +    }while( &zNum[jj]<zEnd );
   658    663     }
   659         -  if( i>19*incr ){                /* Too many digits */
   660         -    /* zNum is empty or contains non-numeric text or is longer
   661         -    ** than 19 digits (thus guaranteeing that it is too large) */
   662         -    return 2;
   663         -  }else if( i<19*incr ){
          664  +  if( i<19*incr ){
   664    665       /* Less than 19 digits, so we know that it fits in 64 bits */
   665    666       assert( u<=LARGEST_INT64 );
   666    667       return rc;
   667    668     }else{
   668    669       /* zNum is a 19-digit numbers.  Compare it against 9223372036854775808. */
   669         -    c = compare2pow63(zNum, incr);
          670  +    c = i>19*incr ? 1 : compare2pow63(zNum, incr);
   670    671       if( c<0 ){
   671    672         /* zNum is less than 9223372036854775808 so it fits */
   672    673         assert( u<=LARGEST_INT64 );
   673    674         return rc;
   674         -    }else if( c>0 ){
   675         -      /* zNum is greater than 9223372036854775808 so it overflows */
   676         -      return 2;
   677    675       }else{
   678         -      /* zNum is exactly 9223372036854775808.  Fits if negative.  The
   679         -      ** special case 2 overflow if positive */
   680         -      assert( u-1==LARGEST_INT64 );
   681         -      return neg ? rc : 3;
          676  +      *pNum = neg ? SMALLEST_INT64 : LARGEST_INT64;
          677  +      if( c>0 ){
          678  +        /* zNum is greater than 9223372036854775808 so it overflows */
          679  +        return 2;
          680  +      }else{
          681  +        /* zNum is exactly 9223372036854775808.  Fits if negative.  The
          682  +        ** special case 2 overflow if positive */
          683  +        assert( u-1==LARGEST_INT64 );
          684  +        return neg ? rc : 3;
          685  +      }
   682    686       }
   683    687     }
   684    688   }
   685    689   
   686    690   /*
   687    691   ** Transform a UTF-8 integer literal, in either decimal or hexadecimal,
   688    692   ** into a 64-bit signed integer.  This routine accepts hexadecimal literals,

Changes to test/cast.test.

   339    339   } {abc 0 abc}
   340    340   do_test cast-4.4 {
   341    341     db eval {
   342    342       SELECT CAST(a AS integer), a, CAST(a AS real), a FROM t1;
   343    343     }
   344    344   } {0 abc 0.0 abc}
   345    345   
          346  +# Added 2018-01-26
          347  +#
          348  +# EVIDENCE-OF: R-48741-32454 If the prefix integer is greater than
          349  +# +9223372036854775807 then the result of the cast is exactly
          350  +# +9223372036854775807.
          351  +do_execsql_test cast-5.1 {
          352  +  SELECT CAST('9223372036854775808' AS integer);
          353  +  SELECT CAST('  +000009223372036854775808' AS integer);
          354  +  SELECT CAST('12345678901234567890123' AS INTEGER);
          355  +} {9223372036854775807 9223372036854775807 9223372036854775807}
          356  +
          357  +# EVIDENCE-OF: R-06028-16857 Similarly, if the prefix integer is less
          358  +# than -9223372036854775808 then the result of the cast is exactly
          359  +# -9223372036854775808.
          360  +do_execsql_test cast-5.2 {
          361  +  SELECT CAST('-9223372036854775808' AS integer);
          362  +  SELECT CAST('-9223372036854775809' AS integer);
          363  +  SELECT CAST('-12345678901234567890123' AS INTEGER);
          364  +} {-9223372036854775808 -9223372036854775808 -9223372036854775808}
          365  +
          366  +# EVIDENCE-OF: R-33990-33527 When casting to INTEGER, if the text looks
          367  +# like a floating point value with an exponent, the exponent will be
          368  +# ignored because it is no part of the integer prefix.
          369  +# EVIDENCE-OF: R-24225-46995 For example, "(CAST '123e+5' AS INTEGER)"
          370  +# results in 123, not in 12300000.
          371  +do_execsql_test case-5.3 {
          372  +  SELECT CAST('123e+5' AS INTEGER);
          373  +  SELECT CAST('123e+5' AS NUMERIC);
          374  +} {123 12300000.0}
          375  +
          376  +
          377  +# The following does not have anything to do with the CAST operator,
          378  +# but it does deal with affinity transformations.
          379  +#
          380  +do_execsql_test case-6.1 {
          381  +  DROP TABLE IF EXISTS t1;
          382  +  CREATE TABLE t1(a NUMERIC);
          383  +  INSERT INTO t1 VALUES
          384  +     ('9000000000000000001'),
          385  +     ('9000000000000000001 '),
          386  +     (' 9000000000000000001'),
          387  +     (' 9000000000000000001 ');
          388  +  SELECT * FROM t1;
          389  +} {9000000000000000001 9000000000000000001 9000000000000000001 9000000000000000001}
          390  +
   346    391   finish_test