From: drh <> Date: Mon, 12 Dec 2022 18:58:53 +0000 (+0000) Subject: If a subquery has a result column of the form "CAST(... AS NUMERIC)" then X-Git-Tag: version-3.41.0~258^2 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=89e160a96a672f283705823c8ca2e746b530f779;p=thirdparty%2Fsqlite.git If a subquery has a result column of the form "CAST(... AS NUMERIC)" then give that column no affinity rather than NUMERIC affinity. This is because casting to numeric preserves real values that could be integers but numeric affinity does not. By using no affinity on the column, we make the behavior consistent if the subquery is implemented as a co-routine or is materialized. FossilOrigin-Name: ece07d091c2ef3367a914187e0b6512c1f2390b8c34844536ad50e88c7e8c2f2 --- diff --git a/manifest b/manifest index fb68b35513..80005c1855 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Move\sJS-to-C\sbinding\ssignatures\sfrom\ssqlite3-api-prologue.js\sto\ssqlite3-api-glue.js\sto\sallow\sfor\suse\sof\sthe\snew/experimental\ssqlite3.wasm.xWrap()\sfeature\swhich\sautomatically\sbinds\sJS\sfunctions\sto\sWASM/C\sas\sneeded,\swhich\ssimplifies\screation\sof\sbindings\swhich\stake\sC\sfunction\spointers.\sReimplement\ssqlite3_exec(),\ssqlite3_create_collation(),\ssqlite3_progress_handler()\sto\suse\sthis\snew\sfeature. -D 2022-12-12T14:31:38.581 +C If\sa\ssubquery\shas\sa\sresult\scolumn\sof\sthe\sform\s"CAST(...\sAS\sNUMERIC)"\sthen\ngive\sthat\scolumn\sno\saffinity\srather\sthan\sNUMERIC\saffinity.\s\sThis\sis\sbecause\ncasting\sto\snumeric\spreserves\sreal\svalues\sthat\scould\sbe\sintegers\sbut\snumeric\naffinity\sdoes\snot.\s\sBy\susing\sno\saffinity\son\sthe\scolumn,\swe\smake\sthe\sbehavior\nconsistent\sif\sthe\ssubquery\sis\simplemented\sas\sa\sco-routine\sor\sis\smaterialized. +D 2022-12-12T18:58:53.208 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -645,7 +645,7 @@ F src/printf.c e99ee9741e79ae3873458146f59644276657340385ade4e76a5f5d1c25793764 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c efea4e5fbecfd6d0a9071b0be0d952620991673391b6ffaaf4c277b0bb674633 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 9a687883032642054b8f400aa3bcb6019c2c30f890850480975e95568f290c52 +F src/select.c 39c4b0e23f3f1334ca3ff9b68014de0ec2c4ae5954186765d669893a8c7fc5a9 F src/shell.c.in 8d9dc02dd03f8fc93f3e3cdb17d8d16e8ddb985dddad213985c08186900a3ebb F src/sqlite.h.in 97e8021f5db6bab8646d9c2d4231d3bab1204a2e88e5f187eca11dc7eab33ef8 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -863,7 +863,7 @@ F test/capi3c.test 54e2dc0c8fd7c34ad1590d1be6864397da2438c95a9f5aee2f8fbc60c112e F test/capi3d.test 8b778794af891b0dca3d900bd345fbc8ebd2aa2aae425a9dccdd10d5233dfbde F test/capi3e.test 3d49c01ef2a1a55f41d73cba2b23b5059ec460fe F test/carray01.test d55d57bf66b1af1c7ac55fae66ff4910884a8f5d21a90a18797ce386212a2634 -F test/cast.test 6064022ba9af31a8a2ff7bb345e5bd0e74172ffad85bdab5898a42d8227c7585 +F test/cast.test 4f14da6ed96af8b3124cd2cda2ff8cda0946a8a0d0d32ae76905795c6e3ac7bc F test/cffault.test 9d6b20606afe712374952eec4f8fd74b1a8097ef F test/changes.test 9dd8e597d84072122fc8a4fcdea837f4a54a461e6e536053ea984303e8ca937b F test/changes2.test d222c0cbf5ab0ac4d7c180594e486c1bf20b2098d33e56ce33b8e12eba6823b9 @@ -2067,8 +2067,11 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d557015208f504c6d5d20ebf1e451b3f07b19590d76371b16a9f4b54e9645282 -R 5a61f05e144f2d7b8121b7e697a724d0 -U stephan -Z 82382106256d8062d011dc4fe2d4d001 +P 9386d6f634680b4e0fa5487c34c63acb29f0b7a6ae738b8f6164ad084a229b62 +R b147605f598862d0859edce8eb970ae1 +T *branch * cast-to-numeric +T *sym-cast-to-numeric * +T -sym-trunk * +U drh +Z 8d98f09634c2da9d51008460bd14d1a6 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index de9a05d4f3..e5d9e2b583 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9386d6f634680b4e0fa5487c34c63acb29f0b7a6ae738b8f6164ad084a229b62 \ No newline at end of file +ece07d091c2ef3367a914187e0b6512c1f2390b8c34844536ad50e88c7e8c2f2 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 3752aaef71..5e2b30462e 100644 --- a/src/select.c +++ b/src/select.c @@ -2289,6 +2289,14 @@ int sqlite3ColumnsFromExprList( return SQLITE_OK; } +/* +** This bit, when added to the "aff" parameter of +** sqlite3SelectAddColumnTypeAndCollation() means that result set +** expressions of the form "CAST(expr AS NUMERIC)" should result in +** NONE affinity rather than NUMERIC affinity. +*/ +#define SQLITE_AFF_FLAG1 0x10 + /* ** Add type and collation information to a column list based on ** a SELECT statement. @@ -2299,12 +2307,17 @@ int sqlite3ColumnsFromExprList( ** ** This routine requires that all identifiers in the SELECT ** statement be resolved. +** +** The SQLITE_AFF_FLAG1 bit added to parameter aff means that a +** result set column of the form "CAST(expr AS NUMERIC)" should use +** NONE affinity rather than NUMERIC affinity. See the +** 2022-12-10 "reopen" of ticket https://sqlite.org/src/tktview/57c47526c3. */ void sqlite3SelectAddColumnTypeAndCollation( Parse *pParse, /* Parsing contexts */ Table *pTab, /* Add column type information to this table */ Select *pSelect, /* SELECT used to determine types and collations */ - char aff /* Default affinity for columns */ + char aff /* Default affinity. Maybe with SQLITE_AFF_FLAG1 too */ ){ sqlite3 *db = pParse->db; NameContext sNC; @@ -2330,6 +2343,12 @@ void sqlite3SelectAddColumnTypeAndCollation( zType = columnType(&sNC, p, 0, 0, 0); /* pCol->szEst = ... // Column size est for SELECT tables never used */ pCol->affinity = sqlite3ExprAffinity(p); + if( pCol->affinity==SQLITE_AFF_NUMERIC + && p->op==TK_CAST + && (aff & SQLITE_AFF_FLAG1)!=0 + ){ + pCol->affinity = SQLITE_AFF_NONE; + } if( zType ){ m = sqlite3Strlen30(zType); n = sqlite3Strlen30(pCol->zCnName); @@ -2342,7 +2361,10 @@ void sqlite3SelectAddColumnTypeAndCollation( pCol->colFlags &= ~(COLFLAG_HASTYPE|COLFLAG_HASCOLL); } } - if( pCol->affinity<=SQLITE_AFF_NONE ) pCol->affinity = aff; + if( pCol->affinity<=SQLITE_AFF_NONE ){ + assert( (SQLITE_AFF_FLAG1 & SQLITE_AFF_MASK)==0 ); + pCol->affinity = aff & SQLITE_AFF_MASK; + } pColl = sqlite3ExprCollSeq(pParse, p); if( pColl ){ assert( pTab->pIndex==0 ); @@ -6216,7 +6238,7 @@ static void selectAddSubqueryTypeInfo(Walker *pWalker, Select *p){ if( pSel ){ while( pSel->pPrior ) pSel = pSel->pPrior; sqlite3SelectAddColumnTypeAndCollation(pParse, pTab, pSel, - SQLITE_AFF_NONE); + SQLITE_AFF_NONE|SQLITE_AFF_FLAG1); } } } diff --git a/test/cast.test b/test/cast.test index cbeec47c9d..cd3f1cad15 100644 --- a/test/cast.test +++ b/test/cast.test @@ -483,5 +483,36 @@ do_execsql_test cast-9.0 { SELECT v1.c0 FROM v1, t0 WHERE v1.c0=0; } {0} +# Set the 2022-12-10 "reopen" of ticket [https://sqlite.org/src/tktview/57c47526c3] +# +do_execsql_test cast-9.1 { + CREATE TABLE dual(dummy TEXT); + INSERT INTO dual VALUES('X'); + SELECT CAST(4 AS NUMERIC); +} {4} +do_execsql_test cast-9.2 { + SELECT CAST(4.0 AS NUMERIC); +} {4.0} +do_execsql_test cast-9.3 { + SELECT CAST(4.5 AS NUMERIC); +} {4.5} +do_execsql_test cast-9.4 { + SELECT x, typeof(x) FROM (SELECT CAST(4 AS NUMERIC) AS x) JOIN dual; +} {4 integer} +do_execsql_test cast-9.5 { + SELECT x, typeof(x) FROM (SELECT CAST(4 AS NUMERIC) AS x) CROSS JOIN dual; +} {4 integer} +do_execsql_test cast-9.10 { + SELECT x, typeof(x) FROM (SELECT CAST(4.0 AS NUMERIC) AS x) JOIN dual; +} {4.0 real} +do_execsql_test cast-9.11 { + SELECT x, typeof(x) FROM (SELECT CAST(4.0 AS NUMERIC) AS x) CROSS JOIN dual; +} {4.0 real} +do_execsql_test cast-9.12 { + SELECT x, typeof(x) FROM (SELECT CAST(4.5 AS NUMERIC) AS x) JOIN dual; +} {4.5 real} +do_execsql_test cast-9.13 { + SELECT x, typeof(x) FROM (SELECT CAST(4.5 AS NUMERIC) AS x) CROSS JOIN dual; +} {4.5 real} finish_test