From 8d5cea6b61c30dd839a32e253bf7ae241b5662f4 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 11 Mar 2020 02:04:15 +0000 Subject: [PATCH 1/3] This variant to the fix for ticket [e0c2ad1aa8a9c691] uses fewer CPU cycles. FossilOrigin-Name: fb5a8a9edd0a4f979d6c30278d4ddc73c651f56ae989b4e5983fca36887c5ceb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 9 +++++++-- 3 files changed, 14 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 06cd979aa0..9ee146f83d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhanced\sdetection\slogic\sfor\spreventing\sthe\suse\sof\sstatic\sschema\sexpressions\nby\scode\sgenerating\sroutines. -D 2020-03-10T19:24:38.960 +C This\svariant\sto\sthe\sfix\sfor\sticket\s[e0c2ad1aa8a9c691]\suses\sfewer\sCPU\scycles. +D 2020-03-11T02:04:15.678 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -483,7 +483,7 @@ F src/date.c 6c408fdd2e9ddf6e8431aba76315a2d061bea2cec8fbb75e25d7c1ba08274712 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 0f55297469d4244ab7df395849e1af98eb5e95816af7c661e7d2d8402dea23da F src/delete.c 11000121c4281c0bce4e41db29addfaea0038eaa127ece02557c9207bc3e541d -F src/expr.c 117997508b41b1d02b4c376bdca16da04e813c0f36d0811e3ea13d1c786f53f4 +F src/expr.c cddb6c7ccdb856338c189c8cc15bd95dd60e596e4bb5a1c8ba86726b49857581 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 4b575423b0a5d4898b1a7868ce985cf1a8ad91c741c9abbb108ff02536d20f41 F src/func.c 108577cebe8a50c86d849a93b99493a54e348dd0b846f00d13b52ca973d5baf4 @@ -1860,7 +1860,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 f45f5de000834da5b23cdcf12c3f0e3073287756afe06bdb77b95fb65b250258 -R f078265eb0d8f8487aa3c2a1c341660a +P 5f60b527b938c0778e8f725c635ce0dc5ed7a4e01fd6252aa2cdb64da2f625bc +R 37bce3d92e4cf86464a6bfb5a7dc2299 U drh -Z 1d0ba7c8bbe7247314d90dba25e45a8e +Z 0b4099ba8ff5f2f0e887def300e748c2 diff --git a/manifest.uuid b/manifest.uuid index c22469d699..0b01cdc6f0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5f60b527b938c0778e8f725c635ce0dc5ed7a4e01fd6252aa2cdb64da2f625bc \ No newline at end of file +fb5a8a9edd0a4f979d6c30278d4ddc73c651f56ae989b4e5983fca36887c5ceb \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 03d58df32e..cf52c5c754 100644 --- a/src/expr.c +++ b/src/expr.c @@ -3805,8 +3805,13 @@ expr_code_doover: Table *pTab = pCol->pTab; sqlite3VdbeAddOp3(v, OP_Column, pAggInfo->sortingIdxPTab, pCol->iSorterColumn, target); - if( ALWAYS(pTab) && pCol->iColumn>=0 ){ - sqlite3ColumnDefault(v, pTab, pCol->iColumn, target); + if( pCol->iColumn<0 ){ + VdbeComment((v,"%s.rowid",pTab->zName)); + }else{ + VdbeComment((v,"%s.%s",pTab->zName,pTab->aCol[pCol->iColumn].zName)); + if( pTab->aCol[pCol->iColumn].affinity==SQLITE_AFF_REAL ){ + sqlite3VdbeAddOp1(v, OP_RealAffinity, target); + } } return target; } From 38dfbdae8a61dd16987d93a6a4bfe0001eab7b3d Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 11 Mar 2020 17:58:27 +0000 Subject: [PATCH 2/3] Do not factor out constant functions into the initialization section at the end of the prepared statement, be cause if they throw an exception, it will abort the statement even if the function is never called. Better to put constant functions in an OP_Once block. FossilOrigin-Name: 97a18a5cd701848a9660385e31bffe2c397e3cfe57ccdb876f44d08c00d1d39a --- manifest | 19 +++++++++++-------- manifest.uuid | 2 +- src/expr.c | 28 +++++++++++++++++++++------- src/vtab.c | 2 +- test/func5.test | 3 ++- 5 files changed, 36 insertions(+), 18 deletions(-) diff --git a/manifest b/manifest index 9ee146f83d..11b5b9c942 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C This\svariant\sto\sthe\sfix\sfor\sticket\s[e0c2ad1aa8a9c691]\suses\sfewer\sCPU\scycles. -D 2020-03-11T02:04:15.678 +C Do\snot\sfactor\sout\sconstant\sfunctions\sinto\sthe\sinitialization\ssection\sat\sthe\nend\sof\sthe\sprepared\sstatement,\sbe\scause\sif\sthey\sthrow\san\sexception,\sit\swill\nabort\sthe\sstatement\seven\sif\sthe\sfunction\sis\snever\scalled.\s\sBetter\sto\sput\nconstant\sfunctions\sin\san\sOP_Once\sblock. +D 2020-03-11T17:58:27.142 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -483,7 +483,7 @@ F src/date.c 6c408fdd2e9ddf6e8431aba76315a2d061bea2cec8fbb75e25d7c1ba08274712 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 0f55297469d4244ab7df395849e1af98eb5e95816af7c661e7d2d8402dea23da F src/delete.c 11000121c4281c0bce4e41db29addfaea0038eaa127ece02557c9207bc3e541d -F src/expr.c cddb6c7ccdb856338c189c8cc15bd95dd60e596e4bb5a1c8ba86726b49857581 +F src/expr.c 137db48827025f68792824eaf8e4c66612dbd160cf5cafe6ae93b27eed101e12 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 4b575423b0a5d4898b1a7868ce985cf1a8ad91c741c9abbb108ff02536d20f41 F src/func.c 108577cebe8a50c86d849a93b99493a54e348dd0b846f00d13b52ca973d5baf4 @@ -612,7 +612,7 @@ F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22 F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 -F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515 +F src/vtab.c ad810f9b771cf66eee2762e18eb2b704c97c18ca4b4bf25af7f88ab1fb254d14 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 697424314e40d99f93f548c7bfa526c10e87f4bdf64d5a76a96b999dd7133ebc F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a @@ -1007,7 +1007,7 @@ F test/func.test b7f1a706d1bb8de103a24bd0c30c9e3dc3eedf0df24aabc54b0a4f6e0874262 F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1e6 F test/func4.test a94858a8c1f10a408b0b3db439c990b59dbb2349411d503de011ac4e2b5f27a6 -F test/func5.test cdd224400bc3e48d891827cc913a57051a426fa4 +F test/func5.test 863e6d1bd0013d09c17236f8a13ea34008dd857d87d85a13a673960e4c25d82a F test/func6.test 90e42b64c4f9fb6f04f44cb8a1da586c8542502e926b19c76504fe74ff2a9b7c F test/fuzz-oss1.test e58330d01cbbd8215ee636b17a03fe220b37dbfa F test/fuzz.test 96083052bf5765e4518c1ba686ce2bab785670d1 @@ -1860,7 +1860,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5f60b527b938c0778e8f725c635ce0dc5ed7a4e01fd6252aa2cdb64da2f625bc -R 37bce3d92e4cf86464a6bfb5a7dc2299 +P fb5a8a9edd0a4f979d6c30278d4ddc73c651f56ae989b4e5983fca36887c5ceb +R cf3e121998a086e24f73b7daa3777948 +T *branch * do-not-factor-functions +T *sym-do-not-factor-functions * +T -sym-trunk * U drh -Z 0b4099ba8ff5f2f0e887def300e748c2 +Z 4a780ea0d068b9c3f4aeae83f545f604 diff --git a/manifest.uuid b/manifest.uuid index 0b01cdc6f0..3625ef547a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -fb5a8a9edd0a4f979d6c30278d4ddc73c651f56ae989b4e5983fca36887c5ceb \ No newline at end of file +97a18a5cd701848a9660385e31bffe2c397e3cfe57ccdb876f44d08c00d1d39a \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index cf52c5c754..8c0768bb7e 100644 --- a/src/expr.c +++ b/src/expr.c @@ -4532,15 +4532,29 @@ int sqlite3ExprCodeAtInit( } } } + if( regDest<0 ) regDest = ++pParse->nMem; pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); - p = sqlite3ExprListAppend(pParse, p, pExpr); - if( p ){ - struct ExprList_item *pItem = &p->a[p->nExpr-1]; - pItem->reusable = regDest<0; - if( regDest<0 ) regDest = ++pParse->nMem; - pItem->u.iConstExprReg = regDest; + if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){ + Vdbe *v = pParse->pVdbe; + int addr; + assert( v ); + addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); + pParse->okConstFactor = 0; + if( !pParse->db->mallocFailed ){ + sqlite3ExprCode(pParse, pExpr, regDest); + } + pParse->okConstFactor = 1; + sqlite3ExprDelete(pParse->db, pExpr); + sqlite3VdbeJumpHere(v, addr); + }else{ + p = sqlite3ExprListAppend(pParse, p, pExpr); + if( p ){ + struct ExprList_item *pItem = &p->a[p->nExpr-1]; + pItem->reusable = regDest<0; + pItem->u.iConstExprReg = regDest; + } + pParse->pConstExpr = p; } - pParse->pConstExpr = p; return regDest; } diff --git a/src/vtab.c b/src/vtab.c index 013511cfb4..6a30f83a91 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -1113,7 +1113,7 @@ FuncDef *sqlite3VtabOverloadFunction( int rc = 0; /* Check to see the left operand is a column in a virtual table */ - if( NEVER(pExpr==0) ) return pDef; + if( pExpr==0 ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; diff --git a/test/func5.test b/test/func5.test index bfd545b4e3..8c3dd05c60 100644 --- a/test/func5.test +++ b/test/func5.test @@ -53,9 +53,10 @@ do_execsql_test func5-2.2 { WHERE x+counter1('hello')=counter1('hello')+x ORDER BY +x; } {} +set cvalue [db one {SELECT counter2('hello')+1}] do_execsql_test func5-2.3 { SELECT x, y FROM t2 - WHERE x+counter2('hello')=counter2('hello')+x + WHERE x+counter2('hello')=$cvalue+x ORDER BY +x; } {1 2 3 4 5 6 7 8} From 9b258c54e453edb5c8c81c3d28b2cb6e2b76a13e Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 11 Mar 2020 19:41:49 +0000 Subject: [PATCH 3/3] Rename sqlite3ExprCodeAtInit() to sqlite3ExprCodeRunJustOnce(). Other changes to make the new code cleaner. Test cases added. FossilOrigin-Name: d7f18489978fdbbe3ab317485518cac91a75416ccef55898301afdd76d3b415b --- manifest | 23 ++++++++++------------- manifest.uuid | 2 +- src/expr.c | 49 ++++++++++++++++++++++--------------------------- src/sqliteInt.h | 2 +- src/vdbe.c | 1 - src/vtab.c | 2 +- test/func.test | 20 ++++++++++++++++++++ 7 files changed, 55 insertions(+), 44 deletions(-) diff --git a/manifest b/manifest index 11b5b9c942..b990d901bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Do\snot\sfactor\sout\sconstant\sfunctions\sinto\sthe\sinitialization\ssection\sat\sthe\nend\sof\sthe\sprepared\sstatement,\sbe\scause\sif\sthey\sthrow\san\sexception,\sit\swill\nabort\sthe\sstatement\seven\sif\sthe\sfunction\sis\snever\scalled.\s\sBetter\sto\sput\nconstant\sfunctions\sin\san\sOP_Once\sblock. -D 2020-03-11T17:58:27.142 +C Rename\ssqlite3ExprCodeAtInit()\sto\ssqlite3ExprCodeRunJustOnce().\nOther\schanges\sto\smake\sthe\snew\scode\scleaner.\s\sTest\scases\sadded. +D 2020-03-11T19:41:49.390 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -483,7 +483,7 @@ F src/date.c 6c408fdd2e9ddf6e8431aba76315a2d061bea2cec8fbb75e25d7c1ba08274712 F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 0f55297469d4244ab7df395849e1af98eb5e95816af7c661e7d2d8402dea23da F src/delete.c 11000121c4281c0bce4e41db29addfaea0038eaa127ece02557c9207bc3e541d -F src/expr.c 137db48827025f68792824eaf8e4c66612dbd160cf5cafe6ae93b27eed101e12 +F src/expr.c ed718ee2206166c9c2fc4fe89eadb1f369318aeb8645e06033566b387970fb9a F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 4b575423b0a5d4898b1a7868ce985cf1a8ad91c741c9abbb108ff02536d20f41 F src/func.c 108577cebe8a50c86d849a93b99493a54e348dd0b846f00d13b52ca973d5baf4 @@ -536,7 +536,7 @@ F src/shell.c.in f76590931c0cbbfef347f44f81ade6b335f80c46bc6e59b8b6114383a8df30e F src/sqlite.h.in 802957feeb249ede54f8dfe99b72aa19e70a0b7737969c46e625dc2f9f2d42b0 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 9c5269260409eb3275324ccace6a13a96f4ad330c708415f70ca6097901ff4ee -F src/sqliteInt.h ed6885bb0ec82db2503c931fd96c795fc7a4b474dc075c3442a45c3a8523c797 +F src/sqliteInt.h 5f74c1c52b152259ee07f241821620f11736e4f590936cfaf1cbbff9a2f563d3 F src/sqliteLimit.h 95cb8479ca459496d9c1c6a9f76b38aee12203a56ce1092fe13e50ae2454c032 F src/status.c 9ff2210207c6c3b4d9631a8241a7d45ab1b26a0e9c84cb07a9b5ce2de9a3b278 F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -603,7 +603,7 @@ F src/upsert.c 2920de71b20f04fe25eb00b655d086f0ba60ea133c59d7fa3325c49838818e78 F src/utf.c 95fb6e03a5ca679045c5adccd05380f0addccabef5911abddcb06af069500ab7 F src/util.c a285c1e026907b69fa2592bd05047a565a1d8a1aef2b73c924b6a8ffe772871a F src/vacuum.c 813b510ba887fee6492bcb11f2bf77d7eb58b232b83649136372e0a2fc17f4b9 -F src/vdbe.c 8ad7906cf9aca841b97064fbf62323f53aaf8e4f8251ffa5e152abc5bda806d3 +F src/vdbe.c 6d0cf7ac2d54f78ff2fb55cbef970199695319c0a95bf862c6561d7d2c9f7134 F src/vdbe.h 51282fbe819ee0e8eeeaab176240860d334c20a12b14f3b363e7f1a4e05d60b9 F src/vdbeInt.h a17146053a1aa438474012998fe07e314f3df274a61491ad838ad85d848ac051 F src/vdbeapi.c 1252d80c548711e47a6d84dae88ed4e95d3fbb4e7bd0eaa1347299af7efddf02 @@ -612,7 +612,7 @@ F src/vdbeblob.c 253ed82894924c362a7fa3079551d3554cd1cdace39aa833da77d3bc67e7c1b F src/vdbemem.c 39b942ecca179f4f30a32b54579a85d74ccaefa5af2a0ad2700abe5ef0768b22 F src/vdbesort.c 2be76d26998ce2b3324cdcc9f6443728e54b6c7677c553ad909c7d7cfab587df F src/vdbetrace.c fa3bf238002f0bbbdfb66cc8afb0cea284ff9f148d6439bc1f6f2b4c3b7143f0 -F src/vtab.c ad810f9b771cf66eee2762e18eb2b704c97c18ca4b4bf25af7f88ab1fb254d14 +F src/vtab.c 7b704a90515a239c6cdba6a66b1bb3a385e62326cceb5ecb05ec7a091d6b8515 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c 697424314e40d99f93f548c7bfa526c10e87f4bdf64d5a76a96b999dd7133ebc F src/wal.h 606292549f5a7be50b6227bd685fa76e3a4affad71bb8ac5ce4cb5c79f6a176a @@ -1003,7 +1003,7 @@ F test/fts4rename.test 15fd9985c2bce6dea20da2245b22029ec89bd4710ed317c4c53abbe3c F test/fts4umlaut.test fcaca4471de7e78c9d1f7e8976e3e8704d7d8ad979d57a739d00f3f757380429 F test/fts4unicode.test ceca76422abc251818cb25dabe33d3c3970da5f7c90e1540f190824e6b3a7c95 F test/full.test 6b3c8fb43c6beab6b95438c1675374b95fab245d -F test/func.test b7f1a706d1bb8de103a24bd0c30c9e3dc3eedf0df24aabc54b0a4f6e08742622 +F test/func.test f673822636fb8ed618dd2b80230d16e495d19c8f2e2e7d6c22e93e2b3de097ad F test/func2.test 772d66227e4e6684b86053302e2d74a2500e1e0f F test/func3.test 2bb0f31ab7baaed690b962a88544d7be6b34fa389364bc36a44e441ed3e3f1e6 F test/func4.test a94858a8c1f10a408b0b3db439c990b59dbb2349411d503de011ac4e2b5f27a6 @@ -1860,10 +1860,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 fb5a8a9edd0a4f979d6c30278d4ddc73c651f56ae989b4e5983fca36887c5ceb -R cf3e121998a086e24f73b7daa3777948 -T *branch * do-not-factor-functions -T *sym-do-not-factor-functions * -T -sym-trunk * +P 97a18a5cd701848a9660385e31bffe2c397e3cfe57ccdb876f44d08c00d1d39a +R bb18f5b4c4c1d8067c8d33e0ad339acb U drh -Z 4a780ea0d068b9c3f4aeae83f545f604 +Z 791b16818e473b4676673e9f9494706b diff --git a/manifest.uuid b/manifest.uuid index 3625ef547a..9e7309105a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -97a18a5cd701848a9660385e31bffe2c397e3cfe57ccdb876f44d08c00d1d39a \ No newline at end of file +d7f18489978fdbbe3ab317485518cac91a75416ccef55898301afdd76d3b415b \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 8c0768bb7e..8587f5ec78 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2096,7 +2096,7 @@ int sqlite3ExprIsConstant(Expr *p){ ** ** When this routine returns true, it indicates that the expression ** can be added to the pParse->pConstExpr list and evaluated once when -** the prepared statement starts up. See sqlite3ExprCodeAtInit(). +** the prepared statement starts up. See sqlite3ExprCodeRunJustOnce(). */ int sqlite3ExprIsConstantNotJoin(Expr *p){ return exprIsConst(p, 2, 0); @@ -4127,9 +4127,9 @@ expr_code_doover: #endif if( ConstFactorOk(pParse) && sqlite3ExprIsConstantNotJoin(pExpr) ){ - /* SQL functions can be expensive. So try to move constant functions - ** out of the inner loop, even if that means an extra OP_Copy. */ - return sqlite3ExprCodeAtInit(pParse, pExpr, -1); + /* SQL functions can be expensive. So try to avoid running them + ** multiple times if we know they always give the same result */ + return sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); } assert( !ExprHasProperty(pExpr, EP_xIsSelect) ); assert( !ExprHasProperty(pExpr, EP_TokenOnly) ); @@ -4507,15 +4507,23 @@ expr_code_doover: } /* -** Factor out the code of the given expression to initialization time. +** Generate code that will evaluate expression pExpr just one time +** per prepared statement execution. +** +** If the expression uses functions (that might throw an exception) then +** guard them with an OP_Once opcode to ensure that the code is only executed +** once. If no functions are involved, then factor the code out and put it at +** the end of the prepared statement in the initialization section. ** ** If regDest>=0 then the result is always stored in that register and the ** result is not reusable. If regDest<0 then this routine is free to ** store the value whereever it wants. The register where the expression -** is stored is returned. When regDest<0, two identical expressions will -** code to the same register. +** is stored is returned. When regDest<0, two identical expressions might +** code to the same register, if they do not contain function calls and hence +** are factored out into the initialization section at the end of the +** prepared statement. */ -int sqlite3ExprCodeAtInit( +int sqlite3ExprCodeRunJustOnce( Parse *pParse, /* Parsing context */ Expr *pExpr, /* The expression to code when the VDBE initializes */ int regDest /* Store the value in this register */ @@ -4532,7 +4540,6 @@ int sqlite3ExprCodeAtInit( } } } - if( regDest<0 ) regDest = ++pParse->nMem; pExpr = sqlite3ExprDup(pParse->db, pExpr, 0); if( pExpr!=0 && ExprHasProperty(pExpr, EP_HasFunc) ){ Vdbe *v = pParse->pVdbe; @@ -4541,6 +4548,7 @@ int sqlite3ExprCodeAtInit( addr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); pParse->okConstFactor = 0; if( !pParse->db->mallocFailed ){ + if( regDest<0 ) regDest = ++pParse->nMem; sqlite3ExprCode(pParse, pExpr, regDest); } pParse->okConstFactor = 1; @@ -4551,6 +4559,7 @@ int sqlite3ExprCodeAtInit( if( p ){ struct ExprList_item *pItem = &p->a[p->nExpr-1]; pItem->reusable = regDest<0; + if( regDest<0 ) regDest = ++pParse->nMem; pItem->u.iConstExprReg = regDest; } pParse->pConstExpr = p; @@ -4579,7 +4588,7 @@ int sqlite3ExprCodeTemp(Parse *pParse, Expr *pExpr, int *pReg){ && sqlite3ExprIsConstantNotJoin(pExpr) ){ *pReg = 0; - r2 = sqlite3ExprCodeAtInit(pParse, pExpr, -1); + r2 = sqlite3ExprCodeRunJustOnce(pParse, pExpr, -1); }else{ int r1 = sqlite3GetTempReg(pParse); r2 = sqlite3ExprCodeTarget(pParse, pExpr, r1); @@ -4636,7 +4645,7 @@ void sqlite3ExprCodeCopy(Parse *pParse, Expr *pExpr, int target){ */ void sqlite3ExprCodeFactorable(Parse *pParse, Expr *pExpr, int target){ if( pParse->okConstFactor && sqlite3ExprIsConstantNotJoin(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target); + sqlite3ExprCodeRunJustOnce(pParse, pExpr, target); }else{ sqlite3ExprCodeCopy(pParse, pExpr, target); } @@ -4696,7 +4705,7 @@ int sqlite3ExprCodeExprList( }else if( (flags & SQLITE_ECEL_FACTOR)!=0 && sqlite3ExprIsConstantNotJoin(pExpr) ){ - sqlite3ExprCodeAtInit(pParse, pExpr, target+i); + sqlite3ExprCodeRunJustOnce(pParse, pExpr, target+i); }else{ int inReg = sqlite3ExprCodeTarget(pParse, pExpr, target+i); if( inReg!=target+i ){ @@ -5256,21 +5265,7 @@ int sqlite3ExprCompare(Parse *pParse, Expr *pA, Expr *pB, int iTab){ && ALWAYS((combinedFlags & EP_Reduced)==0) ){ if( pA->iColumn!=pB->iColumn ) return 2; - if( pA->op2!=pB->op2 ){ - if( pA->op==TK_TRUTH ) return 2; - if( pA->op==TK_FUNCTION && iTab<0 ){ - /* Ex: CREATE TABLE t1(a CHECK( aop2!=pB->op2 && pA->op==TK_TRUTH ) return 2; if( pA->op!=TK_IN && pA->iTable!=pB->iTable && pA->iTable!=iTab ){ return 2; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a5cf8d141d..7a00b576a0 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4239,7 +4239,7 @@ void sqlite3ExprCodeGeneratedColumn(Parse*, Column*, int); #endif void sqlite3ExprCodeCopy(Parse*, Expr*, int); void sqlite3ExprCodeFactorable(Parse*, Expr*, int); -int sqlite3ExprCodeAtInit(Parse*, Expr*, int); +int sqlite3ExprCodeRunJustOnce(Parse*, Expr*, int); int sqlite3ExprCodeTemp(Parse*, Expr*, int*); int sqlite3ExprCodeTarget(Parse*, Expr*, int); int sqlite3ExprCodeExprList(Parse*, ExprList*, int, int, u8); diff --git a/src/vdbe.c b/src/vdbe.c index 8501e7319e..a69c35d83a 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -1544,7 +1544,6 @@ case OP_Concat: { /* same as TK_CONCAT, in1, in2, out3 */ pIn1 = &aMem[pOp->p1]; pIn2 = &aMem[pOp->p2]; pOut = &aMem[pOp->p3]; - testcase( pIn1==pIn2 ); testcase( pOut==pIn2 ); assert( pIn1!=pOut ); flags1 = pIn1->flags; diff --git a/src/vtab.c b/src/vtab.c index 6a30f83a91..013511cfb4 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -1113,7 +1113,7 @@ FuncDef *sqlite3VtabOverloadFunction( int rc = 0; /* Check to see the left operand is a column in a virtual table */ - if( pExpr==0 ) return pDef; + if( NEVER(pExpr==0) ) return pDef; if( pExpr->op!=TK_COLUMN ) return pDef; pTab = pExpr->y.pTab; if( pTab==0 ) return pDef; diff --git a/test/func.test b/test/func.test index 34a6f18bcf..4b235bedb4 100644 --- a/test/func.test +++ b/test/func.test @@ -1477,4 +1477,24 @@ do_execsql_test func-34.10 { SELECT * FROM t1; } {1 2} +# 2020-03-11 COALESCE() should short-circuit +# See also ticket 3c9eadd2a6ba0aa5 +# Both issues stem from the fact that functions that could +# throw exceptions were being factored out into initialization +# code. The fix was to put those function calls inside of +# OP_Once instead. +# +reset_db +do_execsql_test func-35.100 { + CREATE TABLE t1(x); + SELECT coalesce(x, abs(-9223372036854775808)) FROM t1; +} {} +do_execsql_test func-35.110 { + SELECT coalesce(x, 'xyz' LIKE printf('%.1000000c','y')) FROM t1; +} {} +do_execsql_test func-35.200 { + CREATE TABLE t0(c0 CHECK(ABS(-9223372036854775808))); + PRAGMA integrity_check; +} {ok} + finish_test