From 84d4f1a328dd47fcaf5c6899babbdb64aff89184 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 20 Sep 2017 10:47:10 +0000 Subject: [PATCH] Improved resolution of large integer values in "CAST(x AS NUMERIC)". FossilOrigin-Name: 7f2bd4ff45fba29528c18cac6da983bd9b164303525d3965056f5b40f85dc83f --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/expr.c | 4 ++-- src/main.c | 2 +- src/util.c | 38 ++++++++++++++++++++------------------ src/vdbe.c | 2 +- src/vdbemem.c | 15 +++++++++++---- test/e_expr.test | 44 ++++++++++++++++++++++++++++++++++++++++++++ 8 files changed, 91 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index 7d332d8350..2342cdcc0c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Updates\sto\sthe\s"lemon.html"\sdocument\sreceived\sfrom\sAndy\sGoth. -D 2017-09-20T09:09:34.192 +C Improved\sresolution\sof\slarge\sinteger\svalues\sin\s"CAST(x\sAS\sNUMERIC)". +D 2017-09-20T10:47:10.365 F Makefile.in 4bc36d913c2e3e2d326d588d72f618ac9788b2fd4b7efda61102611a6495c3ff F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc 6033b51b6aea702ea059f6ab2d47b1d3cef648695f787247dd4fb395fe60673f @@ -411,7 +411,7 @@ F src/ctime.c ff1be3eed7bdd75aaca61ca8dc848f7c9f850ef2fb9cb56f2734e922a098f9c0 F src/date.c 48f743d88bbe88f848532d333cca84f26e52a4f217e86f86be7fc1b919c33d74 F src/dbstat.c 7a4ba8518b6369ef3600c49cf9c918ad979acba610b2aebef1b656d649b96720 F src/delete.c 21a5f1812fdb599e9f7afb9f650bdabab60a3afd51d7e94e539c982f647b0023 -F src/expr.c 38a225057f5b7d6a2bc403d7a5d3a67f59ee57b73fe7c546221e3c53202a3731 +F src/expr.c 82fedd57c8ce9e7dc16a003ad4cd863308787d5b5cbd0f83263b37805a56319c F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 5ff2c895fe087756d8085dc1a9bc229b5670e2a65c3929dd87c71e43649af333 F src/func.c b4d259af627e3cd9510cf08db37f0bcc88b1887c735169c74490c3739d5cf5c6 @@ -423,7 +423,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c d2d1bf12d2b5382450620d7cede84c7ffe57e6a89fa9a908f1aba68df2731cd9 F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e F src/loadext.c 20865b183bb8a3723d59cf1efffc3c50217eb452c1021d077b908c94da26b0b2 -F src/main.c 34a58563358fe40979186124d1a3614b9a00c833124d7ebfa8e5d604ed1d2521 +F src/main.c 1c2307a9f7e3183232a2d049881026fe43bf25659857cc11a9a44898accd3200 F src/malloc.c a02c9e69bc76bee0f639416b947a946412890b606301454727feadcb313536d6 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de @@ -524,15 +524,15 @@ F src/treeview.c 2ee4a5dada213d5ab08a742af5c876cee6f1aaae65f10a61923f3fb63846afe F src/trigger.c 48e0f7ed6749ce4d50a695e09e20ce9cf84ecabf2691852c965a51e0b620eccc F src/update.c 5404be9e840717323a69209190cdbc9d0d34adaedaaf1d1a1069babf2c4171c0 F src/utf.c 810fbfebe12359f10bc2a011520a6e10879ab2a163bcb26c74768eab82ea62a5 -F src/util.c ece10cb34b4a62cbb3aab8d711b67e93a2765e0b81d0f72458cb801a3ac60703 +F src/util.c 5168013cfd937a695d23cce8c67cb07a3dda242d4cb812530ba1148b88e0f159 F src/vacuum.c 90839322fd5f00df9617eb21b68beda9b6e2a2937576b0d65985e4aeb1c53739 -F src/vdbe.c 0a0ef7f0759ee4c3ed5ff0c6e9641216d4b31ebb0fea9a7b5a9c4a86ce875ff3 +F src/vdbe.c 2664b89eb243c24bd8dd66a7a13b04b5c83f41897dc80266ad13fed4bb09966c F src/vdbe.h d50cadf12bcf9fb99117ef392ce1ea283aa429270481426b6e8b0280c101fd97 F src/vdbeInt.h 1fe00770144c12c4913128f35262d11527ef3284561baaab59b947a41c08d0d9 F src/vdbeapi.c 9c670ca0dcc1cd86373aa353b747b26fe531ca5cd4331690c611d1f03842e2a1 F src/vdbeaux.c 3be977a032e54fe46cb1b1f3ba62158438b0cc93e091f6feca7742d20dad3203 F src/vdbeblob.c 635a79b60340a6a14a622ea8dcb081f0a66b1ac3836870c587f232eec08c0286 -F src/vdbemem.c 2f9d672af5260f0145787e1dc2c6985414987cc0dc575133a0dc17dda767d868 +F src/vdbemem.c 08f89979c4b359483acb21b044d8e47db55f071ca4326e8bfdca5ac4cb5770ac F src/vdbesort.c 731a09e5cb9e96b70c394c1b7cf3860fbe84acca7682e178615eb941a3a0ef2f F src/vdbetrace.c 48e11ebe040c6b41d146abed2602e3d00d621d7ebe4eb29b0a0f1617fd3c2f6c F src/vtab.c f1d5c23132fb0247af3e86146404112283ddedb6c518de0d4edc91cfb36970ef @@ -732,7 +732,7 @@ F test/e_createtable.test d4c6059d44dcd4b636de9aae322766062b471844 F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e F test/e_droptrigger.test 3cd080807622c13e5bbb61fc9a57bd7754da2412 F test/e_dropview.test 21ce09c361227ddbc9819a5608ee2700c276bdd5 -F test/e_expr.test 146deba180273d19e3bf9f6b45f4e50094c64c7ec4756ea72f79dda25818eb17 +F test/e_expr.test ca8896601ade1e27c6559614c7f32c63d44636fdfa720436a160f09b8bf66c89 F test/e_fkey.test dcdc6ad26b1d4f07636208de4c1c22aae7c0597a685a6c10fe6da91f3191dd96 F test/e_fts3.test 8cf40550bb088a6aa187c818c00fabe26ef82900a4cd5c66b427ccafe28bedaa F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e @@ -1655,7 +1655,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 1b2de41453ac33de82f9cd6cbb92eee4fe184fb282c27e5efa5243c8cb239630 -R e0e8cf7279386534b02109d8fa18ad99 +P 5b2002f3df1902aaa571a0efd01ab8bae7f4d37ac4819cc51595277f4de93433 +R 219c5c95f432e38325a9c8586b5b2761 U drh -Z 86920861ac015f347841db4c53c64a7b +Z e4dde272cb6c1ca1520bca8de194c744 diff --git a/manifest.uuid b/manifest.uuid index 0ce91438a9..e0163948ed 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5b2002f3df1902aaa571a0efd01ab8bae7f4d37ac4819cc51595277f4de93433 \ No newline at end of file +7f2bd4ff45fba29528c18cac6da983bd9b164303525d3965056f5b40f85dc83f \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index f3326d02e7..b482fafc05 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3076,7 +3076,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ const char *z = pExpr->u.zToken; assert( z!=0 ); c = sqlite3DecOrHexToI64(z, &value); - if( c==1 || (c==2 && !negFlag) || (negFlag && value==SMALLEST_INT64)){ + if( (c==3 && !negFlag) || (c==2) || (negFlag && value==SMALLEST_INT64)){ #ifdef SQLITE_OMIT_FLOATING_POINT sqlite3ErrorMsg(pParse, "oversized integer: %s%s", negFlag ? "-" : "", z); #else @@ -3090,7 +3090,7 @@ static void codeInteger(Parse *pParse, Expr *pExpr, int negFlag, int iMem){ } #endif }else{ - if( negFlag ){ value = c==2 ? SMALLEST_INT64 : -value; } + if( negFlag ){ value = c==3 ? SMALLEST_INT64 : -value; } sqlite3VdbeAddOp4Dup8(v, OP_Int64, 0, iMem, 0, (u8*)&value, P4_INT64); } } diff --git a/src/main.c b/src/main.c index 3942ed9465..6f697ffb39 100644 --- a/src/main.c +++ b/src/main.c @@ -3942,7 +3942,7 @@ sqlite3_int64 sqlite3_uri_int64( ){ const char *z = sqlite3_uri_parameter(zFilename, zParam); sqlite3_int64 v; - if( z && sqlite3DecOrHexToI64(z, &v)==SQLITE_OK ){ + if( z && sqlite3DecOrHexToI64(z, &v)==0 ){ bDflt = v; } return bDflt; diff --git a/src/util.c b/src/util.c index ebcc5bec6e..fbe3714b77 100644 --- a/src/util.c +++ b/src/util.c @@ -557,16 +557,12 @@ static int compare2pow63(const char *zNum, int incr){ ** Convert zNum to a 64-bit signed integer. zNum must be decimal. This ** routine does *not* accept hexadecimal notation. ** -** If the zNum value is representable as a 64-bit twos-complement -** integer, then write that value into *pNum and return 0. +** Returns: ** -** If zNum is exactly 9223372036854775808, return 2. This special -** case is broken out because while 9223372036854775808 cannot be a -** signed 64-bit integer, its negative -9223372036854775808 can be. -** -** If zNum is too big for a 64-bit integer and is not -** 9223372036854775808 or if zNum contains any non-numeric text, -** then return 1. +** 0 Successful transformation. Fits in a 64-bit signed integer. +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 ** ** length is the number of bytes in the string (bytes, not characters). ** The string is not necessarily zero-terminated. The encoding is @@ -579,6 +575,7 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ int i; int c = 0; int nonNum = 0; /* True if input contains UTF16 with high byte non-zero */ + int rc; /* Baseline return code */ const char *zStart; const char *zEnd = zNum + length; assert( enc==SQLITE_UTF8 || enc==SQLITE_UTF16LE || enc==SQLITE_UTF16BE ); @@ -618,31 +615,35 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ testcase( i==20 ); if( &zNum[i]19*incr /* Too many digits */ || nonNum /* UTF16 with high-order bytes non-zero */ ){ + rc = 1; + }else{ + rc = 0; + } + 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 1; + return 2; }else if( i<19*incr ){ /* Less than 19 digits, so we know that it fits in 64 bits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else{ /* zNum is a 19-digit numbers. Compare it against 9223372036854775808. */ c = compare2pow63(zNum, incr); if( c<0 ){ /* zNum is less than 9223372036854775808 so it fits */ assert( u<=LARGEST_INT64 ); - return 0; + return rc; }else if( c>0 ){ /* zNum is greater than 9223372036854775808 so it overflows */ - return 1; + return 2; }else{ /* zNum is exactly 9223372036854775808. Fits if negative. The ** special case 2 overflow if positive */ assert( u-1==LARGEST_INT64 ); - return neg ? 0 : 2; + return neg ? rc : 3; } } } @@ -655,8 +656,9 @@ int sqlite3Atoi64(const char *zNum, i64 *pNum, int length, u8 enc){ ** Returns: ** ** 0 Successful transformation. Fits in a 64-bit signed integer. -** 1 Integer too large for a 64-bit signed integer or is malformed -** 2 Special case of 9223372036854775808 +** 1 Excess text after the integer value +** 2 Integer too large for a 64-bit signed integer or is malformed +** 3 Special case of 9223372036854775808 */ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ #ifndef SQLITE_OMIT_HEX_INTEGER @@ -670,7 +672,7 @@ int sqlite3DecOrHexToI64(const char *z, i64 *pOut){ u = u*16 + sqlite3HexToInt(z[k]); } memcpy(pOut, &u, 8); - return (z[k]==0 && k-i<=16) ? 0 : 1; + return (z[k]==0 && k-i<=16) ? 0 : 2; }else #endif /* SQLITE_OMIT_HEX_INTEGER */ { diff --git a/src/vdbe.c b/src/vdbe.c index 37699bbba0..2273d1f5da 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -354,7 +354,7 @@ static u16 SQLITE_NOINLINE computeNumericType(Mem *pMem){ if( sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc)==0 ){ return 0; } - if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==SQLITE_OK ){ + if( sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc)==0 ){ return MEM_Int; } return MEM_Real; diff --git a/src/vdbemem.c b/src/vdbemem.c index 345c41a72d..09ced1e567 100644 --- a/src/vdbemem.c +++ b/src/vdbemem.c @@ -597,14 +597,21 @@ int sqlite3VdbeMemRealify(Mem *pMem){ */ int sqlite3VdbeMemNumerify(Mem *pMem){ if( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))==0 ){ + int rc; assert( (pMem->flags & (MEM_Blob|MEM_Str))!=0 ); assert( pMem->db==0 || sqlite3_mutex_held(pMem->db->mutex) ); - if( 0==sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc) ){ + rc = sqlite3Atoi64(pMem->z, &pMem->u.i, pMem->n, pMem->enc); + if( rc==0 ){ MemSetTypeFlag(pMem, MEM_Int); }else{ - pMem->u.r = sqlite3VdbeRealValue(pMem); - MemSetTypeFlag(pMem, MEM_Real); - sqlite3VdbeIntegerAffinity(pMem); + i64 i = pMem->u.i; + sqlite3AtoF(pMem->z, &pMem->u.r, pMem->n, pMem->enc); + if( rc==1 && pMem->u.r==(double)i ){ + pMem->u.i = i; + MemSetTypeFlag(pMem, MEM_Int); + }else{ + MemSetTypeFlag(pMem, MEM_Real); + } } } assert( (pMem->flags & (MEM_Int|MEM_Real|MEM_Null))!=0 ); diff --git a/test/e_expr.test b/test/e_expr.test index 373ffef4f9..1cac31948b 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -1663,6 +1663,50 @@ do_expr_test e_expr-32.2.3 { do_expr_test e_expr-32.2.4 { CAST(9223372036854775807 AS NUMERIC) } integer 9223372036854775807 +do_expr_test e_expr-32.2.5 { + CAST('9223372036854775807 ' AS NUMERIC) +} integer 9223372036854775807 +do_expr_test e_expr-32.2.6 { + CAST(' 9223372036854775807 ' AS NUMERIC) +} integer 9223372036854775807 +do_expr_test e_expr-32.2.7 { + CAST(' ' AS NUMERIC) +} integer 0 +do_execsql_test e_expr-32.2.8 { + WITH t1(x) AS (VALUES + ('9000000000000000001'), + ('9000000000000000001x'), + ('9000000000000000001 '), + (' 9000000000000000001 '), + (' 9000000000000000001'), + (' 9000000000000000001.'), + ('9223372036854775807'), + ('9223372036854775807 '), + (' 9223372036854775807 '), + ('9223372036854775808'), + (' 9223372036854775808 '), + ('9223372036854775807.0'), + ('9223372036854775807e+0'), + ('-5.0'), + ('-5e+0')) + SELECT typeof(CAST(x AS NUMERIC)), CAST(x AS NUMERIC)||'' FROM t1; +} [list \ + integer 9000000000000000001 \ + integer 9000000000000000001 \ + integer 9000000000000000001 \ + integer 9000000000000000001 \ + integer 9000000000000000001 \ + integer 9000000000000000001 \ + integer 9223372036854775807 \ + integer 9223372036854775807 \ + integer 9223372036854775807 \ + real 9.22337203685478e+18 \ + real 9.22337203685478e+18 \ + integer 9223372036854775807 \ + integer 9223372036854775807 \ + integer -5 \ + integer -5 \ +] # EVIDENCE-OF: R-64550-29191 Note that the result from casting any # non-BLOB value into a BLOB and the result from casting any BLOB value