From 1f3366cd68b935067005b5088f9306b57a09379d Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 17 Jan 2022 23:37:25 +0000 Subject: [PATCH 01/28] Allow an "IntReal" value to count as a REAL when checking types for insertion into a generated column on a STRICT table. [forum:/forumpost/fa012c77796d9399|Forum post fa012c77796d9399]. FossilOrigin-Name: 1ec44d55da2ced1a1b0b78b489caff628652464f5709ee827e35409eb20ea794 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbe.c | 4 +++- test/strict1.test | 27 +++++++++++++++++++++++++++ 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index c6e2b868e4..ee457e7d4b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sincorrect\stestcase()\sand\sassert()\smacros\sin\sjson.c.\s\sThey\swere\snot\scausing\nproblems.\s\sThe\sassert()\swas\ssimply\sunreachable.\s\sThe\stestcase()\sadded\san\nunreachable\scondition. -D 2022-01-17T15:23:57.622 +C Allow\san\s"IntReal"\svalue\sto\scount\sas\sa\sREAL\swhen\schecking\stypes\sfor\ninsertion\sinto\sa\sgenerated\scolumn\son\sa\sSTRICT\stable.\n[forum:/forumpost/fa012c77796d9399|Forum\spost\sfa012c77796d9399]. +D 2022-01-17T23:37:25.709 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -623,7 +623,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 -F src/vdbe.c 93b2403c28a9b902da1bc4dff82350c72eeb982976c95afca32b660a2dd33273 +F src/vdbe.c 71fbbf8da3d8aadf14a574b35b48f488166793e5add34908380ee2dc7c732c99 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5 F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a @@ -1438,7 +1438,7 @@ F test/stat.test 123212a20ceb496893d5254a5f6c76442ce549fdc08d1702d8288a2bbaac840 F test/statfault.test 55f86055f9cd7b2d962a621b8a04215c1cebd4eaaecde92d279442327fe648a0 F test/stmt.test 54ed2cc0764bf3e48a058331813c3dbd19fc1d0827c3d8369914a5d8f564ec75 F test/stmtvtab1.test 6873dfb24f8e79cbb5b799b95c2e4349060eb7a3b811982749a84b359468e2d5 -F test/strict1.test a3ec495471f24c1a6e1a1664bd23e24ccdb27ae93b1a763ee1942ec955b68e71 +F test/strict1.test 4d2b492152b984fd7e8196d23eb88e2ccb0ef9e46ca2f96c2ce7147ceef9d168 F test/strict2.test b22c7a98b5000aef937f1990776497f0e979b1a23bc4f63e2d53b00e59b20070 F test/subjournal.test 8d4e2572c0ee9a15549f0d8e40863161295107e52f07a3e8012a2e1fdd093c49 F test/subquery.test 3a1a5b600b8d4f504d2a2c61f33db820983dba94a0ef3e4aedca8f0165eaecb8 @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0407c8793700491b8519a649b9624f569b0e7e9b94d0db79d4a08139e0ecdb69 -R 670ac84bd1cbcf3ee71909c2b9111d9c +P 5623497adc8af9950fd79392000a68ba6fdca43594603eadaa7e19c8fb845a7d +R d7f30d4a9d7ccac7aeccaad0e2d1565f U drh -Z c2bcb8ac21e89e27e00a6871302a21a2 +Z 4500b696eddd282332eeff2a3e3b1ed5 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 993ab344b8..3732d28590 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5623497adc8af9950fd79392000a68ba6fdca43594603eadaa7e19c8fb845a7d \ No newline at end of file +1ec44d55da2ced1a1b0b78b489caff628652464f5709ee827e35409eb20ea794 \ No newline at end of file diff --git a/src/vdbe.c b/src/vdbe.c index 015acfc0f0..db9116e92b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -2986,6 +2986,8 @@ case OP_TypeCheck: { break; } case COLTYPE_REAL: { + testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_Real ); + testcase( (pIn1->flags & (MEM_Real|MEM_IntReal))==MEM_IntReal ); if( pIn1->flags & MEM_Int ){ /* When applying REAL affinity, if the result is still an MEM_Int ** that will fit in 6 bytes, then change the type to MEM_IntReal @@ -3003,7 +3005,7 @@ case OP_TypeCheck: { pIn1->flags |= MEM_Real; pIn1->flags &= ~MEM_Int; } - }else if( (pIn1->flags & MEM_Real)==0 ){ + }else if( (pIn1->flags & (MEM_Real|MEM_IntReal))==0 ){ goto vdbe_type_error; } break; diff --git a/test/strict1.test b/test/strict1.test index 67483413fa..fc6438843f 100644 --- a/test/strict1.test +++ b/test/strict1.test @@ -135,4 +135,31 @@ ifcapable altertable { } {1 {error in table t4 after add column: missing datatype for t4.d}} } +# 2022-01-17 https://sqlite.org/forum/forumpost/fa012c77796d9399 +# +reset_db +do_execsql_test strict1-8.1 { + CREATE TABLE csv_import_table ( + "debit" TEXT, + "credit" TEXT + ); + INSERT INTO csv_import_table VALUES ('', '250.00'); + CREATE TABLE IF NOT EXISTS transactions ( + debit REAL, + credit REAL, + amount REAL GENERATED ALWAYS AS (ifnull(credit, 0.0) - ifnull(debit, 0.0)) + ) STRICT; + INSERT INTO transactions + SELECT + nullif(debit, '') AS debit, + nullif(credit, '') AS credit + FROM csv_import_table; + SELECT * FROM transactions; +} {{} 250.0 250.0} +do_execsql_test strict1-8.2 { + CREATE TABLE t1(x REAL, y REAL AS (x)) STRICT; + INSERT INTO t1 VALUES(5),(4611686018427387904); + SELECT *, '|' FROM t1; +} {/5.0 5.0 4.6116\d*e\+18 4.6116\d+e\+18 |/} + finish_test From 85b70e009fcd9e307e84c2242bdf31327252acc7 Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 18 Jan 2022 16:16:32 +0000 Subject: [PATCH 02/28] Fix ALTER TABLE DROP COLUMN so that it invokes the authorizer. Fix for [forum:/forumpost/fd82b85947541dec|forum post fd82b85947541dec]. FossilOrigin-Name: aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/alter.c | 6 ++++++ test/auth.test | 43 +++++++++++++++++++++++++++++++++++++------ 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index ee457e7d4b..6120ebba42 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Allow\san\s"IntReal"\svalue\sto\scount\sas\sa\sREAL\swhen\schecking\stypes\sfor\ninsertion\sinto\sa\sgenerated\scolumn\son\sa\sSTRICT\stable.\n[forum:/forumpost/fa012c77796d9399|Forum\spost\sfa012c77796d9399]. -D 2022-01-17T23:37:25.709 +C Fix\sALTER\sTABLE\sDROP\sCOLUMN\sso\sthat\sit\sinvokes\sthe\sauthorizer.\sFix\sfor\n[forum:/forumpost/fd82b85947541dec|forum\spost\sfd82b85947541dec]. +D 2022-01-18T16:16:32.786 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -484,7 +484,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 67ef8e685f547038b7ad93a7c6571f790d0a5bb1c00632d5466ffb4ccf3ee6e8 +F src/alter.c e3943d8fbcaf60f79f39d4aecc56a6a8092f51f93d6a7c5b1db2633c5fa10c30 F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516 F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf @@ -698,7 +698,7 @@ F test/attach2.test 256bd240da1835fb8408dd59fb7ef71f8358c7a756c46662434d11d07ba3 F test/attach3.test c59d92791070c59272e00183b7353eeb94915976 F test/attach4.test 00e754484859998d124d144de6d114d920f2ed6ca2f961e6a7f4183c714f885e F test/attachmalloc.test 12c4f028e570acf9e0a4b0b7fe6f536e21f3d5ebddcece423603d0569beaf438 -F test/auth.test 567d917e0baddb6d0026a251cff977a3ab2c805a3cef906ba8653aafe7ad7240 +F test/auth.test 0f246deec5cb2f6f893f8fbb76628f182c08fe40f178b254dd72467ca012f657 F test/auth2.test 9eb7fce9f34bf1f50d3f366fb3e606be5a2000a1 F test/auth3.test 76d20a7fa136d63bcfcf8bcb65c0b1455ed71078d81f22bcd0550d3eb18594ab F test/autoanalyze1.test b9cc3f32a990fa56669b668d237c6d53e983554ae80c0604992e18869a0b2dec @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5623497adc8af9950fd79392000a68ba6fdca43594603eadaa7e19c8fb845a7d -R d7f30d4a9d7ccac7aeccaad0e2d1565f +P 1ec44d55da2ced1a1b0b78b489caff628652464f5709ee827e35409eb20ea794 +R 95e7a59705503a6dcb60422114f45f3f U drh -Z 4500b696eddd282332eeff2a3e3b1ed5 +Z 5be66cdbe738584adde3523c6d04c88d # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 3732d28590..2c628a8a94 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1ec44d55da2ced1a1b0b78b489caff628652464f5709ee827e35409eb20ea794 \ No newline at end of file +aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index f3f4f570e6..28efd28722 100644 --- a/src/alter.c +++ b/src/alter.c @@ -2131,6 +2131,12 @@ void sqlite3AlterDropColumn(Parse *pParse, SrcList *pSrc, const Token *pName){ iDb = sqlite3SchemaToIndex(db, pTab->pSchema); assert( iDb>=0 ); zDb = db->aDb[iDb].zDbSName; +#ifndef SQLITE_OMIT_AUTHORIZATION + /* Invoke the authorization callback. */ + if( sqlite3AuthCheck(pParse, SQLITE_ALTER_TABLE, zDb, pTab->zName, zCol) ){ + goto exit_drop_column; + } +#endif renameTestSchema(pParse, zDb, iDb==1, "", 0); renameFixQuotes(pParse, zDb, iDb==1); sqlite3NestedParse(pParse, diff --git a/test/auth.test b/test/auth.test index d8f23a15e2..d8afa2dbff 100644 --- a/test/auth.test +++ b/test/auth.test @@ -2069,6 +2069,15 @@ ifcapable {altertable} { do_test auth-1.302 { set authargs } {main t5 {} {}} + db eval BEGIN + set authargs {} + do_execsql_test auth-1.302-drop-1 { + ALTER TABLE t5 DROP COLUMN new_col_1; + } {} + db eval ROLLBACK + do_test auth-1.302-drop-2 { + set authargs + } {main t5 new_col_1 {}} do_test auth-1.303 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { @@ -2088,6 +2097,16 @@ ifcapable {altertable} { do_test auth-1.305 { set authargs } {main t5 {} {}} + db eval BEGIN + set authargs {} + do_execsql_test auth-1.305-drop-1 { + ALTER TABLE t5 DROP COLUMN new_col_1; + SELECT 1 FROM sqlite_schema WHERE name='t5' AND sql LIKE '%new_col_1%'; + } {1} + db eval ROLLBACK + do_test auth-1.305-drop-2 { + set authargs + } {main t5 new_col_1 {}} do_test auth-1.306 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { @@ -2104,10 +2123,22 @@ ifcapable {altertable} { set x [execsql {SELECT sql FROM temp.sqlite_master WHERE type='t5'}] regexp new_col_3 $x } {0} - do_test auth-1.308 { set authargs } {main t5 {} {}} + db eval BEGIN + set authargs {} + do_catchsql_test auth-1.308-drop-1 { + ALTER TABLE t5 DROP COLUMN new_col_1; + } {1 {not authorized}} + do_execsql_test auth-1.308-drop-2 { + SELECT 1 FROM sqlite_schema WHERE name='t5' AND sql LIKE '%new_col_1%'; + } {1} + do_test auth-1.308-drop-3 { + set authargs + } {main t5 new_col_1 {}} + db eval ROLLBACK + execsql {DROP TABLE t5} } ;# ifcapable altertable @@ -2159,7 +2190,7 @@ ifcapable {cte} { # MAIN: CREATE TABLE t1(a,b); # ifcapable altertable&&vtab { - do_test 1.350 { + do_test auth-1.350 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] @@ -2177,7 +2208,7 @@ ifcapable altertable&&vtab { do_test auth-1.352 { set authargs } {main t1 {} {}} - do_test 1.353 { + do_test auth-1.353 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] @@ -2195,7 +2226,7 @@ ifcapable altertable&&vtab { do_test auth-1.355 { set authargs } {main t1 {} {}} - do_test 1.356 { + do_test auth-1.356 { proc auth {code arg1 arg2 arg3 arg4 args} { if {$code=="SQLITE_ALTER_TABLE"} { set ::authargs [list $arg1 $arg2 $arg3 $arg4] @@ -2207,10 +2238,10 @@ ifcapable altertable&&vtab { ALTER TABLE t1 RENAME COLUMN bcdefg TO b; } } {1 {not authorized}} - do_execsql_test auth-1.356 { + do_execsql_test auth-1.357 { SELECT name FROM pragma_table_info('t1') ORDER BY cid; } {a bcdefg} - do_test auth-1.357 { + do_test auth-1.358 { set authargs } {main t1 {} {}} } From 29a7bbffba41d55b9606d3dd8073dc54c9eb89e9 Mon Sep 17 00:00:00 2001 From: drh <> Date: Wed, 19 Jan 2022 18:31:43 +0000 Subject: [PATCH 03/28] Fix a test result for alterauth2.test due to the recent fix to authorizer calls for ALTER TABLE DROP COLUMN. FossilOrigin-Name: e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/alterauth2.test | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 6120ebba42..01dc783a6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sALTER\sTABLE\sDROP\sCOLUMN\sso\sthat\sit\sinvokes\sthe\sauthorizer.\sFix\sfor\n[forum:/forumpost/fd82b85947541dec|forum\spost\sfd82b85947541dec]. -D 2022-01-18T16:16:32.786 +C Fix\sa\stest\sresult\sfor\salterauth2.test\sdue\sto\sthe\srecent\sfix\sto\sauthorizer\ncalls\sfor\sALTER\sTABLE\sDROP\sCOLUMN. +D 2022-01-19T18:31:43.542 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -655,7 +655,7 @@ F test/alter2.test a966ccfcddf9ce0a4e0e6ff1aca9e6e7948e0e242cd7e43fc091948521807 F test/alter3.test ffc4ab29ce78a3517a66afd69b2730667e3471622509c283b2bd4c46f680fba3 F test/alter4.test 716caa071dd8a3c6d57225778d15d3c3cbf5e34b2e84ae44199aeb2bbf50a707 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959 -F test/alterauth2.test 381b1ab603c9ef96314a3158528ea17f7964449385a28eeaf8191120b2e24a8d +F test/alterauth2.test 48967abae0494d9a300d1c92473d99fcb66edfcc23579c89322f033f49410adc F test/altercol.test 9471187fe155d9c4211ae185e104ff48ce8f114262ee1256cf1e110b339c725f F test/altercorrupt.test 2e1d705342cf9d7de884518ddbb053fd52d7e60d2b8869b7b63b2fda68435c12 F test/alterdropcol.test a653a3945f964d26845ec0cd0a8e74189f46de3119a984c5bc45457da392612e @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1ec44d55da2ced1a1b0b78b489caff628652464f5709ee827e35409eb20ea794 -R 95e7a59705503a6dcb60422114f45f3f +P aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 +R 49af707cd669468ece46f1dd370b2f63 U drh -Z 5be66cdbe738584adde3523c6d04c88d +Z 256bb3763483caaf79af6f149c662bf0 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2c628a8a94..672d9b9c73 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 \ No newline at end of file +e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 \ No newline at end of file diff --git a/test/alterauth2.test b/test/alterauth2.test index 27ded1c3ea..6f9242d364 100644 --- a/test/alterauth2.test +++ b/test/alterauth2.test @@ -99,6 +99,7 @@ do_auth_test 1.2 { do_auth_test 1.3 { ALTER TABLE t2 DROP COLUMN c; } { + {SQLITE_ALTER_TABLE main t2 c {}} {SQLITE_FUNCTION {} like {} {}} {SQLITE_FUNCTION {} sqlite_drop_column {} {}} {SQLITE_FUNCTION {} sqlite_rename_quotefix {} {}} From d6b44ec32a5709cb56cc6f9d9a80c1a336f1a53c Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 20 Jan 2022 02:04:53 +0000 Subject: [PATCH 04/28] Fix the ability to read read-only WAL-mode database when -shm is present, ([00ec95fcd02bb415|check-in 00ec95fcd02bb415]) so that it works for the case of 64K page size. FossilOrigin-Name: f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd --- manifest | 14 +- manifest.uuid | 2 +- src/wal.c | 6 +- test/walro2.test | 689 ++++++++++++++++++++++++----------------------- 4 files changed, 359 insertions(+), 352 deletions(-) diff --git a/manifest b/manifest index 01dc783a6f..7cf6470469 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\stest\sresult\sfor\salterauth2.test\sdue\sto\sthe\srecent\sfix\sto\sauthorizer\ncalls\sfor\sALTER\sTABLE\sDROP\sCOLUMN. -D 2022-01-19T18:31:43.542 +C Fix\sthe\sability\sto\sread\sread-only\sWAL-mode\sdatabase\swhen\s-shm\sis\spresent,\n([00ec95fcd02bb415|check-in\s00ec95fcd02bb415])\sso\sthat\sit\sworks\nfor\sthe\scase\sof\s64K\spage\ssize. +D 2022-01-20T02:04:53.654 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -635,7 +635,7 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c ed0398a7adf02c31e34aada42cc86c58f413a7afe5f741a5d373ad087abde028 +F src/wal.c c55ef660f9ee91e1331ced61f312aae81179ff9ec8632639136bcb252ce86e1b F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7 @@ -1753,7 +1753,7 @@ F test/walpersist.test 8c6b7e3ec1ba91b5e4dc4e0921d6d3f87cd356a6 F test/walprotocol.test 1b3f922125e341703f6e946d77fdc564d38fb3e07a9385cfdc6c99cac1ecf878 F test/walprotocol2.test 7d3b6b4bf0b12f8007121b1e6ef714bc99101fb3b48e46371df1db868eebc131 F test/walro.test cb438d05ba0d191f10b688e39c4f0cd5b71569a1d1f4440e5bdf3c6880e08c20 -F test/walro2.test 0e79dd15cbdb4f482c01ea248373669c732414a726b357d04846a816afafb768 +F test/walro2.test 33955a6fd874dd9724005e17f77fef89d334b3171454a1256fe4941a96766cdc F test/walrofault.test c70cb6e308c443867701856cce92ad8288cd99488fa52afab77cca6cfd51af68 F test/walsetlk.test 3185bebc90557e0d611442c8d64f7a0cb7b06f8e156eea37a4a7358f722715be F test/walshared.test 0befc811dcf0b287efae21612304d15576e35417 @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P aca6c61d79215519fb006af19d9011029df68f195a4ce65aff7a1bf4e36efb94 -R 49af707cd669468ece46f1dd370b2f63 +P e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 +R a570f2b782808526402854b4e442ef9f U drh -Z 256bb3763483caaf79af6f149c662bf0 +Z ad5c72d40960b0db8c967cbfe55162e8 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 672d9b9c73..d86b834717 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 \ No newline at end of file +f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index a0ec91965c..37930f89e2 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2520,6 +2520,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ volatile void *pDummy; /* Dummy argument for xShmMap */ int rc; /* Return code */ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */ + int szPage; /* Page size */ assert( pWal->bShmUnreliable ); assert( pWal->readOnly & WAL_SHM_RDONLY ); @@ -2603,7 +2604,8 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ } /* Allocate a buffer to read frames into */ - szFrame = pWal->hdr.szPage + WAL_FRAME_HDRSIZE; + szPage = walPagesize(pWal); + szFrame = szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -2617,7 +2619,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ ** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; - for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->hdr.szPage); + for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){ diff --git a/test/walro2.test b/test/walro2.test index 34408c1695..1eb9d1c3ee 100644 --- a/test/walro2.test +++ b/test/walro2.test @@ -50,357 +50,362 @@ do_execsql_test 0.0 { CREATE TABLE t1(x); } {wal} set MINSHMSZ [file size test.db-shm] +set dfltpgsz [db one {PRAGMA page_size}] foreach bZeroShm {0 1} { -set TN [expr $bZeroShm+1] -do_multiclient_test tn { - - # Close all connections and delete the database. - # - code1 { db close } - code2 { db2 close } - code3 { db3 close } - forcedelete test.db - - # Do not run tests with the connections in the same process. - # - if {$tn==2} continue - - foreach c {code1 code2 code3} { - $c { - sqlite3_shutdown - sqlite3_config_uri 1 - } - } - - do_test $TN.1.1 { - code2 { sqlite3 db2 test.db } - sql2 { - CREATE TABLE t1(x, y); - PRAGMA journal_mode = WAL; - INSERT INTO t1 VALUES('a', 'b'); - INSERT INTO t1 VALUES('c', 'd'); - } - file exists test.db-shm - } {1} - - do_test $TN.1.2.1 { - copy_to_test2 $bZeroShm - code1 { - sqlite3 db file:test.db2?readonly_shm=1 - } - - sql1 { SELECT * FROM t1 } - } {a b c d} - do_test $TN.1.2.2 { - sql1 { SELECT * FROM t1 } - } {a b c d} - - do_test $TN.1.3.1 { - code3 { sqlite3 db3 test.db2 } - sql3 { SELECT * FROM t1 } - } {a b c d} - - do_test $TN.1.3.2 { - sql1 { SELECT * FROM t1 } - } {a b c d} - - code1 { db close } - code2 { db2 close } - code3 { db3 close } - - do_test $TN.2.1 { - code2 { sqlite3 db2 test.db } - sql2 { - INSERT INTO t1 VALUES('e', 'f'); - INSERT INTO t1 VALUES('g', 'h'); - } - file exists test.db-shm - } {1} - - do_test $TN.2.2 { - copy_to_test2 $bZeroShm - code1 { - sqlite3 db file:test.db2?readonly_shm=1 - } - sql1 { - BEGIN; - SELECT * FROM t1; - } - } {a b c d e f g h} - - do_test $TN.2.3.1 { - code3 { sqlite3 db3 test.db2 } - sql3 { SELECT * FROM t1 } - } {a b c d e f g h} - do_test $TN.2.3.2 { - sql3 { INSERT INTO t1 VALUES('i', 'j') } - code3 { db3 close } - sql1 { COMMIT } - } {} - do_test $TN.2.3.3 { - sql1 { SELECT * FROM t1 } - } {a b c d e f g h i j} - - - #----------------------------------------------------------------------- - # 3.1.*: That a readonly_shm connection can read a database file if both - # the *-wal and *-shm files are zero bytes in size. - # - # 3.2.*: That it flushes the cache if, between transactions on a db with a - # zero byte *-wal file, some other connection modifies the db, then - # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file - # back to zero bytes in size. - # - # 3.3.*: That, if between transactions some other process wraps the wal - # file, the readonly_shm client reruns recovery. - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - do_test $TN.3.1.0 { - list [file exists test.db-wal] [file exists test.db-shm] - } {0 0} - do_test $TN.3.1.1 { - close [open test.db-wal w] - close [open test.db-shm w] - code1 { - sqlite3 db file:test.db?readonly_shm=1 - } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h} - - do_test $TN.3.2.0 { - list [file size test.db-wal] [file size test.db-shm] - } {0 0} - do_test $TN.3.2.1 { - code2 { sqlite3 db2 test.db } - sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } - code2 { db2 close } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h 1 2} - do_test $TN.3.2.2 { - list [file size test.db-wal] [file size test.db-shm] - } [list 0 $MINSHMSZ] - - do_test $TN.3.3.0 { - code2 { sqlite3 db2 test.db } - sql2 { - INSERT INTO t1 VALUES(3, 4); - INSERT INTO t1 VALUES(5, 6); - INSERT INTO t1 VALUES(7, 8); - INSERT INTO t1 VALUES(9, 10); - } - code2 { db2 close } - code1 { db close } - list [file size test.db-wal] [file size test.db-shm] - } [list [wal_file_size 4 1024] $MINSHMSZ] - do_test $TN.3.3.1 { - code1 { sqlite3 db file:test.db?readonly_shm=1 } - sql1 { SELECT * FROM t1 } - } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} - do_test $TN.3.3.2 { - code2 { sqlite3 db2 test.db } - sql2 { - PRAGMA wal_checkpoint; - DELETE FROM t1; - INSERT INTO t1 VALUES('i', 'ii'); - } - code2 { db2 close } - list [file size test.db-wal] [file size test.db-shm] - } [list [wal_file_size 4 1024] $MINSHMSZ] - do_test $TN.3.3.3 { - sql1 { SELECT * FROM t1 } - } {i ii} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.4.0 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - } - - copy_to_test2 $bZeroShm - - code1 { db close } - } {} - - do_test $TN.4.1.1 { - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { SELECT * FROM t1 } - } {hello world} - - do_test $TN.4.1.2 { - code3 { sqlite3 db3 test.db2 } - sql3 { - INSERT INTO t1 VALUES('!'); - PRAGMA wal_checkpoint = truncate; - } - code3 { db3 close } - } {} - do_test $TN.4.1.3 { - sql2 { SELECT * FROM t1 } - } {hello world !} - - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.4.2.1 { - code1 { sqlite3 db test.db } - sql1 { - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('!'); - - PRAGMA cache_size = 10; - CREATE TABLE t2(x); - - BEGIN; - WITH s(i) AS ( - SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 - ) - INSERT INTO t2 SELECT randomblob(500) FROM s; - SELECT count(*) FROM t2; - } - } {500} - set sz [file size test.db-wal] - do_test $TN.4.2.2.(sz=$sz) { - expr {$sz>400000} - } {1} - do_test $TN.4.2.4 { - file_control_persist_wal db 1; db close - - copy_to_test2 $bZeroShm - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { - SELECT * FROM t1; - SELECT count(*) FROM t2; - } - } {hello world ! ! 0} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.5.0 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('hello'); - } - - copy_to_test2 $bZeroShm + for {set pgsz 512} {$pgsz<=65536} {set pgsz [expr {$pgsz*2}]} { + set TN [expr $bZeroShm+1]-$pgsz + do_multiclient_test tn { + + # Close all connections and delete the database. + # + code1 { db close } + code2 { db2 close } + code3 { db3 close } + forcedelete test.db + + # Do not run tests with the connections in the same process. + # + if {$tn==2} continue - code1 { db close } - } {} - - do_test $TN.5.1 { - code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } - sql2 { - SELECT * FROM t1; - } - } {hello world ! world hello} - - do_test $TN.5.2 { - code1 { - proc handle_read {op args} { - if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { - set ::res2 [sql2 { SELECT * FROM t1 }] + foreach c {code1 code2 code3} { + $c { + sqlite3_shutdown + sqlite3_config_uri 1 } - puts "$msg xRead $args" - return "SQLITE_OK" } - testvfs tvfs -fullshm 1 - - sqlite3 db file:test.db2?vfs=tvfs - db eval { SELECT * FROM sqlite_master } - - tvfs filter xRead - tvfs script handle_read - } - sql1 { - PRAGMA wal_checkpoint = truncate; - } - code1 { set ::res2 } - } {hello world ! world hello} - - do_test $TN.5.3 { - code1 { db close } - code1 { tvfs delete } - } {} - - #----------------------------------------------------------------------- - # - # - catch { code1 { db close } } - catch { code2 { db2 close } } - catch { code3 { db3 close } } - - do_test $TN.6.1 { - code1 { forcedelete test.db } - code1 { sqlite3 db test.db } - sql1 { - PRAGMA journal_mode = wal; - CREATE TABLE t1(x); - INSERT INTO t1 VALUES('hello'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('!'); - INSERT INTO t1 VALUES('world'); - INSERT INTO t1 VALUES('hello'); - } - - copy_to_test2 $bZeroShm - code1 { db close } - } {} - - do_test $TN.6.2 { - code1 { - set ::nRem 5 - proc handle_read {op args} { - if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { - incr ::nRem -1 - if {$::nRem==0} { - code2 { sqlite3 db2 test.db2 } - sql2 { PRAGMA wal_checkpoint = truncate } + do_test $TN.1.1 { + code2 { sqlite3 db2 test.db } + sql2 "PRAGMA page_size=$::pgsz" + sql2 { + CREATE TABLE t1(x, y); + PRAGMA journal_mode = WAL; + INSERT INTO t1 VALUES('a', 'b'); + INSERT INTO t1 VALUES('c', 'd'); + } + file exists test.db-shm + } {1} + + do_test $TN.1.2.1 { + copy_to_test2 $bZeroShm + code1 { + sqlite3 db file:test.db2?readonly_shm=1 + } + + sql1 { SELECT * FROM t1 } + } {a b c d} + do_test $TN.1.2.2 { + sql1 { SELECT * FROM t1 } + } {a b c d} + + do_test $TN.1.3.1 { + code3 { sqlite3 db3 test.db2 } + sql3 { SELECT * FROM t1 } + } {a b c d} + + do_test $TN.1.3.2 { + sql1 { SELECT * FROM t1 } + } {a b c d} + + code1 { db close } + code2 { db2 close } + code3 { db3 close } + + do_test $TN.2.1 { + code2 { sqlite3 db2 test.db } + sql2 "PRAGMA page_size=$::pgsz;" + sql2 { + INSERT INTO t1 VALUES('e', 'f'); + INSERT INTO t1 VALUES('g', 'h'); + } + file exists test.db-shm + } {1} + + do_test $TN.2.2 { + copy_to_test2 $bZeroShm + code1 { + sqlite3 db file:test.db2?readonly_shm=1 + } + sql1 { + BEGIN; + SELECT * FROM t1; + } + } {a b c d e f g h} + + do_test $TN.2.3.1 { + code3 { sqlite3 db3 test.db2 } + sql3 { SELECT * FROM t1 } + } {a b c d e f g h} + do_test $TN.2.3.2 { + sql3 { INSERT INTO t1 VALUES('i', 'j') } + code3 { db3 close } + sql1 { COMMIT } + } {} + do_test $TN.2.3.3 { + sql1 { SELECT * FROM t1 } + } {a b c d e f g h i j} + + + #----------------------------------------------------------------------- + # 3.1.*: That a readonly_shm connection can read a database file if both + # the *-wal and *-shm files are zero bytes in size. + # + # 3.2.*: That it flushes the cache if, between transactions on a db with a + # zero byte *-wal file, some other connection modifies the db, then + # does "PRAGMA wal_checkpoint=truncate" to truncate the wal file + # back to zero bytes in size. + # + # 3.3.*: That, if between transactions some other process wraps the wal + # file, the readonly_shm client reruns recovery. + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + do_test $TN.3.1.0 { + list [file exists test.db-wal] [file exists test.db-shm] + } {0 0} + do_test $TN.3.1.1 { + close [open test.db-wal w] + close [open test.db-shm w] + code1 { + sqlite3 db file:test.db?readonly_shm=1 + } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h} + + do_test $TN.3.2.0 { + list [file size test.db-wal] [file size test.db-shm] + } {0 0} + do_test $TN.3.2.1 { + code2 { sqlite3 db2 test.db } + sql2 { INSERT INTO t1 VALUES(1, 2) ; PRAGMA wal_checkpoint=truncate } + code2 { db2 close } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h 1 2} + if {$pgsz!=$dfltpgsz} continue + do_test $TN.3.2.2 { + list [file size test.db-wal] [file size test.db-shm] + } [list 0 $MINSHMSZ] + do_test $TN.3.3.0 { + code2 { sqlite3 db2 test.db } + sql2 { + INSERT INTO t1 VALUES(3, 4); + INSERT INTO t1 VALUES(5, 6); + INSERT INTO t1 VALUES(7, 8); + INSERT INTO t1 VALUES(9, 10); + } + code2 { db2 close } + code1 { db close } + list [file size test.db-wal] [file size test.db-shm] + } [list [wal_file_size 4 1024] $MINSHMSZ] + do_test $TN.3.3.1 { + code1 { sqlite3 db file:test.db?readonly_shm=1 } + sql1 { SELECT * FROM t1 } + } {a b c d e f g h 1 2 3 4 5 6 7 8 9 10} + do_test $TN.3.3.2 { + code2 { sqlite3 db2 test.db } + sql2 { + PRAGMA wal_checkpoint; + DELETE FROM t1; + INSERT INTO t1 VALUES('i', 'ii'); + } + code2 { db2 close } + list [file size test.db-wal] [file size test.db-shm] + } [list [wal_file_size 4 1024] $MINSHMSZ] + do_test $TN.3.3.3 { + sql1 { SELECT * FROM t1 } + } {i ii} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.4.0 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.4.1.1 { + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { SELECT * FROM t1 } + } {hello world} + + do_test $TN.4.1.2 { + code3 { sqlite3 db3 test.db2 } + sql3 { + INSERT INTO t1 VALUES('!'); + PRAGMA wal_checkpoint = truncate; + } + code3 { db3 close } + } {} + do_test $TN.4.1.3 { + sql2 { SELECT * FROM t1 } + } {hello world !} + + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.4.2.1 { + code1 { sqlite3 db test.db } + sql1 { + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('!'); + + PRAGMA cache_size = 10; + CREATE TABLE t2(x); + + BEGIN; + WITH s(i) AS ( + SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<500 + ) + INSERT INTO t2 SELECT randomblob(500) FROM s; + SELECT count(*) FROM t2; + } + } {500} + set sz [file size test.db-wal] + do_test $TN.4.2.2.(sz=$sz) { + expr {$sz>400000} + } {1} + do_test $TN.4.2.4 { + file_control_persist_wal db 1; db close + + copy_to_test2 $bZeroShm + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { + SELECT * FROM t1; + SELECT count(*) FROM t2; + } + } {hello world ! ! 0} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.5.0 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('hello'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.5.1 { + code2 { sqlite3 db2 file:test.db2?readonly_shm=1 } + sql2 { + SELECT * FROM t1; + } + } {hello world ! world hello} + + do_test $TN.5.2 { + code1 { + proc handle_read {op args} { + if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { + set ::res2 [sql2 { SELECT * FROM t1 }] + } + puts "$msg xRead $args" + return "SQLITE_OK" } + testvfs tvfs -fullshm 1 + + sqlite3 db file:test.db2?vfs=tvfs + db eval { SELECT * FROM sqlite_master } + + tvfs filter xRead + tvfs script handle_read } - return "SQLITE_OK" - } - testvfs tvfs -fullshm 1 - - tvfs filter xRead - tvfs script handle_read - - sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs - db eval { SELECT * FROM t1 } + sql1 { + PRAGMA wal_checkpoint = truncate; + } + code1 { set ::res2 } + } {hello world ! world hello} + + do_test $TN.5.3 { + code1 { db close } + code1 { tvfs delete } + } {} + + #----------------------------------------------------------------------- + # + # + catch { code1 { db close } } + catch { code2 { db2 close } } + catch { code3 { db3 close } } + + do_test $TN.6.1 { + code1 { forcedelete test.db } + code1 { sqlite3 db test.db } + sql1 { + PRAGMA journal_mode = wal; + CREATE TABLE t1(x); + INSERT INTO t1 VALUES('hello'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('!'); + INSERT INTO t1 VALUES('world'); + INSERT INTO t1 VALUES('hello'); + } + + copy_to_test2 $bZeroShm + + code1 { db close } + } {} + + do_test $TN.6.2 { + code1 { + set ::nRem 5 + proc handle_read {op args} { + if {$op=="xRead" && [file tail [lindex $args 0]]=="test.db2-wal"} { + incr ::nRem -1 + if {$::nRem==0} { + code2 { sqlite3 db2 test.db2 } + sql2 { PRAGMA wal_checkpoint = truncate } + } + } + return "SQLITE_OK" + } + testvfs tvfs -fullshm 1 + + tvfs filter xRead + tvfs script handle_read + + sqlite3 db file:test.db2?readonly_shm=1&vfs=tvfs + db eval { SELECT * FROM t1 } + } + } {hello world ! world hello} + + do_test $TN.6.3 { + code1 { db close } + code1 { tvfs delete } + } {} } - } {hello world ! world hello} - - do_test $TN.6.3 { - code1 { db close } - code1 { tvfs delete } - } {} -} + } ;# for pgsz } ;# foreach bZeroShm finish_test From 98bb34c501dfa59b22c2a7110b7b76fb1df5c90d Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 20 Jan 2022 12:58:15 +0000 Subject: [PATCH 05/28] Fix harmless scan-build warnings. FossilOrigin-Name: ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 1 + src/vdbe.c | 1 - 4 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 7cf6470469..33c4f075da 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\sability\sto\sread\sread-only\sWAL-mode\sdatabase\swhen\s-shm\sis\spresent,\n([00ec95fcd02bb415|check-in\s00ec95fcd02bb415])\sso\sthat\sit\sworks\nfor\sthe\scase\sof\s64K\spage\ssize. -D 2022-01-20T02:04:53.654 +C Fix\sharmless\sscan-build\swarnings. +D 2022-01-20T12:58:15.816 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -551,7 +551,7 @@ F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c a4a23a70f0a24a1103ac9698f6be181a6ec7ff6c19e03e8899c43cb6d2af09d6 +F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -623,7 +623,7 @@ F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 -F src/vdbe.c 71fbbf8da3d8aadf14a574b35b48f488166793e5add34908380ee2dc7c732c99 +F src/vdbe.c cfe1980fbeb87eb35297b4a41808034761f26277cf45c9cf3e4eac20edcba1d5 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5 F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e799a35f2bf85ce43b476738bfbd9b6b378bbf02fa0708dda0deba71dd37f608 -R a570f2b782808526402854b4e442ef9f +P f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd +R 28fbf90223c9405cd84e24c8fccd3062 U drh -Z ad5c72d40960b0db8c967cbfe55162e8 +Z 61feeb81d56e471280e3dafdb42e233a # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d86b834717..20e02c7c16 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd \ No newline at end of file +ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf \ No newline at end of file diff --git a/src/select.c b/src/select.c index 2d1b54b3ae..a0fc3d90f5 100644 --- a/src/select.c +++ b/src/select.c @@ -3436,6 +3436,7 @@ static int multiSelectOrderBy( for(i=2; ipPrior; } } pPrior = pSplit->pPrior; + assert( pPrior!=0 ); pSplit->pPrior = 0; pPrior->pNext = 0; assert( p->pOrderBy == pOrderBy ); diff --git a/src/vdbe.c b/src/vdbe.c index db9116e92b..d4ff33141b 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -677,7 +677,6 @@ static u64 filterHash(const Mem *aMem, const Op *pOp){ int i, mx; u64 h = 0; - i = pOp->p3; assert( pOp->p4type==P4_INT32 ); for(i=pOp->p3, mx=i+pOp->p4.i; i Date: Thu, 20 Jan 2022 14:40:34 +0000 Subject: [PATCH 06/28] A better and more robust fix for the problem of reading a read-only WAL mode database with existing -wal and -shm files, replacing [f426874e005e3c23]. FossilOrigin-Name: 71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/wal.c | 8 ++++---- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 33c4f075da..9cea17bdca 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\sscan-build\swarnings. -D 2022-01-20T12:58:15.816 +C A\sbetter\sand\smore\srobust\sfix\sfor\sthe\sproblem\sof\sreading\sa\sread-only\sWAL\nmode\sdatabase\swith\sexisting\s-wal\sand\s-shm\sfiles,\sreplacing\s[f426874e005e3c23]. +D 2022-01-20T14:40:34.203 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -635,7 +635,7 @@ F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf8 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 -F src/wal.c c55ef660f9ee91e1331ced61f312aae81179ff9ec8632639136bcb252ce86e1b +F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7 @@ -1938,8 +1938,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f426874e005e3c23e8a00083b7c201408e072bca413e52bfc436da6483afb0cd -R 28fbf90223c9405cd84e24c8fccd3062 +P ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf +R 23c453292071b3de4a1e0dc51f1f1bde U drh -Z 61feeb81d56e471280e3dafdb42e233a +Z 048e904f267f4777d2809de2936b5439 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 20e02c7c16..9abd24dbef 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf \ No newline at end of file +71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 \ No newline at end of file diff --git a/src/wal.c b/src/wal.c index 37930f89e2..fdc4ac39b6 100644 --- a/src/wal.c +++ b/src/wal.c @@ -2520,7 +2520,6 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ volatile void *pDummy; /* Dummy argument for xShmMap */ int rc; /* Return code */ u32 aSaveCksum[2]; /* Saved copy of pWal->hdr.aFrameCksum */ - int szPage; /* Page size */ assert( pWal->bShmUnreliable ); assert( pWal->readOnly & WAL_SHM_RDONLY ); @@ -2604,8 +2603,9 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ } /* Allocate a buffer to read frames into */ - szPage = walPagesize(pWal); - szFrame = szPage + WAL_FRAME_HDRSIZE; + assert( (pWal->szPage & (pWal->szPage-1))==0 ); + assert( pWal->szPage>=512 && pWal->szPage<=65536 ); + szFrame = pWal->szPage + WAL_FRAME_HDRSIZE; aFrame = (u8 *)sqlite3_malloc64(szFrame); if( aFrame==0 ){ rc = SQLITE_NOMEM_BKPT; @@ -2619,7 +2619,7 @@ static int walBeginShmUnreliable(Wal *pWal, int *pChanged){ ** the caller. */ aSaveCksum[0] = pWal->hdr.aFrameCksum[0]; aSaveCksum[1] = pWal->hdr.aFrameCksum[1]; - for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, szPage); + for(iOffset=walFrameOffset(pWal->hdr.mxFrame+1, pWal->szPage); iOffset+szFrame<=szWal; iOffset+=szFrame ){ From 82801a5b72809b57f2ced68c239151daa8a1ee44 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 20 Jan 2022 17:10:59 +0000 Subject: [PATCH 07/28] Initial implementation of the sqlite3_vtab_rhs_value() interface and the qpvtab extension used for testing the virtual table interface. FossilOrigin-Name: 0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5 --- Makefile.in | 1 + Makefile.msc | 1 + ext/misc/qpvtab.c | 338 ++++++++++++++++++++++++++++++++++++++++++++++ main.mk | 1 + manifest | 30 ++-- manifest.uuid | 2 +- src/loadext.c | 1 + src/sqlite.h.in | 23 ++++ src/sqlite3ext.h | 2 + src/test1.c | 2 + src/where.c | 66 ++++++++- 11 files changed, 446 insertions(+), 21 deletions(-) create mode 100644 ext/misc/qpvtab.c diff --git a/Makefile.in b/Makefile.in index 9d37f883e9..b70e2d5167 100644 --- a/Makefile.in +++ b/Makefile.in @@ -460,6 +460,7 @@ TESTSRC += \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/prefixes.c \ + $(TOP)/ext/misc/qpvtab.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ diff --git a/Makefile.msc b/Makefile.msc index ef78eae62f..a77d8b0447 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1579,6 +1579,7 @@ TESTEXT = \ $(TOP)\ext\misc\normalize.c \ $(TOP)\ext\misc\percentile.c \ $(TOP)\ext\misc\prefixes.c \ + $(TOP)\ext\misc\qpvtab.c \ $(TOP)\ext\misc\regexp.c \ $(TOP)\ext\misc\remember.c \ $(TOP)\ext\misc\series.c \ diff --git a/ext/misc/qpvtab.c b/ext/misc/qpvtab.c new file mode 100644 index 0000000000..fb22b61d68 --- /dev/null +++ b/ext/misc/qpvtab.c @@ -0,0 +1,338 @@ +/* +** 2022-01-19 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** +** This file implements a virtual-table that returns information about +** how the query planner called the xBestIndex method. This virtual table +** is intended for testing and debugging only. +** +** The schema of the virtual table is this: +** +** CREATE TABLE qpvtab(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t); +** +** There is also a HIDDEN column "flags". +** +** All columns except column "a" have a value that is either TEXT that +** is there name, or INTEGER which is their index (b==1). TEXT is the +** default, but INTEGER is used of there is a constraint on flags where the +** right-hand side is an integer that includes the 1 bit. +** +** The "a" column returns text that describes one of the parameters that +** xBestIndex was called with. A completely query of the table should +** show all details of how xBestIndex was called. +*/ +#if !defined(SQLITEINT_H) +#include "sqlite3ext.h" +#endif +SQLITE_EXTENSION_INIT1 +#include +#include + +#if !defined(SQLITE_OMIT_VIRTUALTABLE) + +/* qpvtab_vtab is a subclass of sqlite3_vtab which is +** underlying representation of the virtual table +*/ +typedef struct qpvtab_vtab qpvtab_vtab; +struct qpvtab_vtab { + sqlite3_vtab base; /* Base class - must be first */ +}; + +/* qpvtab_cursor is a subclass of sqlite3_vtab_cursor which will +** serve as the underlying representation of a cursor that scans +** over rows of the result +*/ +typedef struct qpvtab_cursor qpvtab_cursor; +struct qpvtab_cursor { + sqlite3_vtab_cursor base; /* Base class - must be first */ + sqlite3_int64 iRowid; /* The rowid */ + const char *zData; /* Data to return */ + int nData; /* Number of bytes of data */ + int flags; /* Flags value */ +}; + +/* +** The qpvtabConnect() method is invoked to create a new +** qpvtab virtual table. +*/ +static int qpvtabConnect( + sqlite3 *db, + void *pAux, + int argc, const char *const*argv, + sqlite3_vtab **ppVtab, + char **pzErr +){ + qpvtab_vtab *pNew; + int rc; + + rc = sqlite3_declare_vtab(db, + "CREATE TABLE x(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t," + " flags HIDDEN)" + ); +#define QPVTAB_A 0 +#define QPVTAB_B 1 +#define QPVTAB_T 19 +#define QPVTAB_FLAGS 20 + if( rc==SQLITE_OK ){ + pNew = sqlite3_malloc( sizeof(*pNew) ); + *ppVtab = (sqlite3_vtab*)pNew; + if( pNew==0 ) return SQLITE_NOMEM; + memset(pNew, 0, sizeof(*pNew)); + } + return rc; +} + +/* +** This method is the destructor for qpvtab_vtab objects. +*/ +static int qpvtabDisconnect(sqlite3_vtab *pVtab){ + qpvtab_vtab *p = (qpvtab_vtab*)pVtab; + sqlite3_free(p); + return SQLITE_OK; +} + +/* +** Constructor for a new qpvtab_cursor object. +*/ +static int qpvtabOpen(sqlite3_vtab *p, sqlite3_vtab_cursor **ppCursor){ + qpvtab_cursor *pCur; + pCur = sqlite3_malloc( sizeof(*pCur) ); + if( pCur==0 ) return SQLITE_NOMEM; + memset(pCur, 0, sizeof(*pCur)); + *ppCursor = &pCur->base; + return SQLITE_OK; +} + +/* +** Destructor for a qpvtab_cursor. +*/ +static int qpvtabClose(sqlite3_vtab_cursor *cur){ + qpvtab_cursor *pCur = (qpvtab_cursor*)cur; + sqlite3_free(pCur); + return SQLITE_OK; +} + + +/* +** Advance a qpvtab_cursor to its next row of output. +*/ +static int qpvtabNext(sqlite3_vtab_cursor *cur){ + qpvtab_cursor *pCur = (qpvtab_cursor*)cur; + while( pCur->iRowidnData && pCur->zData[pCur->iRowid]!='\n' ){ + pCur->iRowid++; + } + if( pCur->zData[pCur->iRowid]=='\n' ) pCur->iRowid++; + return SQLITE_OK; +} + +/* +** Return values of columns for the row at which the qpvtab_cursor +** is currently pointing. +*/ +static int qpvtabColumn( + sqlite3_vtab_cursor *cur, /* The cursor */ + sqlite3_context *ctx, /* First argument to sqlite3_result_...() */ + int i /* Which column to return */ +){ + qpvtab_cursor *pCur = (qpvtab_cursor*)cur; + if( i==0 && pCur->iRowidnData ){ + int j; + for(j=pCur->iRowid; jnData && pCur->zData[j]!='\n'; j++){} + sqlite3_result_text64(ctx, &pCur->zData[pCur->iRowid], j-pCur->iRowid, + SQLITE_TRANSIENT, SQLITE_UTF8); + }else if( i>=QPVTAB_B && i<=QPVTAB_T ){ + if( pCur->flags & 1 ){ + sqlite3_result_int(ctx, i); + }else{ + char x = 'a'+i; + sqlite3_result_text64(ctx, &x, 1, SQLITE_TRANSIENT, SQLITE_UTF8); + } + }else if( i==QPVTAB_FLAGS ){ + sqlite3_result_int(ctx, pCur->flags); + } + return SQLITE_OK; +} + +/* +** Return the rowid for the current row. In this implementation, the +** rowid is the same as the output value. +*/ +static int qpvtabRowid(sqlite3_vtab_cursor *cur, sqlite_int64 *pRowid){ + qpvtab_cursor *pCur = (qpvtab_cursor*)cur; + *pRowid = pCur->iRowid; + return SQLITE_OK; +} + +/* +** Return TRUE if the cursor has been moved off of the last +** row of output. +*/ +static int qpvtabEof(sqlite3_vtab_cursor *cur){ + qpvtab_cursor *pCur = (qpvtab_cursor*)cur; + return pCur->iRowid>=pCur->nData; +} + +/* +** This method is called to "rewind" the qpvtab_cursor object back +** to the first row of output. This method is always called at least +** once prior to any call to qpvtabColumn() or qpvtabRowid() or +** qpvtabEof(). +*/ +static int qpvtabFilter( + sqlite3_vtab_cursor *pVtabCursor, + int idxNum, const char *idxStr, + int argc, sqlite3_value **argv +){ + qpvtab_cursor *pCur = (qpvtab_cursor *)pVtabCursor; + pCur->iRowid = 0; + pCur->zData = idxStr; + pCur->nData = (int)strlen(idxStr); + pCur->flags = idxNum; + return SQLITE_OK; +} + +/* +** Append the text of a value to pStr +*/ +static void qpvtabStrAppendValue( + sqlite3_str *pStr, + sqlite3_value *pVal +){ + switch( sqlite3_value_type(pVal) ){ + case SQLITE_NULL: + sqlite3_str_appendf(pStr, "NULL"); + break; + case SQLITE_INTEGER: + sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pVal)); + break; + case SQLITE_FLOAT: + sqlite3_str_appendf(pStr, "%f", sqlite3_value_double(pVal)); + break; + case SQLITE_TEXT: + sqlite3_str_appendf(pStr, "%Q", sqlite3_value_text(pVal)); + break; + case SQLITE_BLOB: { + int i; + const unsigned char *a = sqlite3_value_blob(pVal); + int n = sqlite3_value_bytes(pVal); + sqlite3_str_append(pStr, "x'", 2); + for(i=0; inConstraint); + for(i=0; inConstraint; i++){ + sqlite3_value *pVal; + int iCol = pIdxInfo->aConstraint[i].iColumn; + char zCol[8]; + if( iCol==QPVTAB_FLAGS ){ + strcpy(zCol, "flags"); + if( pIdxInfo->aConstraint[i].usable ){ + pVal = 0; + sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + if( pVal ){ + pIdxInfo->idxNum = sqlite3_value_int(pVal); + } + } + }else{ + zCol[0] = iCol+'a'; + zCol[1] = 0; + } + sqlite3_str_appendf(pStr,"aConstraint[%d]: iColumn=%s op=%d usable=%d", + i, + zCol, + pIdxInfo->aConstraint[i].op, + pIdxInfo->aConstraint[i].usable); + pVal = 0; + sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + if( pVal ){ + sqlite3_str_appendf(pStr, " value="); + qpvtabStrAppendValue(pStr, pVal); + } + sqlite3_str_append(pStr, "\n", 1); + if( pIdxInfo->aConstraint[i].usable ){ + pIdxInfo->aConstraintUsage[i].argvIndex = ++k; + pIdxInfo->aConstraintUsage[i].omit = 1; + } + } + pIdxInfo->estimatedCost = (double)10; + pIdxInfo->estimatedRows = 10; + sqlite3_str_appendf(pStr, "idxNum=%d\n", pIdxInfo->idxNum); + pIdxInfo->idxStr = sqlite3_str_finish(pStr); + pIdxInfo->needToFreeIdxStr = 1; + return SQLITE_OK; +} + +/* +** This following structure defines all the methods for the +** virtual table. +*/ +static sqlite3_module qpvtabModule = { + /* iVersion */ 0, + /* xCreate */ 0, + /* xConnect */ qpvtabConnect, + /* xBestIndex */ qpvtabBestIndex, + /* xDisconnect */ qpvtabDisconnect, + /* xDestroy */ 0, + /* xOpen */ qpvtabOpen, + /* xClose */ qpvtabClose, + /* xFilter */ qpvtabFilter, + /* xNext */ qpvtabNext, + /* xEof */ qpvtabEof, + /* xColumn */ qpvtabColumn, + /* xRowid */ qpvtabRowid, + /* xUpdate */ 0, + /* xBegin */ 0, + /* xSync */ 0, + /* xCommit */ 0, + /* xRollback */ 0, + /* xFindMethod */ 0, + /* xRename */ 0, + /* xSavepoint */ 0, + /* xRelease */ 0, + /* xRollbackTo */ 0, + /* xShadowName */ 0 +}; +#endif /* SQLITE_OMIT_VIRTUALTABLE */ + + +#ifdef _WIN32 +__declspec(dllexport) +#endif +int sqlite3_qpvtab_init( + sqlite3 *db, + char **pzErrMsg, + const sqlite3_api_routines *pApi +){ + int rc = SQLITE_OK; + SQLITE_EXTENSION_INIT2(pApi); +#ifndef SQLITE_OMIT_VIRTUALTABLE + rc = sqlite3_create_module(db, "qpvtab", &qpvtabModule, 0); +#endif + return rc; +} diff --git a/main.mk b/main.mk index e09505aee2..514776f64b 100644 --- a/main.mk +++ b/main.mk @@ -377,6 +377,7 @@ TESTSRC += \ $(TOP)/ext/misc/normalize.c \ $(TOP)/ext/misc/percentile.c \ $(TOP)/ext/misc/prefixes.c \ + $(TOP)/ext/misc/qpvtab.c \ $(TOP)/ext/misc/regexp.c \ $(TOP)/ext/misc/remember.c \ $(TOP)/ext/misc/series.c \ diff --git a/manifest b/manifest index 9cea17bdca..426d57cde5 100644 --- a/manifest +++ b/manifest @@ -1,11 +1,11 @@ -C A\sbetter\sand\smore\srobust\sfix\sfor\sthe\sproblem\sof\sreading\sa\sread-only\sWAL\nmode\sdatabase\swith\sexisting\s-wal\sand\s-shm\sfiles,\sreplacing\s[f426874e005e3c23]. -D 2022-01-20T14:40:34.203 +C Initial\simplementation\sof\sthe\ssqlite3_vtab_rhs_value()\sinterface\sand\sthe\nqpvtab\sextension\sused\sfor\stesting\sthe\svirtual\stable\sinterface. +D 2022-01-20T17:10:59.757 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 -F Makefile.in fd537743957bfe87997dc5727783d8eec82098921e15eab984d6711cd46f001b +F Makefile.in 3271f3cffa0fb1e214816bbffbdb8a367f8d3b8415eda5346839cf427a138c70 F Makefile.linux-gcc f609543700659711fbd230eced1f01353117621dccae7b9fb70daa64236c5241 -F Makefile.msc 22ce0007874c61c8eb51fc22b84f72af175ce2d7431c242253bdffa39c163da4 +F Makefile.msc eeb45109d245d1bc5d6ce78da818d62848307419f950b0de0a00ab0672b15081 F README.md 2dd87a5c1d108b224921f3dd47dea567973f706e1f6959386282a626f459a70c F VERSION 392c2f83569705069415a5d98b1c138ec8fe8a56a663a0d94cea019e806537b2 F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -316,6 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 +F ext/misc/qpvtab.c 0f6e3f4081f6ad0104d016bf6e21de8a7f5e3f14b984a2158940a1809741fd96 F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -472,7 +473,7 @@ F ext/userauth/userauth.c 7f00cded7dcaa5d47f54539b290a43d2e59f4b1eb5f447545fa865 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 32e8c752386520016933873a23a9c649f1a9cfd5c75c218614e622f0510b8f42 +F main.mk 3de4bca45fee4b843aaf74df8ffc639aa8ae3c52af997bbbd6927add30154fda F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -514,7 +515,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743 F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 95db1fe62c5973f1c5d9c53f6083e21a73ece14cdd47eeca0639691332e85c4d +F src/loadext.c 9a693eb89575af5d54b025c1e927b2ea8114bbeee3db346e8abc81676dd82160 F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960 F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 @@ -553,15 +554,15 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e -F src/sqlite.h.in a5e0d6bd47e67aabf1475986d36bdcc7bfa9e06566790ebf8e3aa7fa551c9f99 +F src/sqlite.h.in 9257b85dd160fda70e12727881e6c48be0f21ab0d149fa27446505fec5fa4fca F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h 01eb85e4f2759a5ee79c183f4b2877889d4ffdc49d27ae74529c9579e3c8c0ef +F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 F src/tclsqlite.c 48f291e1a7e672a7204884d4c164a8ed3a522ff087c361ada2991f5d54e987f6 -F src/test1.c f13fe747afc7d9af189ce0cdaaf641252c5803db2a32bd3525eec2905c7b4f37 +F src/test1.c 9287559cc1f7c5a25f927aa172e69778237f0e037960dbcdb4257d0bea500114 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 7c4420e01c577b5c4add2cb03119743b1a357543d347773b9e717195ea967159 @@ -638,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c eedf0311d59095bcd8523bd13bf25865e1caf1fab9beddbff9093340a1a409c7 +F src/where.c 9f8a9c1c18ab37bbb32ea82c322b09c72e237a89e9005b30089273c6efa5d406 F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6 F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 @@ -1938,8 +1939,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 ab160e8bae3a4fc2067d73fe33542f261652985390fe9b0390a4f9c33a1990bf -R 23c453292071b3de4a1e0dc51f1f1bde +P 71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 +R 2d7b697c8fff979e242ffc760548c840 +T *branch * sqlite3_vtab_rhs_value +T *sym-sqlite3_vtab_rhs_value * +T -sym-trunk * U drh -Z 048e904f267f4777d2809de2936b5439 +Z 906d4e9a8d8e3be5e145d8027611963e # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 9abd24dbef..87e9323d0e 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 \ No newline at end of file +0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5 \ No newline at end of file diff --git a/src/loadext.c b/src/loadext.c index 681e12c4e7..c917e11c8e 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -487,6 +487,7 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_autovacuum_pages, /* Version 3.38.0 and later */ sqlite3_error_offset, + sqlite3_vtab_rhs_value, }; /* True if x is the directory separator character diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 3aad3690a2..43a9c8eca7 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -9503,6 +9503,29 @@ int sqlite3_vtab_nochange(sqlite3_context*); */ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +/* +** CAPI3REF: Constraint values in xBestIndex() +** METHOD: sqlite3_index_info +** +** This API may only be used from within an xBestIndex() callback. The +** results of calling it from outside of an xBestIndex() callback are +** undefined and probably harmful. +** +** When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within +** the [xBestIndex] method of a [virtual table] implementation, with P being +** a copy of the sqlite3_index_info object pointer passed into xBestIndex and +** J being a 0-based index of one of the constraints, then this routine +** attempts to set *V to be the value on the right-hand side of +** that constraint if the right-hand side is a known constant. If the +** right-hand side of the constraint is not known, then *V is set to a NULL +** pointer. +** +** The sqlite3_value object returned in *V remains valid for the duration of +** the xBestIndex method code. When xBestIndex returns, the sqlite3_value +** object returned by sqlite3_vtab_rhs_value() is automatically deallocated. +*/ +int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); + /* ** CAPI3REF: Conflict resolution modes ** KEYWORDS: {conflict resolution mode} diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 5b82346227..580078b6d0 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -346,6 +346,7 @@ struct sqlite3_api_routines { void*, void(*)(void*)); /* Version 3.38.0 and later */ int (*error_offset)(sqlite3*); + int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); }; /* @@ -659,6 +660,7 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_autovacuum_pages sqlite3_api->autovacuum_pages /* Version 3.38.0 and later */ #define sqlite3_error_offset sqlite3_api->error_offset +#define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/test1.c b/src/test1.c index b7fdd2a4bf..b5787f0874 100644 --- a/src/test1.c +++ b/src/test1.c @@ -7568,6 +7568,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd( #ifndef SQLITE_OMIT_VIRTUALTABLE extern int sqlite3_prefixes_init(sqlite3*,char**,const sqlite3_api_routines*); #endif + extern int sqlite3_qpvtab_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_regexp_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_remember_init(sqlite3*,char**,const sqlite3_api_routines*); extern int sqlite3_series_init(sqlite3*,char**,const sqlite3_api_routines*); @@ -7598,6 +7599,7 @@ static int SQLITE_TCLAPI tclLoadStaticExtensionCmd( #ifndef SQLITE_OMIT_VIRTUALTABLE { "prefixes", sqlite3_prefixes_init }, #endif + { "qpvtab", sqlite3_qpvtab_init }, { "regexp", sqlite3_regexp_init }, { "remember", sqlite3_remember_init }, { "series", sqlite3_series_init }, diff --git a/src/where.c b/src/where.c index 35bad3f696..4084fd80c8 100644 --- a/src/where.c +++ b/src/where.c @@ -30,8 +30,11 @@ */ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { - WhereClause *pWC; /* The Where clause being analyzed */ - Parse *pParse; /* The parsing context */ + WhereClause *pWC; /* The Where clause being analyzed */ + Parse *pParse; /* The parsing context */ + sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST + ** because extra space is allocated to hold up + ** to nTerm such values */ }; /* Forward declaration of methods */ @@ -1095,7 +1098,7 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( /* ** Allocate and populate an sqlite3_index_info structure. It is the ** responsibility of the caller to eventually release the structure -** by passing the pointer returned by this function to sqlite3_free(). +** by passing the pointer returned by this function to freeIndexInfo(). */ static sqlite3_index_info *allocateIndexInfo( Parse *pParse, /* The parsing context */ @@ -1207,13 +1210,14 @@ static sqlite3_index_info *allocateIndexInfo( */ pIdxInfo = sqlite3DbMallocZero(pParse->db, sizeof(*pIdxInfo) + (sizeof(*pIdxCons) + sizeof(*pUsage))*nTerm - + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) ); + + sizeof(*pIdxOrderBy)*nOrderBy + sizeof(*pHidden) + + sizeof(sqlite3_value*)*nTerm ); if( pIdxInfo==0 ){ sqlite3ErrorMsg(pParse, "out of memory"); return 0; } pHidden = (struct HiddenIndexInfo*)&pIdxInfo[1]; - pIdxCons = (struct sqlite3_index_constraint*)&pHidden[1]; + pIdxCons = (struct sqlite3_index_constraint*)&pHidden->aRhs[nTerm]; pIdxOrderBy = (struct sqlite3_index_orderby*)&pIdxCons[nTerm]; pUsage = (struct sqlite3_index_constraint_usage*)&pIdxOrderBy[nOrderBy]; pIdxInfo->aConstraint = pIdxCons; @@ -1278,6 +1282,24 @@ static sqlite3_index_info *allocateIndexInfo( return pIdxInfo; } +/* +** Free an sqlite3_index_info structure allocated by allocateIndexInfo() +** and possibly modified by xBestIndex methods. +*/ +static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden; + int i; + assert( pIdxInfo!=0 ); + pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + assert( pHidden->pParse!=0 ); + assert( pHidden->pParse->db==db ); + for(i=0; inConstraint; i++){ + sqlite3ValueFree(pHidden->aRhs[i]); + pHidden->aRhs[i] = 0; + } + sqlite3DbFree(db, pIdxInfo); +} + /* ** The table object reference passed as the second argument to this function ** must represent a virtual table. This function invokes the xBestIndex() @@ -3633,6 +3655,36 @@ const char *sqlite3_vtab_collation(sqlite3_index_info *pIdxInfo, int iCons){ return zRet; } +/* +** This interface is callable from within the xBestIndex callback only. +** +** If possible, set (*ppVal) to point to an object containing the value +** on the right-hand-side of constraint iCons. +*/ +int sqlite3_vtab_rhs_value( + sqlite3_index_info *pIdxInfo, /* Copy of first argument to xBestIndex */ + int iCons, /* Constraint for which RHS is wanted */ + sqlite3_value **ppVal /* Write value extracted here */ +){ + HiddenIndexInfo *pH = (HiddenIndexInfo*)&pIdxInfo[1]; + sqlite3_value *pVal = 0; + int rc = SQLITE_OK; + if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ + rc = SQLITE_MISUSE; + }else{ + if( pH->aRhs[iCons]==0 ){ + WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; + rc = sqlite3ValueFromExpr( + pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db), + SQLITE_AFF_BLOB, &pH->aRhs[iCons] + ); + } + pVal = pH->aRhs[iCons]; + } + *ppVal = pVal; + return rc; +} + /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. @@ -3691,7 +3743,7 @@ static int whereLoopAddVirtual( pNew->u.vtab.needFree = 0; nConstraint = p->nConstraint; if( whereLoopResize(pParse->db, pNew, nConstraint) ){ - sqlite3DbFree(pParse->db, p); + freeIndexInfo(pParse->db, p); return SQLITE_NOMEM_BKPT; } @@ -3771,7 +3823,7 @@ static int whereLoopAddVirtual( } if( p->needToFreeIdxStr ) sqlite3_free(p->idxStr); - sqlite3DbFreeNN(pParse->db, p); + freeIndexInfo(pParse->db, p); WHERETRACE(0x800, ("END %s.addVirtual(), rc=%d\n", pSrc->pTab->zName, rc)); return rc; } From fdb6f44fac700d81cf3b9a7f0c6a4a1c89ee78ee Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 20 Jan 2022 18:27:54 +0000 Subject: [PATCH 08/28] Enhancements to the qpvtab virtual table to make it more useful for testing and verification of virtual table interfaces. FossilOrigin-Name: 850efc4cf3d136fba9173c380e9417b43bb93c050f7eeb85d07fd39a4b1cc6aa --- ext/misc/qpvtab.c | 185 ++++++++++++++++++++++++++++++++++------------ manifest | 15 ++-- manifest.uuid | 2 +- 3 files changed, 146 insertions(+), 56 deletions(-) diff --git a/ext/misc/qpvtab.c b/ext/misc/qpvtab.c index fb22b61d68..fe79b966bd 100644 --- a/ext/misc/qpvtab.c +++ b/ext/misc/qpvtab.c @@ -16,18 +16,50 @@ ** ** The schema of the virtual table is this: ** -** CREATE TABLE qpvtab(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t); +** CREATE TABLE qpvtab( +** vn TEXT, -- Name of an sqlite3_index_info field +** ix INTEGER, -- Array index or value +** cn TEXT, -- Column name +** op INTEGER, -- operator +** ux BOOLEAN, -- "usable" field +** rhs TEXT, -- sqlite3_vtab_rhs_value() ** -** There is also a HIDDEN column "flags". +** a, b, c, d, e, -- Extra columns to attach constraints to ** -** All columns except column "a" have a value that is either TEXT that -** is there name, or INTEGER which is their index (b==1). TEXT is the -** default, but INTEGER is used of there is a constraint on flags where the -** right-hand side is an integer that includes the 1 bit. +** flags INTEGER HIDDEN -- control flags +** ); ** -** The "a" column returns text that describes one of the parameters that -** xBestIndex was called with. A completely query of the table should -** show all details of how xBestIndex was called. +** The virtual table returns a description of the sqlite3_index_info object +** that was provided to the (successful) xBestIndex method. There is one +** row in the result table for each field in the sqlite3_index_info object. +** +** The values of the "a" through "e" columns are one of: +** +** 1. TEXT - the same as the column name +** 2. INTEGER - 1 for "a", 2 for "b", and so forth +** +** Option 1 is the default behavior. 2 is use if there is a usable +** constraint on "flags" with an integer right-hand side that where the +** value of the right-hand side has its 0x01 bit set. +** +** All constraints on columns "a" through "e" are marked as "omit". +** +** If there is a usable constraint on "flags" that has a RHS value that +** is an integer and that integer has its 0x02 bit set, then the +** orderByConsumed flag is set. +** +** COMPILE: +** +** gcc -Wall -g -shared -fPIC -I. qpvtab.c -o qqvtab.so +** +** EXAMPLE USAGE: +** +** .load ./qpvtab +** SELECT rowid, *, flags FROM qpvtab(102) +** WHERE a=19 +** AND b BETWEEN 4.5 and 'hello' +** AND c<>x'aabbcc' +** ORDER BY d, e DESC; */ #if !defined(SQLITEINT_H) #include "sqlite3ext.h" @@ -35,6 +67,7 @@ SQLITE_EXTENSION_INIT1 #include #include +#include #if !defined(SQLITE_OMIT_VIRTUALTABLE) @@ -59,6 +92,20 @@ struct qpvtab_cursor { int flags; /* Flags value */ }; +/* +** Names of columns +*/ +static const char *azColname[] = { + "vn", + "ix", + "cn", + "op", + "ux", + "rhs", + "a", "b", "c", "d", "e", + "flags" +}; + /* ** The qpvtabConnect() method is invoked to create a new ** qpvtab virtual table. @@ -74,13 +121,28 @@ static int qpvtabConnect( int rc; rc = sqlite3_declare_vtab(db, - "CREATE TABLE x(a,b,c,d,e, f,g,h,i,j, k,l,m,n,o, p,q,r,s,t," - " flags HIDDEN)" + "CREATE TABLE x(" + " vn TEXT," + " ix INT," + " cn TEXT," + " op INT," + " ux BOOLEAN," + " rhs TEXT," + " a, b, c, d, e," + " flags INT HIDDEN)" ); -#define QPVTAB_A 0 -#define QPVTAB_B 1 -#define QPVTAB_T 19 -#define QPVTAB_FLAGS 20 +#define QPVTAB_VN 0 +#define QPVTAB_IX 1 +#define QPVTAB_CN 2 +#define QPVTAB_OP 3 +#define QPVTAB_UX 4 +#define QPVTAB_RHS 5 +#define QPVTAB_A 6 +#define QPVTAB_B 7 +#define QPVTAB_C 8 +#define QPVTAB_D 9 +#define QPVTAB_E 10 +#define QPVTAB_FLAGS 11 if( rc==SQLITE_OK ){ pNew = sqlite3_malloc( sizeof(*pNew) ); *ppVtab = (sqlite3_vtab*)pNew; @@ -126,10 +188,12 @@ static int qpvtabClose(sqlite3_vtab_cursor *cur){ */ static int qpvtabNext(sqlite3_vtab_cursor *cur){ qpvtab_cursor *pCur = (qpvtab_cursor*)cur; - while( pCur->iRowidnData && pCur->zData[pCur->iRowid]!='\n' ){ - pCur->iRowid++; + if( pCur->iRowidnData ){ + const char *z = &pCur->zData[pCur->iRowid]; + const char *zEnd = strchr(z, '\n'); + if( zEnd ) zEnd++; + pCur->iRowid = (int)(zEnd - pCur->zData); } - if( pCur->zData[pCur->iRowid]=='\n' ) pCur->iRowid++; return SQLITE_OK; } @@ -143,16 +207,29 @@ static int qpvtabColumn( int i /* Which column to return */ ){ qpvtab_cursor *pCur = (qpvtab_cursor*)cur; - if( i==0 && pCur->iRowidnData ){ + if( i>=QPVTAB_VN && i<=QPVTAB_RHS && pCur->iRowidnData ){ + const char *z = &pCur->zData[pCur->iRowid]; + const char *zEnd; int j; - for(j=pCur->iRowid; jnData && pCur->zData[j]!='\n'; j++){} - sqlite3_result_text64(ctx, &pCur->zData[pCur->iRowid], j-pCur->iRowid, - SQLITE_TRANSIENT, SQLITE_UTF8); - }else if( i>=QPVTAB_B && i<=QPVTAB_T ){ - if( pCur->flags & 1 ){ - sqlite3_result_int(ctx, i); + j = QPVTAB_VN; + while(1){ + zEnd = strchr(z, j==QPVTAB_RHS ? '\n' : ','); + if( j==i || zEnd==0 ) break; + z = zEnd+1; + j++; + } + if( zEnd==z ){ + sqlite3_result_null(ctx); + }else if( i==QPVTAB_IX || i==QPVTAB_OP || i==QPVTAB_UX ){ + sqlite3_result_int(ctx, atoi(z)); }else{ - char x = 'a'+i; + sqlite3_result_text64(ctx, z, zEnd-z, SQLITE_TRANSIENT, SQLITE_UTF8); + } + }else if( i>=QPVTAB_A && i<=QPVTAB_E ){ + if( pCur->flags & 1 ){ + sqlite3_result_int(ctx, i-QPVTAB_A+1); + }else{ + char x = 'a'+i-QPVTAB_A; sqlite3_result_text64(ctx, &x, 1, SQLITE_TRANSIENT, SQLITE_UTF8); } }else if( i==QPVTAB_FLAGS ){ @@ -216,9 +293,20 @@ static void qpvtabStrAppendValue( case SQLITE_FLOAT: sqlite3_str_appendf(pStr, "%f", sqlite3_value_double(pVal)); break; - case SQLITE_TEXT: - sqlite3_str_appendf(pStr, "%Q", sqlite3_value_text(pVal)); + case SQLITE_TEXT: { + int i; + const char *a = (const char*)sqlite3_value_text(pVal); + int n = sqlite3_value_bytes(pVal); + sqlite3_str_append(pStr, "'", 1); + for(i=0; inConstraint); + sqlite3_str_appendf(pStr, "nConstraint,%d,,,,\n", pIdxInfo->nConstraint); for(i=0; inConstraint; i++){ sqlite3_value *pVal; int iCol = pIdxInfo->aConstraint[i].iColumn; - char zCol[8]; - if( iCol==QPVTAB_FLAGS ){ - strcpy(zCol, "flags"); - if( pIdxInfo->aConstraint[i].usable ){ - pVal = 0; - sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); - if( pVal ){ - pIdxInfo->idxNum = sqlite3_value_int(pVal); - } + if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){ + pVal = 0; + sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + if( pVal ){ + pIdxInfo->idxNum = sqlite3_value_int(pVal); + if( pIdxInfo->idxNum & 2 ) pIdxInfo->orderByConsumed = 1; } - }else{ - zCol[0] = iCol+'a'; - zCol[1] = 0; } - sqlite3_str_appendf(pStr,"aConstraint[%d]: iColumn=%s op=%d usable=%d", + sqlite3_str_appendf(pStr,"aConstraint,%d,%s,%d,%d,", i, - zCol, + azColname[iCol], pIdxInfo->aConstraint[i].op, pIdxInfo->aConstraint[i].usable); pVal = 0; sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); if( pVal ){ - sqlite3_str_appendf(pStr, " value="); qpvtabStrAppendValue(pStr, pVal); } sqlite3_str_append(pStr, "\n", 1); - if( pIdxInfo->aConstraint[i].usable ){ + if( iCol>=QPVTAB_A && pIdxInfo->aConstraint[i].usable ){ pIdxInfo->aConstraintUsage[i].argvIndex = ++k; pIdxInfo->aConstraintUsage[i].omit = 1; } } + sqlite3_str_appendf(pStr, "nOrderBy,%d,,,,\n", pIdxInfo->nOrderBy); + for(i=0; inOrderBy; i++){ + int iCol = pIdxInfo->aOrderBy[i].iColumn; + sqlite3_str_appendf(pStr, "aOrderBy,%d,%s,%d,,\n",i, + iCol>=0 ? azColname[iCol] : "rowid", + pIdxInfo->aOrderBy[i].desc + ); + } + sqlite3_str_appendf(pStr, "idxFlags,%d,,,,\n", pIdxInfo->idxFlags); + sqlite3_str_appendf(pStr, "colUsed,%d,,,,\n", (int)pIdxInfo->colUsed); pIdxInfo->estimatedCost = (double)10; pIdxInfo->estimatedRows = 10; - sqlite3_str_appendf(pStr, "idxNum=%d\n", pIdxInfo->idxNum); + sqlite3_str_appendf(pStr, "idxNum,%d,,,,\n", pIdxInfo->idxNum); + sqlite3_str_appendf(pStr, "orderByConsumed,%d,,,,\n", + pIdxInfo->orderByConsumed); pIdxInfo->idxStr = sqlite3_str_finish(pStr); pIdxInfo->needToFreeIdxStr = 1; return SQLITE_OK; diff --git a/manifest b/manifest index 426d57cde5..9fcc7fcf6d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Initial\simplementation\sof\sthe\ssqlite3_vtab_rhs_value()\sinterface\sand\sthe\nqpvtab\sextension\sused\sfor\stesting\sthe\svirtual\stable\sinterface. -D 2022-01-20T17:10:59.757 +C Enhancements\sto\sthe\sqpvtab\svirtual\stable\sto\smake\sit\smore\suseful\sfor\stesting\nand\sverification\sof\svirtual\stable\sinterfaces. +D 2022-01-20T18:27:54.219 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 -F ext/misc/qpvtab.c 0f6e3f4081f6ad0104d016bf6e21de8a7f5e3f14b984a2158940a1809741fd96 +F ext/misc/qpvtab.c 38f0753b264cb206574c720eb8a118b0d6b7be077aaefd3229711de7d6a65dee F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -1939,11 +1939,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 -R 2d7b697c8fff979e242ffc760548c840 -T *branch * sqlite3_vtab_rhs_value -T *sym-sqlite3_vtab_rhs_value * -T -sym-trunk * +P 0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5 +R d96d8f6f20ceef7302e199b2da925b92 U drh -Z 906d4e9a8d8e3be5e145d8027611963e +Z 918c35408c3bb1880315f1de3ce596eb # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 87e9323d0e..2bc9990cb8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5 \ No newline at end of file +850efc4cf3d136fba9173c380e9417b43bb93c050f7eeb85d07fd39a4b1cc6aa \ No newline at end of file From bd3a247c734509b212364e06d000abd0a1fc87a9 Mon Sep 17 00:00:00 2001 From: drh <> Date: Thu, 20 Jan 2022 19:00:48 +0000 Subject: [PATCH 09/28] Test cases for sqlite3_vtab_rhs_value() based on the qpvtab extension. FossilOrigin-Name: 577d3d66558368c34acab8a9e552957cf3fa054c348f1383a9121de6e8b281b7 --- ext/misc/qpvtab.c | 2 +- manifest | 13 ++++++------ manifest.uuid | 2 +- test/vtabrhs1.test | 51 ++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 60 insertions(+), 8 deletions(-) create mode 100644 test/vtabrhs1.test diff --git a/ext/misc/qpvtab.c b/ext/misc/qpvtab.c index fe79b966bd..e3c689a266 100644 --- a/ext/misc/qpvtab.c +++ b/ext/misc/qpvtab.c @@ -291,7 +291,7 @@ static void qpvtabStrAppendValue( sqlite3_str_appendf(pStr, "%lld", sqlite3_value_int64(pVal)); break; case SQLITE_FLOAT: - sqlite3_str_appendf(pStr, "%f", sqlite3_value_double(pVal)); + sqlite3_str_appendf(pStr, "%!f", sqlite3_value_double(pVal)); break; case SQLITE_TEXT: { int i; diff --git a/manifest b/manifest index 9fcc7fcf6d..1e5b4c15bb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enhancements\sto\sthe\sqpvtab\svirtual\stable\sto\smake\sit\smore\suseful\sfor\stesting\nand\sverification\sof\svirtual\stable\sinterfaces. -D 2022-01-20T18:27:54.219 +C Test\scases\sfor\ssqlite3_vtab_rhs_value()\sbased\son\sthe\sqpvtab\sextension. +D 2022-01-20T19:00:48.033 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 -F ext/misc/qpvtab.c 38f0753b264cb206574c720eb8a118b0d6b7be077aaefd3229711de7d6a65dee +F ext/misc/qpvtab.c 69667dfc5c0417c1d2352e2cf0f3abdfd65919a423a07083952e27f3a30bf717 F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -1725,6 +1725,7 @@ F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c37 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12 +F test/vtabrhs1.test 5205e3f662c35f75101520f882bf7d6abe0f5126f05b775ad2cbb13c9da1172f F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089 F test/wal2.test 31f6e2c404b9f2cdf9ca19b105a1742fdc19653c2c936da39e3658c617524046 F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2 @@ -1939,8 +1940,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 0873c76b9b96b66fa9d13ddc8bca126d575ea3352349c7fd648f0c2f75d770f5 -R d96d8f6f20ceef7302e199b2da925b92 +P 850efc4cf3d136fba9173c380e9417b43bb93c050f7eeb85d07fd39a4b1cc6aa +R 3ecb930f6cfc60c294bf42c3052a9c99 U drh -Z 918c35408c3bb1880315f1de3ce596eb +Z e518270449fd92d31e3cdea40bbeb849 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 2bc9990cb8..d5299e28c2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -850efc4cf3d136fba9173c380e9417b43bb93c050f7eeb85d07fd39a4b1cc6aa \ No newline at end of file +577d3d66558368c34acab8a9e552957cf3fa054c348f1383a9121de6e8b281b7 \ No newline at end of file diff --git a/test/vtabrhs1.test b/test/vtabrhs1.test new file mode 100644 index 0000000000..86086cfcc4 --- /dev/null +++ b/test/vtabrhs1.test @@ -0,0 +1,51 @@ +# 2022-01-20 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for sqlite3_vtab_rhs_value() interface. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix vtabrhs1 + +ifcapable !vtab { + finish_test + return +} +load_static_extension db qpvtab + +do_execsql_test 1.1 { + SELECT rhs FROM qpvtab + WHERE cn='a' + AND a=12345 +} {12345} +do_execsql_test 1.2 { + SELECT rhs FROM qpvtab + WHERE cn='a' + AND a<>4.5 +} {4.5} +do_execsql_test 1.3 { + SELECT rhs FROM qpvtab + WHERE cn='a' + AND 'quokka' < a +} {'quokka'} +do_execsql_test 1.4 { + SELECT rhs FROM qpvtab + WHERE cn='a' + AND a IS NULL +} {{}} +do_execsql_test 1.5 { + SELECT rhs FROM qpvtab + WHERE cn='a' + AND a GLOB x'0123' +} {x'0123'} + +finish_test From 991d1085e3de3d377195c3c899b48188f465a217 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 21 Jan 2022 00:38:49 +0000 Subject: [PATCH 10/28] Add requirements marks and tuning. FossilOrigin-Name: ac951490fd7d5864fe422a80ee8557478e823e79461bec2ee538f57b6733eb5a --- ext/misc/qpvtab.c | 7 +++++-- manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/sqlite.h.in | 17 +++++++++++------ src/where.c | 10 ++++++++-- test/vtabrhs1.test | 25 +++++++++++++++++++++++++ 6 files changed, 59 insertions(+), 20 deletions(-) diff --git a/ext/misc/qpvtab.c b/ext/misc/qpvtab.c index e3c689a266..6c145ffd17 100644 --- a/ext/misc/qpvtab.c +++ b/ext/misc/qpvtab.c @@ -333,13 +333,15 @@ static int qpvtabBestIndex( ){ sqlite3_str *pStr = sqlite3_str_new(0); int i, k = 0; + int rc; sqlite3_str_appendf(pStr, "nConstraint,%d,,,,\n", pIdxInfo->nConstraint); for(i=0; inConstraint; i++){ sqlite3_value *pVal; int iCol = pIdxInfo->aConstraint[i].iColumn; if( iCol==QPVTAB_FLAGS && pIdxInfo->aConstraint[i].usable ){ pVal = 0; - sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + assert( rc==SQLITE_OK || pVal==0 ); if( pVal ){ pIdxInfo->idxNum = sqlite3_value_int(pVal); if( pIdxInfo->idxNum & 2 ) pIdxInfo->orderByConsumed = 1; @@ -351,7 +353,8 @@ static int qpvtabBestIndex( pIdxInfo->aConstraint[i].op, pIdxInfo->aConstraint[i].usable); pVal = 0; - sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + rc = sqlite3_vtab_rhs_value(pIdxInfo, i, &pVal); + assert( rc==SQLITE_OK || pVal==0 ); if( pVal ){ qpvtabStrAppendValue(pStr, pVal); } diff --git a/manifest b/manifest index 1e5b4c15bb..ec69532efb 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scases\sfor\ssqlite3_vtab_rhs_value()\sbased\son\sthe\sqpvtab\sextension. -D 2022-01-20T19:00:48.033 +C Add\srequirements\smarks\sand\stuning. +D 2022-01-21T00:38:49.617 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 -F ext/misc/qpvtab.c 69667dfc5c0417c1d2352e2cf0f3abdfd65919a423a07083952e27f3a30bf717 +F ext/misc/qpvtab.c d40b07a8c341d16629010c3e8d8801f1477f70d6257e052973a8ddf14c07cd8d F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -554,7 +554,7 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e -F src/sqlite.h.in 9257b85dd160fda70e12727881e6c48be0f21ab0d149fa27446505fec5fa4fca +F src/sqlite.h.in 67e49a50bb29e3af86d2b3606af6b3fe20a0d09cf326cc574d632d878c0696d6 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 9f8a9c1c18ab37bbb32ea82c322b09c72e237a89e9005b30089273c6efa5d406 +F src/where.c 6b4cd84869dafc250d2b0f47a2c190759904a4bb6a31fc930bc8e6a9fd9a8d77 F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6 F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 @@ -1725,7 +1725,7 @@ F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c37 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12 -F test/vtabrhs1.test 5205e3f662c35f75101520f882bf7d6abe0f5126f05b775ad2cbb13c9da1172f +F test/vtabrhs1.test c138346be341916ecc9d918dcfc2657d27bce211a350a82b01d62d224b167b56 F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089 F test/wal2.test 31f6e2c404b9f2cdf9ca19b105a1742fdc19653c2c936da39e3658c617524046 F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2 @@ -1940,8 +1940,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 850efc4cf3d136fba9173c380e9417b43bb93c050f7eeb85d07fd39a4b1cc6aa -R 3ecb930f6cfc60c294bf42c3052a9c99 +P 577d3d66558368c34acab8a9e552957cf3fa054c348f1383a9121de6e8b281b7 +R 90012b52ae4dda5b0e0f59cd4c524b70 U drh -Z e518270449fd92d31e3cdea40bbeb849 +Z 0ca7e1064e9e25edf7c6ed09bdf60dba # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index d5299e28c2..01f69afd18 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -577d3d66558368c34acab8a9e552957cf3fa054c348f1383a9121de6e8b281b7 \ No newline at end of file +ac951490fd7d5864fe422a80ee8557478e823e79461bec2ee538f57b6733eb5a \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 43a9c8eca7..ca27742cb1 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -9511,17 +9511,22 @@ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** results of calling it from outside of an xBestIndex() callback are ** undefined and probably harmful. ** -** When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within +** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within ** the [xBestIndex] method of a [virtual table] implementation, with P being ** a copy of the sqlite3_index_info object pointer passed into xBestIndex and -** J being a 0-based index of one of the constraints, then this routine +** J being a 0-based index into P->aConstraint[], then this routine ** attempts to set *V to be the value on the right-hand side of -** that constraint if the right-hand side is a known constant. If the +** that constraint if the right-hand side is a known constant. ^If the ** right-hand side of the constraint is not known, then *V is set to a NULL -** pointer. +** pointer. ^The sqlite3_vtab_rhs_value(P,J,V) interface returns SQLITE_OK if +** and only if *V is set to a value. ^The sqlite3_vtab_rhs_value(P,J,V) +** inteface returns SQLITE_NOTFOUND if the right-hand side of the J-th +** constraint is not available. ^The sqlite3_vtab_rhs_value() interface +** can return an result code other than SQLITE_OK or SQLITE_NOTFOUND if +** something goes wrong. ** -** The sqlite3_value object returned in *V remains valid for the duration of -** the xBestIndex method code. When xBestIndex returns, the sqlite3_value +** ^The sqlite3_value object returned in *V remains valid for the duration of +** the xBestIndex method code. ^When xBestIndex returns, the sqlite3_value ** object returned by sqlite3_vtab_rhs_value() is automatically deallocated. */ int sqlite3_vtab_rhs_value(sqlite3_index_info*, int, sqlite3_value **ppVal); diff --git a/src/where.c b/src/where.c index 4084fd80c8..bf6cf49e03 100644 --- a/src/where.c +++ b/src/where.c @@ -1294,7 +1294,7 @@ static void freeIndexInfo(sqlite3 *db, sqlite3_index_info *pIdxInfo){ assert( pHidden->pParse!=0 ); assert( pHidden->pParse->db==db ); for(i=0; inConstraint; i++){ - sqlite3ValueFree(pHidden->aRhs[i]); + sqlite3ValueFree(pHidden->aRhs[i]); /* IMP: R-14553-25174 */ pHidden->aRhs[i] = 0; } sqlite3DbFree(db, pIdxInfo); @@ -3670,7 +3670,7 @@ int sqlite3_vtab_rhs_value( sqlite3_value *pVal = 0; int rc = SQLITE_OK; if( iCons<0 || iCons>=pIdxInfo->nConstraint ){ - rc = SQLITE_MISUSE; + rc = SQLITE_MISUSE; /* EV: R-30545-25046 */ }else{ if( pH->aRhs[iCons]==0 ){ WhereTerm *pTerm = &pH->pWC->a[pIdxInfo->aConstraint[iCons].iTermOffset]; @@ -3678,10 +3678,16 @@ int sqlite3_vtab_rhs_value( pH->pParse->db, pTerm->pExpr->pRight, ENC(pH->pParse->db), SQLITE_AFF_BLOB, &pH->aRhs[iCons] ); + testcase( rc!=SQLITE_OK ); } pVal = pH->aRhs[iCons]; } *ppVal = pVal; + + if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-60459-24801 */ + rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */ + } + return rc; } diff --git a/test/vtabrhs1.test b/test/vtabrhs1.test index 86086cfcc4..48fb6f1f6f 100644 --- a/test/vtabrhs1.test +++ b/test/vtabrhs1.test @@ -22,6 +22,14 @@ ifcapable !vtab { } load_static_extension db qpvtab +# EVIDENCE-OF: R-12211-29175 When the sqlite3_vtab_rhs_value(P,J,V) +# interface is invoked from within the xBestIndex method of a virtual +# table implementation, with P being a copy of the sqlite3_index_info +# object pointer passed into xBestIndex and J being a 0-based index into +# P->aConstraint[], then this routine attempts to set *V to be the +# value on the right-hand side of that constraint if the right-hand side +# is a known constant. +# do_execsql_test 1.1 { SELECT rhs FROM qpvtab WHERE cn='a' @@ -48,4 +56,21 @@ do_execsql_test 1.5 { AND a GLOB x'0123' } {x'0123'} +# EVIDENCE-OF: R-29440-53190 If the right-hand side of the constraint is +# not known, then *V is set to a NULL pointer. +# +do_execsql_test 2.1 { + SELECT typeof(rhs) FROM qpvtab WHERE cn='a' AND a=format('abc'); +} {null} +do_execsql_test 2.2 { + SELECT typeof(rhs) FROM qpvtab WHERE cn='a' AND a=?2 +} {null} + +# EVIDENCE-OF: R-14553-25174 When xBestIndex returns, the sqlite3_value +# object returned by sqlite3_vtab_rhs_value() is automatically +# deallocated. +# +# Where this not the case, the following "finish_test" statement would +# report a memory leak. +# finish_test From e482fde6ee3c07bab5370eda20df6e0ab6cee4ea Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 21 Jan 2022 16:41:11 +0000 Subject: [PATCH 11/28] When computing a vector to be used as a key for an index lookup, do not check for NULL values and abort until after all key values have been computed, in case one of the later key values involves some initialization that is needed by a LEFT JOIN. Fix for the problem identified by [forum:/forumpost/ab95010d410a0a55|Forum post ab95010d410a0a55]. FossilOrigin-Name: 4db5217a28ce767fa14ddfe51cf3ca25eceb72079d46a2fc00f7d6b8ae9abe0b --- manifest | 15 +++++++-------- manifest.uuid | 2 +- src/wherecode.c | 3 +++ test/rowvalue.test | 15 +++++++++++++++ 4 files changed, 26 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 0cfb4d2094..c4f2b80e50 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3_vtab_rhs_value()\sinterface,\sallowing\sthe\sxBestIndex\smethod\nof\sa\svirtual\stable\sto\saccess\sknown\svalues\son\sthe\sright-hand\sside\sof\nconstraint\sexpressions. -D 2022-01-21T01:00:53.326 +C When\scomputing\sa\svector\sto\sbe\sused\sas\sa\skey\sfor\san\sindex\slookup,\sdo\snot\ncheck\sfor\sNULL\svalues\sand\sabort\suntil\safter\sall\skey\svalues\shave\sbeen\ncomputed,\sin\scase\sone\sof\sthe\slater\skey\svalues\sinvolves\ssome\sinitialization\nthat\sis\sneeded\sby\sa\sLEFT\sJOIN.\s\sFix\sfor\sthe\sproblem\sidentified\sby\n[forum:/forumpost/ab95010d410a0a55|Forum\spost\sab95010d410a0a55]. +D 2022-01-21T16:41:11.844 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -641,7 +641,7 @@ F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b F src/where.c 6b4cd84869dafc250d2b0f47a2c190759904a4bb6a31fc930bc8e6a9fd9a8d77 F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be -F src/wherecode.c 6a594ed25bfbeb60d455868b7be62637575e4f1949152de4336e4825e0c54ba6 +F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1322,7 +1322,7 @@ F test/round1.test 768018b04522ca420b1aba8a24bd76091d269f3bce3902af3ec6ebcee41ab F test/rowallock.test 3f88ec6819489d0b2341c7a7528ae17c053ab7cc F test/rowhash.test 0bc1d31415e4575d10cacf31e1a66b5cc0f8be81 F test/rowid.test e29025be95baf6b32f0d5edef59a7633028325896a98f1caa8019559ca910350 -F test/rowvalue.test 37effea4dd83555ea969a9461dfcffb25e6731a5db7c388e232410999c100853 +F test/rowvalue.test 02214016f747854ef636e64ff204778649937aa801ca78e2495a960f8e0d509d F test/rowvalue2.test 060d238b7e5639a7c5630cb5e63e311b44efef2b F test/rowvalue3.test 3068f508753af69884b12125995f023da0dbb256 F test/rowvalue4.test 441e7e366ac6d939a3a95a574031c56ec2a854077a91d66eee5ff1d86cb5be58 @@ -1940,9 +1940,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 71bfd0b57ab197405606b8096b8521d784ff174c4eecf1d9804d38342c03cc80 ac951490fd7d5864fe422a80ee8557478e823e79461bec2ee538f57b6733eb5a -R 90012b52ae4dda5b0e0f59cd4c524b70 -T +closed ac951490fd7d5864fe422a80ee8557478e823e79461bec2ee538f57b6733eb5a +P e19a0b132a641f0e9f3d72586af538b95b4db8665b1555f84bc0a291bf1a4056 +R 3ccffcbe5ebff55f0ce3325fb7a3c810 U drh -Z 34e99bffd10cf2786088d1ed018f667b +Z c6c4905bc0565a74c6f262fe9b11d1a3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 569daa5f5f..5af5151c6c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e19a0b132a641f0e9f3d72586af538b95b4db8665b1555f84bc0a291bf1a4056 \ No newline at end of file +4db5217a28ce767fa14ddfe51cf3ca25eceb72079d46a2fc00f7d6b8ae9abe0b \ No newline at end of file diff --git a/src/wherecode.c b/src/wherecode.c index a08ff84d28..77ee738f0c 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -824,6 +824,9 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_Copy, r1, regBase+j); } } + } + for(j=nSkip; jaLTerm[j]; if( pTerm->eOperator & WO_IN ){ if( pTerm->pExpr->flags & EP_xIsSelect ){ /* No affinity ever needs to be (or should be) applied to a value diff --git a/test/rowvalue.test b/test/rowvalue.test index c92d344821..7c101d9b3e 100644 --- a/test/rowvalue.test +++ b/test/rowvalue.test @@ -692,6 +692,21 @@ do_execsql_test 30.3 { UPDATE t2 SET (d,d,a)=(SELECT EXISTS(SELECT 1 IN(SELECT max( 1 IN(SELECT x ORDER BY 1)) OVER(PARTITION BY sum((SELECT y FROM t1 UNION SELECT x ORDER BY 1)))INTERSECT SELECT EXISTS(SELECT 1 FROM t1 UNION SELECT x ORDER BY 1) ORDER BY 1) ORDERa)|9 AS blob, 2, 3) FROM t1 WHERE x Date: Fri, 21 Jan 2022 18:57:30 +0000 Subject: [PATCH 12/28] Fix some of the new date/time function features to comply with the spec. Update requirement marks. FossilOrigin-Name: 2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/date.c | 7 +++++-- src/where.c | 2 +- test/printf2.test | 19 +++++++++++-------- 5 files changed, 26 insertions(+), 20 deletions(-) diff --git a/manifest b/manifest index c4f2b80e50..7b4945ce49 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C When\scomputing\sa\svector\sto\sbe\sused\sas\sa\skey\sfor\san\sindex\slookup,\sdo\snot\ncheck\sfor\sNULL\svalues\sand\sabort\suntil\safter\sall\skey\svalues\shave\sbeen\ncomputed,\sin\scase\sone\sof\sthe\slater\skey\svalues\sinvolves\ssome\sinitialization\nthat\sis\sneeded\sby\sa\sLEFT\sJOIN.\s\sFix\sfor\sthe\sproblem\sidentified\sby\n[forum:/forumpost/ab95010d410a0a55|Forum\spost\sab95010d410a0a55]. -D 2022-01-21T16:41:11.844 +C Fix\ssome\sof\sthe\snew\sdate/time\sfunction\sfeatures\sto\scomply\swith\sthe\sspec.\nUpdate\srequirement\smarks. +D 2022-01-21T18:57:30.991 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -499,7 +499,7 @@ F src/build.c c72407a27a28982a384cd453a3a6b6992a1ceae8bd8d95e96d7fb9c0d645a32f F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 -F src/date.c ab8e01d928f201f5dee0bc6d54d6702fdcec96dff4d58c387447671f6a46d191 +F src/date.c e25773f06a8f9043bfa1e5fa0bee93483c41933adfff0891752f00eadd12ab1c F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c 19814f621cde10b1771a0dea7fe25d3d7d39975b8d4be4888537d30860e7c08c @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 6b4cd84869dafc250d2b0f47a2c190759904a4bb6a31fc930bc8e6a9fd9a8d77 +F src/where.c eb54405957c295e0706cbaea74f9e7cbb3d3dfdefe35d243440d2b4cbf601f0c F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 @@ -1292,7 +1292,7 @@ F test/pragma5.test 7b33fc43e2e41abf17f35fb73f71b49671a380ea92a6c94b6ce530a25f8d F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8 F test/prefixes.test b524a1c44bffec225b9aec98bd728480352aa8532ac4c15771fb85e8beef65d9 F test/printf.test 390d0d7fcffc3c4ea3c1bb4cbb267444e32b33b048ae21895f23a291844fe1da -F test/printf2.test 30b5dd0b4b992dc5626496846ecce17ff592cacbcb11c3e589f3ac4d7e129dae +F test/printf2.test 3f55c1871a5a65507416076f6eb97e738d5210aeda7595a74ee895f2224cce60 F test/progress.test ebab27f670bd0d4eb9d20d49cef96e68141d92fb F test/ptrchng.test ef1aa72d6cf35a2bbd0869a649b744e9d84977fc F test/pushdown.test 5e72c51c5e33253ed639ccee1e01ce62d62b6eee5ca893cd82334e4ee7b1d7fc @@ -1940,8 +1940,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e19a0b132a641f0e9f3d72586af538b95b4db8665b1555f84bc0a291bf1a4056 -R 3ccffcbe5ebff55f0ce3325fb7a3c810 +P 4db5217a28ce767fa14ddfe51cf3ca25eceb72079d46a2fc00f7d6b8ae9abe0b +R 24d2bd64e4649dfdcb9c37612f05fb9b U drh -Z c6c4905bc0565a74c6f262fe9b11d1a3 +Z 2f4202747416d6f8106ca71a5cd08950 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 5af5151c6c..a9fd050c99 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4db5217a28ce767fa14ddfe51cf3ca25eceb72079d46a2fc00f7d6b8ae9abe0b \ No newline at end of file +2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8 \ No newline at end of file diff --git a/src/date.c b/src/date.c index b018c39f68..2117b1b853 100644 --- a/src/date.c +++ b/src/date.c @@ -658,7 +658,8 @@ static int parseModifier( sqlite3_context *pCtx, /* Function context */ const char *z, /* The text of the modifier */ int n, /* Length of zMod in bytes */ - DateTime *p /* The date/time value to be modified */ + DateTime *p, /* The date/time value to be modified */ + int idx /* Parameter index of the modifier */ ){ int rc = 1; double r; @@ -671,6 +672,7 @@ static int parseModifier( ** a unix timestamp, depending on its magnitude. */ if( sqlite3_stricmp(z, "auto")==0 ){ + if( idx>1 ) return 1; /* IMP: R-33611-57934 */ if( !p->rawS || p->validJD ){ rc = 0; p->rawS = 0; @@ -695,6 +697,7 @@ static int parseModifier( ** SQLite (0..5373484.5) then the result will be NULL. */ if( sqlite3_stricmp(z, "julianday")==0 ){ + if( idx>1 ) return 1; if( p->validJD && p->rawS ){ rc = 0; p->rawS = 0; @@ -938,7 +941,7 @@ static int isDate( for(i=1; iisError || !validJulianDay(p->iJD) ) return 1; diff --git a/src/where.c b/src/where.c index bf6cf49e03..3fa7a921de 100644 --- a/src/where.c +++ b/src/where.c @@ -3684,7 +3684,7 @@ int sqlite3_vtab_rhs_value( } *ppVal = pVal; - if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-60459-24801 */ + if( rc==SQLITE_OK && pVal==0 ){ /* IMP: R-19933-32160 */ rc = SQLITE_NOTFOUND; /* IMP: R-36424-56542 */ } diff --git a/test/printf2.test b/test/printf2.test index 998038f88e..2f6208b17f 100644 --- a/test/printf2.test +++ b/test/printf2.test @@ -12,10 +12,13 @@ # focus of this file is testing the printf() SQL function. # # -# EVIDENCE-OF: R-63057-40065 The printf(FORMAT,...) SQL function works +# EVIDENCE-OF: R-32560-14372 The format(FORMAT,...) SQL function works # like the sqlite3_mprintf() C-language function and the printf() # function from the standard C library. # +# EVIDENCE-OF: R-64900-53159 The printf() SQL function is an alias for +# the format() SQL function. +# set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -24,7 +27,7 @@ source $testdir/tester.tcl # then the result is NULL. # do_execsql_test printf2-1.1 { - SELECT quote(printf()), quote(printf(NULL,1,2,3)); + SELECT quote(format()), quote(format(NULL,1,2,3)); } {NULL NULL} @@ -32,31 +35,31 @@ do_execsql_test printf2-1.2 { SELECT printf('hello'); } {hello} do_execsql_test printf2-1.3 { - SELECT printf('%d,%d,%d',55,-11,3421); + SELECT format('%d,%d,%d',55,-11,3421); } {55,-11,3421} do_execsql_test printf2-1.4 { SELECT printf('%d,%d,%d',55,'-11',3421); } {55,-11,3421} do_execsql_test printf2-1.5 { - SELECT printf('%d,%d,%d,%d',55,'-11',3421); + SELECT format('%d,%d,%d,%d',55,'-11',3421); } {55,-11,3421,0} do_execsql_test printf2-1.6 { SELECT printf('%.2f',3.141592653); } {3.14} do_execsql_test printf2-1.7 { - SELECT printf('%.*f',2,3.141592653); + SELECT format('%.*f',2,3.141592653); } {3.14} do_execsql_test printf2-1.8 { SELECT printf('%*.*f',5,2,3.141592653); } {{ 3.14}} do_execsql_test printf2-1.9 { - SELECT printf('%d',314159.2653); + SELECT format('%d',314159.2653); } {314159} do_execsql_test printf2-1.10 { SELECT printf('%lld',314159.2653); } {314159} do_execsql_test printf2-1.11 { - SELECT printf('%lld%n',314159.2653,'hi'); + SELECT format('%lld%n',314159.2653,'hi'); } {314159} do_execsql_test printf2-1.12 { SELECT printf('%n',0); @@ -65,7 +68,7 @@ do_execsql_test printf2-1.12 { # EVIDENCE-OF: R-17002-27534 The %z format is interchangeable with %s. # do_execsql_test printf2-1.12 { - SELECT printf('%.*z',5,'abcdefghijklmnop'); + SELECT format('%.*z',5,'abcdefghijklmnop'); } {abcde} do_execsql_test printf2-1.13 { SELECT printf('%c','abcdefghijklmnop'); From 4d7f335e8bd4773befdb73e7c0a42b6f773726f9 Mon Sep 17 00:00:00 2001 From: drh <> Date: Fri, 21 Jan 2022 19:26:18 +0000 Subject: [PATCH 13/28] Update evidence marks for the latest changes to the documentation. FossilOrigin-Name: 19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/e_expr.test | 11 ++++------- test/e_fkey.test | 4 ++-- 4 files changed, 14 insertions(+), 17 deletions(-) diff --git a/manifest b/manifest index 7b4945ce49..577199e3ba 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\ssome\sof\sthe\snew\sdate/time\sfunction\sfeatures\sto\scomply\swith\sthe\sspec.\nUpdate\srequirement\smarks. -D 2022-01-21T18:57:30.991 +C Update\sevidence\smarks\sfor\sthe\slatest\schanges\sto\sthe\sdocumentation. +D 2022-01-21T19:26:18.123 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -868,8 +868,8 @@ F test/e_createtable.test 04c50b7fe41c12ed9cd88fbbc09b4900bcfc66f98ad198874fc993 F test/e_delete.test ab39084f26ae1f033c940b70ebdbbd523dc4962e F test/e_droptrigger.test 235c610f8bf8ec44513e222b9085c7e49fad65ad0c1975ac2577109dd06fd8fa F test/e_dropview.test 74e405df7fa0f762e0c9445b166fe03955856532e2bb234c372f7c51228d75e7 -F test/e_expr.test e164550b9f8fd9c130283d1eae692dff9e2ba67f4dbd35f7325021f5d4b8851c -F test/e_fkey.test ee321dbca3c53204da46cb40b8ec80192e995035f9ea26576ddcd842b1f0877f +F test/e_expr.test bc6aa5906ba967587525bc746ea403011557cf6d8e4fc9efb1fab5dae7fb4fd6 +F test/e_fkey.test feeba6238aeff9d809fb6236b351da8df4ae9bda89e088e54526b31a0cbfeec5 F test/e_fts3.test 17ba7c373aba4d4f5696ba147ee23fd1a1ef70782af050e03e262ca187c5ee07 F test/e_insert.test f02f7f17852b2163732c6611d193f84fc67bc641fb4882c77a464076e5eba80e F test/e_reindex.test 2b0e29344497d9a8a999453a003cb476b6b1d2eef2d6c120f83c2d3a429f3164 @@ -1940,8 +1940,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4db5217a28ce767fa14ddfe51cf3ca25eceb72079d46a2fc00f7d6b8ae9abe0b -R 24d2bd64e4649dfdcb9c37612f05fb9b +P 2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8 +R fe7b9dd51502fbf713e5aec593679235 U drh -Z 2f4202747416d6f8106ca71a5cd08950 +Z 6c89130f8a98285b65b9e81e57d8e5fd # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index a9fd050c99..7a58964939 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8 \ No newline at end of file +19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e \ No newline at end of file diff --git a/test/e_expr.test b/test/e_expr.test index 93ca0268c8..3f8d5ad85c 100644 --- a/test/e_expr.test +++ b/test/e_expr.test @@ -265,13 +265,10 @@ do_execsql_test e_expr-6.4 {SELECT -72%5} {-2} do_execsql_test e_expr-6.5 {SELECT 72.35%5} {2.0} #------------------------------------------------------------------------- -# Test that the results of all binary operators are either numeric or -# NULL, except for the || operator, which may evaluate to either a text -# value or NULL. -# -# EVIDENCE-OF: R-20665-17792 The result of any binary operator is either -# a numeric value or NULL, except for the || concatenation operator -# which always evaluates to either NULL or a text value. +# EVIDENCE-OF: R-15904-00746 The result of any binary operator is either +# a numeric value or NULL, except for the || concatenation operator, and +# the -> and ->> extract operators which evaluate to either +# NULL or a text value. # set literals { 1 'abc' 2 'hexadecimal' 3 '' diff --git a/test/e_fkey.test b/test/e_fkey.test index ab3c29033b..3662a39981 100644 --- a/test/e_fkey.test +++ b/test/e_fkey.test @@ -48,9 +48,9 @@ proc do_detail_test {tn sql res} { ########################################################################### #------------------------------------------------------------------------- -# EVIDENCE-OF: R-33710-56344 In order to use foreign key constraints in +# EVIDENCE-OF: R-37672-59189 In order to use foreign key constraints in # SQLite, the library must be compiled with neither -# SQLITE_OMIT_FOREIGN_KEY or SQLITE_OMIT_TRIGGER defined. +# SQLITE_OMIT_FOREIGN_KEY nor SQLITE_OMIT_TRIGGER defined. # ifcapable trigger&&foreignkey { do_test e_fkey-1 { From ec778d27241d54be6967a2d1eb44cf549507f728 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 22 Jan 2022 00:18:01 +0000 Subject: [PATCH 14/28] An initial attempt to implement sqlite3_vtab_distinct(). FossilOrigin-Name: d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5 --- ext/misc/qpvtab.c | 2 ++ manifest | 24 ++++++++++++++---------- manifest.uuid | 2 +- src/loadext.c | 1 + src/sqlite.h.in | 22 ++++++++++++++++++++++ src/sqlite3ext.h | 2 ++ src/where.c | 28 +++++++++++++++++++++++----- test/vtabdistinct.test | 36 ++++++++++++++++++++++++++++++++++++ 8 files changed, 101 insertions(+), 16 deletions(-) create mode 100644 test/vtabdistinct.test diff --git a/ext/misc/qpvtab.c b/ext/misc/qpvtab.c index 6c145ffd17..828a5ba1b8 100644 --- a/ext/misc/qpvtab.c +++ b/ext/misc/qpvtab.c @@ -372,6 +372,8 @@ static int qpvtabBestIndex( pIdxInfo->aOrderBy[i].desc ); } + sqlite3_str_appendf(pStr, "sqlite3_vtab_distinct,%d,,,,\n", + sqlite3_vtab_distinct(pIdxInfo)); sqlite3_str_appendf(pStr, "idxFlags,%d,,,,\n", pIdxInfo->idxFlags); sqlite3_str_appendf(pStr, "colUsed,%d,,,,\n", (int)pIdxInfo->colUsed); pIdxInfo->estimatedCost = (double)10; diff --git a/manifest b/manifest index 577199e3ba..cc18282832 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Update\sevidence\smarks\sfor\sthe\slatest\schanges\sto\sthe\sdocumentation. -D 2022-01-21T19:26:18.123 +C An\sinitial\sattempt\sto\simplement\ssqlite3_vtab_distinct(). +D 2022-01-22T00:18:01.617 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -316,7 +316,7 @@ F ext/misc/noop.c 81efe4cad9ec740e64388b14281cb983e6e2c223fed43eb77ab3e34946e0c1 F ext/misc/normalize.c bd84355c118e297522aba74de34a4fd286fc775524e0499b14473918d09ea61f F ext/misc/percentile.c b9086e223d583bdaf8cb73c98a6539d501a2fc4282654adbfea576453d82e691 F ext/misc/prefixes.c 0f4f8cff5aebc00a7e3ac4021fd59cfe1a8e17c800ceaf592859ecb9cbc38196 -F ext/misc/qpvtab.c d40b07a8c341d16629010c3e8d8801f1477f70d6257e052973a8ddf14c07cd8d +F ext/misc/qpvtab.c c662fa0a452ad286e49b6c83ac917600656b2eb47d2225ff6185c56bf80cf8d2 F ext/misc/regexp.c b267fd05ff8d38b22f4c2809d7b7a2c61d522e9faf2feb928dbb9662e4a3a386 F ext/misc/remember.c add730f0f7e7436cd15ea3fd6a90fd83c3f706ab44169f7f048438b7d6baa69c F ext/misc/rot13.c 51ac5f51e9d5fd811db58a9c23c628ad5f333c173f1fc53c8491a3603d38556c @@ -515,7 +515,7 @@ F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743 F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa -F src/loadext.c 9a693eb89575af5d54b025c1e927b2ea8114bbeee3db346e8abc81676dd82160 +F src/loadext.c 657534339585ac234839e5187aa51d8802f292e0771c4f874b3af1f1223f81e2 F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960 F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 @@ -554,9 +554,9 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e -F src/sqlite.h.in 67e49a50bb29e3af86d2b3606af6b3fe20a0d09cf326cc574d632d878c0696d6 +F src/sqlite.h.in 1335c91f118ed8490ab8661becf8ad7d29fe531149464d72ccc095290c872e86 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h 234b5ff5c20512a116b14d6d08e23caeb68667749f8a94117779a9d38afc7e5c +F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c eb54405957c295e0706cbaea74f9e7cbb3d3dfdefe35d243440d2b4cbf601f0c +F src/where.c 7df767249645ba428b8a217278319028c679f48f2daecac8461ae6e2d281cd6d F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 @@ -1724,6 +1724,7 @@ F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3af F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad +F test/vtabdistinct.test e35a8c91cd9e2a1130eb708376e33aa38511b880fb7c1691387d3e9ec57d9157 F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12 F test/vtabrhs1.test c138346be341916ecc9d918dcfc2657d27bce211a350a82b01d62d224b167b56 F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089 @@ -1940,8 +1941,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 2f5dc7a9eed89baf6814e9e123354b262c806c853dee1243c93286c564b9aba8 -R fe7b9dd51502fbf713e5aec593679235 +P 19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e +R dfc70e19d986a79e444a3389314d1aa6 +T *branch * sqlite3_vtab_distinct +T *sym-sqlite3_vtab_distinct * +T -sym-trunk * U drh -Z 6c89130f8a98285b65b9e81e57d8e5fd +Z 502f02fc5994424f0d3cd19482ecaf51 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7a58964939..7744a710a7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e \ No newline at end of file +d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5 \ No newline at end of file diff --git a/src/loadext.c b/src/loadext.c index c917e11c8e..a4aad7e748 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -488,6 +488,7 @@ static const sqlite3_api_routines sqlite3Apis = { /* Version 3.38.0 and later */ sqlite3_error_offset, sqlite3_vtab_rhs_value, + sqlite3_vtab_distinct, }; /* True if x is the directory separator character diff --git a/src/sqlite.h.in b/src/sqlite.h.in index ca27742cb1..1e78911129 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -9503,6 +9503,28 @@ int sqlite3_vtab_nochange(sqlite3_context*); */ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); +/* +** CAPI3REF: Determine if virtual table query is DISTINCT +** METHOD: sqlite3_index_info +** +** This API may only be used from within an xBestIndex() callback. The +** results of calling it from outside of an xBestIndex() callback are +** undefined and probably harmful. +** +** ^The sqlite3_vtab_distinct() returns an integer that is either 0, 1, or +** 2. ^The sqlite3_vtab_distinct() interface returns 0 if SQLite needs the +** output rows sorted as defined by the nOrderBy and aOrderBy fields of the +** [sqlite3_index_info] object P. ^The sqlite3_vtab_distinct() interface +** returns 1 if SQLite needs all rows to be returned and for equivalent rows +** to be adjacent to one another, but if it does not require that the rows +** be sorted. ^The sqlite3_vtab_distinct() interface returns 2 if SQLite only +** needs the virtual table to return rows that are distinct for the columns +** identified by the nOrderBy and aOrderBy fields of the [sqlite3_index_info] +** object. If rows are returned that differ in any of the columns identified +** by the nOrderBy and aOrderBy fields, then all such rows should be adjacent. +*/ +int sqlite3_vtab_distinct(sqlite3_index_info*); + /* ** CAPI3REF: Constraint values in xBestIndex() ** METHOD: sqlite3_index_info diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 580078b6d0..88010b9d8d 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -347,6 +347,7 @@ struct sqlite3_api_routines { /* Version 3.38.0 and later */ int (*error_offset)(sqlite3*); int (*vtab_rhs_value)(sqlite3_index_info*,int,sqlite3_value**); + int (*vtab_distinct)(sqlite3_index_info*); }; /* @@ -661,6 +662,7 @@ typedef int (*sqlite3_loadext_entry)( /* Version 3.38.0 and later */ #define sqlite3_error_offset sqlite3_api->error_offset #define sqlite3_vtab_rhs_value sqlite3_api->vtab_rhs_value +#define sqlite3_vtab_distinct sqlite3_api->vtab_distinct #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/where.c b/src/where.c index 3fa7a921de..fe262b36e1 100644 --- a/src/where.c +++ b/src/where.c @@ -32,6 +32,7 @@ typedef struct HiddenIndexInfo HiddenIndexInfo; struct HiddenIndexInfo { WhereClause *pWC; /* The Where clause being analyzed */ Parse *pParse; /* The parsing context */ + int eDistinct; /* Value to return from sqlite3_vtab_distinct() */ sqlite3_value *aRhs[1]; /* RHS values for constraints. MUST BE LAST ** because extra space is allocated to hold up ** to nTerm such values */ @@ -1101,15 +1102,15 @@ static SQLITE_NOINLINE void sqlite3ConstructBloomFilter( ** by passing the pointer returned by this function to freeIndexInfo(). */ static sqlite3_index_info *allocateIndexInfo( - Parse *pParse, /* The parsing context */ + WhereInfo *pWInfo, /* The WHERE clause */ WhereClause *pWC, /* The WHERE clause being analyzed */ Bitmask mUnusable, /* Ignore terms with these prereqs */ SrcItem *pSrc, /* The FROM clause term that is the vtab */ - ExprList *pOrderBy, /* The ORDER BY clause */ u16 *pmNoOmit /* Mask of terms not to omit */ ){ int i, j; int nTerm; + Parse *pParse = pWInfo->pParse; struct sqlite3_index_constraint *pIdxCons; struct sqlite3_index_orderby *pIdxOrderBy; struct sqlite3_index_constraint_usage *pUsage; @@ -1119,7 +1120,9 @@ static sqlite3_index_info *allocateIndexInfo( sqlite3_index_info *pIdxInfo; u16 mNoOmit = 0; const Table *pTab; - + int eDistinct = 0; + ExprList *pOrderBy = pWInfo->pOrderBy; + assert( pSrc!=0 ); pTab = pSrc->pTab; assert( pTab!=0 ); @@ -1203,6 +1206,9 @@ static sqlite3_index_info *allocateIndexInfo( } if( i==n){ nOrderBy = n; + if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){ + eDistinct = 1; + } } } @@ -1225,6 +1231,7 @@ static sqlite3_index_info *allocateIndexInfo( pIdxInfo->aConstraintUsage = pUsage; pHidden->pWC = pWC; pHidden->pParse = pParse; + pHidden->eDistinct = eDistinct; for(i=j=0, pTerm=pWC->a; inTerm; i++, pTerm++){ u16 op; if( (pTerm->wtFlags & TERM_OK)==0 ) continue; @@ -3691,6 +3698,18 @@ int sqlite3_vtab_rhs_value( return rc; } + +/* +** Return true if ORDER BY clause may be handled as DISTINCT. +*/ +int sqlite3_vtab_distinct(sqlite3_index_info *pIdxInfo){ + HiddenIndexInfo *pHidden = (HiddenIndexInfo*)&pIdxInfo[1]; + assert( pHidden->eDistinct==0 + || pHidden->eDistinct==1 + || pHidden->eDistinct==2 ); + return pHidden->eDistinct; +} + /* ** Add all WhereLoop objects for a table of the join identified by ** pBuilder->pNew->iTab. That table is guaranteed to be a virtual table. @@ -3740,8 +3759,7 @@ static int whereLoopAddVirtual( pNew = pBuilder->pNew; pSrc = &pWInfo->pTabList->a[pNew->iTab]; assert( IsVirtual(pSrc->pTab) ); - p = allocateIndexInfo(pParse, pWC, mUnusable, pSrc, pBuilder->pOrderBy, - &mNoOmit); + p = allocateIndexInfo(pWInfo, pWC, mUnusable, pSrc, &mNoOmit); if( p==0 ) return SQLITE_NOMEM_BKPT; pNew->rSetup = 0; pNew->wsFlags = WHERE_VIRTUALTABLE; diff --git a/test/vtabdistinct.test b/test/vtabdistinct.test new file mode 100644 index 0000000000..63fa1569d3 --- /dev/null +++ b/test/vtabdistinct.test @@ -0,0 +1,36 @@ +# 2022-01-21 +# +# The author disclaims copyright to this source code. In place of +# a legal notice, here is a blessing: +# +# May you do good and not evil. +# May you find forgiveness for yourself and forgive others. +# May you share freely, never taking more than you give. +# +#*********************************************************************** +# +# This file implements tests for sqlite3_vtab_distinct() interface. +# + +set testdir [file dirname $argv0] +source $testdir/tester.tcl +set testprefix vtabdistinct + +ifcapable !vtab { + finish_test + return +} +load_static_extension db qpvtab + +do_execsql_test 1.1 { + SELECT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct'; +} {0} +do_execsql_test 1.2 { + SELECT DISTINCT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct'; +} {1} +do_execsql_test 1.3 { + SELECT distinct vn, ix FROM qpvtab(3) + WHERE +vn IN ('sqlite3_vtab_distinct','nOrderBy'); +} {nOrderBy 2 sqlite3_vtab_distinct 1} + +finish_test From 57c58b4de8a9e0b41a683e9a1d8b6bb3fc31bac2 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 22 Jan 2022 02:52:22 +0000 Subject: [PATCH 15/28] Omit the WhereLoopBuilder.pOrderBy field, which is no longer needed. FossilOrigin-Name: a13afc909c8bb643aa154b39ba8c023bae7352d3cd7cfb96be3891fa0e4bc045 --- manifest | 17 +++++++---------- manifest.uuid | 2 +- src/where.c | 2 -- src/whereInt.h | 1 - 4 files changed, 8 insertions(+), 14 deletions(-) diff --git a/manifest b/manifest index cc18282832..b4574239e7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C An\sinitial\sattempt\sto\simplement\ssqlite3_vtab_distinct(). -D 2022-01-22T00:18:01.617 +C Omit\sthe\sWhereLoopBuilder.pOrderBy\sfield,\swhich\sis\sno\slonger\sneeded. +D 2022-01-22T02:52:22.316 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,8 +639,8 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 7df767249645ba428b8a217278319028c679f48f2daecac8461ae6e2d281cd6d -F src/whereInt.h 91865afa4a3540bb3bd643619acc56fbceff7defeb8f249b8e157fd5325d88be +F src/where.c bf15b922a134948a56a078e0a01d1e63f9f8ff59f6503cba241855f8cb961b4f +F src/whereInt.h 8a215acde0f833a4dea3d30a7bbed9f48b4b547b5d5e34cd02acee366476ab80 F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e @@ -1941,11 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e -R dfc70e19d986a79e444a3389314d1aa6 -T *branch * sqlite3_vtab_distinct -T *sym-sqlite3_vtab_distinct * -T -sym-trunk * +P d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5 +R c8f2432bbe6ecf01b6e5ac0aa57d1f94 U drh -Z 502f02fc5994424f0d3cd19482ecaf51 +Z 0649a152fd9646f6591062a2384e3001 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 7744a710a7..c378259f5f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5 \ No newline at end of file +a13afc909c8bb643aa154b39ba8c023bae7352d3cd7cfb96be3891fa0e4bc045 \ No newline at end of file diff --git a/src/where.c b/src/where.c index fe262b36e1..c8e7d906b9 100644 --- a/src/where.c +++ b/src/where.c @@ -3891,7 +3891,6 @@ static int whereLoopAddOr( int i, j; sSubBuild = *pBuilder; - sSubBuild.pOrderBy = 0; sSubBuild.pOrSet = &sCur; WHERETRACE(0x200, ("Begin processing OR-clause %p\n", pTerm)); @@ -5283,7 +5282,6 @@ WhereInfo *sqlite3WhereBegin( /* An ORDER/GROUP BY clause of more than 63 terms cannot be optimized */ testcase( pOrderBy && pOrderBy->nExpr==BMS-1 ); if( pOrderBy && pOrderBy->nExpr>=BMS ) pOrderBy = 0; - sWLB.pOrderBy = pOrderBy; /* The number of tables in the FROM clause is limited by the number of ** bits in a Bitmask diff --git a/src/whereInt.h b/src/whereInt.h index a97b4afc69..1304a40a77 100644 --- a/src/whereInt.h +++ b/src/whereInt.h @@ -386,7 +386,6 @@ struct WhereMaskSet { struct WhereLoopBuilder { WhereInfo *pWInfo; /* Information about this WHERE */ WhereClause *pWC; /* WHERE clause terms */ - ExprList *pOrderBy; /* ORDER BY clause */ WhereLoop *pNew; /* Template WhereLoop */ WhereOrSet *pOrSet; /* Record best loops here, if not NULL */ #ifdef SQLITE_ENABLE_STAT4 From 9b9fc74f2eafeb8a280198ee7209c8ccefe6a108 Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 22 Jan 2022 19:19:35 +0000 Subject: [PATCH 16/28] Iimproved documentation for sqlite3_vtab_distinct(). No changes to code. FossilOrigin-Name: 7af03f02940b5380ee7375672ca8d0ff68c5f741d0ea206911631f3eb5a78555 --- manifest | 12 ++++----- manifest.uuid | 2 +- src/sqlite.h.in | 72 +++++++++++++++++++++++++++++++++++++++---------- 3 files changed, 65 insertions(+), 21 deletions(-) diff --git a/manifest b/manifest index b4574239e7..00218ad384 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Omit\sthe\sWhereLoopBuilder.pOrderBy\sfield,\swhich\sis\sno\slonger\sneeded. -D 2022-01-22T02:52:22.316 +C Iimproved\sdocumentation\sfor\ssqlite3_vtab_distinct().\s\sNo\schanges\sto\scode. +D 2022-01-22T19:19:35.721 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -554,7 +554,7 @@ F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e -F src/sqlite.h.in 1335c91f118ed8490ab8661becf8ad7d29fe531149464d72ccc095290c872e86 +F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d571262d2345bb11e71bef395cf078e5d7303b974b38b4e319adda6194ccc1c5 -R c8f2432bbe6ecf01b6e5ac0aa57d1f94 +P a13afc909c8bb643aa154b39ba8c023bae7352d3cd7cfb96be3891fa0e4bc045 +R ee7e69afa00103e3a528aaa0afa4a945 U drh -Z 0649a152fd9646f6591062a2384e3001 +Z f9808520490668283a6ca50de433adb3 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index c378259f5f..fb902954b0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a13afc909c8bb643aa154b39ba8c023bae7352d3cd7cfb96be3891fa0e4bc045 \ No newline at end of file +7af03f02940b5380ee7375672ca8d0ff68c5f741d0ea206911631f3eb5a78555 \ No newline at end of file diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 1e78911129..4b36233b37 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -9471,13 +9471,14 @@ int sqlite3_vtab_nochange(sqlite3_context*); /* ** CAPI3REF: Determine The Collation For a Virtual Table Constraint +** METHOD: sqlite3_index_info ** ** This function may only be called from within a call to the [xBestIndex] ** method of a [virtual table]. This function returns a pointer to a string ** that is the name of the appropriate collation sequence to use for text ** comparisons on the constraint identified by its arguments. ** -** The first argument must be the pointer to the sqlite3_index_info object +** The first argument must be the pointer to the [sqlite3_index_info] object ** that is the first parameter to the xBestIndex() method. The second argument ** must be an index into the aConstraint[] array belonging to the ** sqlite3_index_info structure passed to xBestIndex. @@ -9485,7 +9486,7 @@ int sqlite3_vtab_nochange(sqlite3_context*); ** Important: ** The first parameter must be the same pointer that is passed into the ** xBestMethod() method. The first parameter may not be a pointer to a -** different sqlite3_index_info object, even an exact copy. +** different [sqlite3_index_info] object, even an exact copy. ** ** The return value is computed as follows: ** @@ -9504,7 +9505,7 @@ int sqlite3_vtab_nochange(sqlite3_context*); SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); /* -** CAPI3REF: Determine if virtual table query is DISTINCT +** CAPI3REF: Determine if a virtual table query is DISTINCT ** METHOD: sqlite3_index_info ** ** This API may only be used from within an xBestIndex() callback. The @@ -9512,16 +9513,59 @@ SQLITE_EXPERIMENTAL const char *sqlite3_vtab_collation(sqlite3_index_info*,int); ** undefined and probably harmful. ** ** ^The sqlite3_vtab_distinct() returns an integer that is either 0, 1, or -** 2. ^The sqlite3_vtab_distinct() interface returns 0 if SQLite needs the -** output rows sorted as defined by the nOrderBy and aOrderBy fields of the -** [sqlite3_index_info] object P. ^The sqlite3_vtab_distinct() interface -** returns 1 if SQLite needs all rows to be returned and for equivalent rows -** to be adjacent to one another, but if it does not require that the rows -** be sorted. ^The sqlite3_vtab_distinct() interface returns 2 if SQLite only -** needs the virtual table to return rows that are distinct for the columns -** identified by the nOrderBy and aOrderBy fields of the [sqlite3_index_info] -** object. If rows are returned that differ in any of the columns identified -** by the nOrderBy and aOrderBy fields, then all such rows should be adjacent. +** 2. The integer returned by sqlite3_vtab_distinct() gives the virtual table +** additional information about how the query planner wants the output to be +** ordered. As long as the virtual table can meet the ordering requirements +** of the query planner, it may set the "orderByConsumed" flag. +** +**
  1. +** ^If the sqlite3_vtab_distinct() interface returns 0, that means +** that the query planner needs the virtual table to return all rows in the +** sort order defined by the "nOrderBy" and "aOrderBy" fields of the +** [sqlite3_index_info] object. This is the default expectation. If the +** virtual table outputs all rows in sorted order, then it is always safe for +** the xBestIndex method to set the "orderByConsumed" flag, regardless of +** what the return value from sqlite3_vtab_distinct(). +**

  2. +** ^(If the sqlite3_vtab_distinct() interface returns 1, that means +** that the query planner does not need the rows to be returned in sorted order +** as long as all rows with the same values in all columns identified by the +** "aOrderBy" field are adjacent.)^ This mode is used when the query planner +** is doing a GROUP BY. +**

  3. +** ^(If the sqlite3_vtab_distinct() interface returns 2, that means +** that the query planner does not need the rows returned in any particular +** order, as long as rows with the same values in all "aOrderBy" columns +** are adjacent.)^ ^(Furthermore, only a single row for each particular +** combination of values in the columns identified by the "aOrderBy" field +** needs to be returned.)^ ^It is ok always for two or more rows with the same +** values in all "aOrderBy" columns to be returned, as long as all such rows +** are adjacent. ^The virtual table may, if it chooses, omit extra rows +** that have the same value for all columns identified by "aOrderBy". +** ^However omitting the extra rows is optional. +** This mode is used for a DISTINCT query. +**

+** +** ^For the purposes of comparing virtual table output values to see if the +** values are same value for sorting purposes, two NULL values are considered +** to be the same. In other words, the comparison operator is "IS" +** (or "IS NOT DISTINCT FROM") and not "==". +** +** If a virtual table implementation is unable to meet the requirements +** specified above, then it must not set the "orderByConsumed" flag in the +** [sqlite3_index_info] object or an incorrect answer may result. +** +** ^A virtual table implementation is always free to return rows in any order +** it wants, as long as the "orderByConsumed" flag is not set. ^When the +** the "orderByConsumed" flag is unset, the query planner will add extra +** [bytecode] to ensure that the final results returned by the SQL query are +** ordered correctly. The use of the "orderByConsumed" flag and the +** sqlite3_vtab_distinct() interface is merely an optimization. ^Careful +** use of the sqlite3_vtab_distinct() interface and the "orderByConsumed" +** flag might help queries against a virtual table to run faster. Being +** overly aggressive and setting the "orderByConsumed" flag when it is not +** valid to do so, on the other hand, might cause SQLite to return incorrect +** results. */ int sqlite3_vtab_distinct(sqlite3_index_info*); @@ -9535,7 +9579,7 @@ int sqlite3_vtab_distinct(sqlite3_index_info*); ** ** ^When the sqlite3_vtab_rhs_value(P,J,V) interface is invoked from within ** the [xBestIndex] method of a [virtual table] implementation, with P being -** a copy of the sqlite3_index_info object pointer passed into xBestIndex and +** a copy of the [sqlite3_index_info] object pointer passed into xBestIndex and ** J being a 0-based index into P->aConstraint[], then this routine ** attempts to set *V to be the value on the right-hand side of ** that constraint if the right-hand side is a known constant. ^If the From 68dc8151e092019baba5a190e195a982252b925f Mon Sep 17 00:00:00 2001 From: drh <> Date: Sat, 22 Jan 2022 20:45:57 +0000 Subject: [PATCH 17/28] Bring sqlite3_vtab_distinct() up to spec so that it works as described in the documentation. FossilOrigin-Name: 4289edf3c5e32a05b51f232020099b33f6f5e79b0ceca2b96baf1186168d9af6 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/where.c | 4 ++-- test/vtabdistinct.test | 9 +++++++-- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index 00218ad384..882cfbc89f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Iimproved\sdocumentation\sfor\ssqlite3_vtab_distinct().\s\sNo\schanges\sto\scode. -D 2022-01-22T19:19:35.721 +C Bring\ssqlite3_vtab_distinct()\sup\sto\sspec\sso\sthat\sit\sworks\sas\sdescribed\sin\sthe\ndocumentation. +D 2022-01-22T20:45:57.210 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -639,7 +639,7 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c bf15b922a134948a56a078e0a01d1e63f9f8ff59f6503cba241855f8cb961b4f +F src/where.c 9824d15f2a92cbe4d6566e2a97fa4466ce6297e68693322e64281db5e942fa92 F src/whereInt.h 8a215acde0f833a4dea3d30a7bbed9f48b4b547b5d5e34cd02acee366476ab80 F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 @@ -1724,7 +1724,7 @@ F test/vtabK.test 13293177528fada1235c0112db0d187d754af1355c5a39371abd365104e3af F test/vtab_alter.test 736e66fb5ec7b4fee58229aa3ada2f27ec58bc58c00edae4836890c3784c6783 F test/vtab_err.test dcc8b7b9cb67522b3fe7a272c73856829dae4ab7fdb30399aea1b6981bda2b65 F test/vtab_shared.test 5253bff2355a9a3f014c15337da7e177ab0ef8ad -F test/vtabdistinct.test e35a8c91cd9e2a1130eb708376e33aa38511b880fb7c1691387d3e9ec57d9157 +F test/vtabdistinct.test 7688f0889358f849fd60bbfde1ded38b014b18066076d4bfbb75395804dfe072 F test/vtabdrop.test 65d4cf6722972e5499bdaf0c0d70ee3b8133944a4e4bc31862563f32a7edca12 F test/vtabrhs1.test c138346be341916ecc9d918dcfc2657d27bce211a350a82b01d62d224b167b56 F test/wal.test b7cc6984709f54afbf8441747ced1f646af120bf0c1b1d847bfa39306fbea089 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a13afc909c8bb643aa154b39ba8c023bae7352d3cd7cfb96be3891fa0e4bc045 -R ee7e69afa00103e3a528aaa0afa4a945 +P 7af03f02940b5380ee7375672ca8d0ff68c5f741d0ea206911631f3eb5a78555 +R 8c92b45cd50ac9ababc3056da5861966 U drh -Z f9808520490668283a6ca50de433adb3 +Z 0f40ebbc8d49180e2de4a825f9a960d1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fb902954b0..e96d220661 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7af03f02940b5380ee7375672ca8d0ff68c5f741d0ea206911631f3eb5a78555 \ No newline at end of file +4289edf3c5e32a05b51f232020099b33f6f5e79b0ceca2b96baf1186168d9af6 \ No newline at end of file diff --git a/src/where.c b/src/where.c index c8e7d906b9..57c4808906 100644 --- a/src/where.c +++ b/src/where.c @@ -1206,8 +1206,8 @@ static sqlite3_index_info *allocateIndexInfo( } if( i==n){ nOrderBy = n; - if( (pWInfo->wctrlFlags & WHERE_DISTINCTBY) ){ - eDistinct = 1; + if( (pWInfo->wctrlFlags & (WHERE_GROUPBY|WHERE_DISTINCTBY)) ){ + eDistinct = 1 + ((pWInfo->wctrlFlags & WHERE_DISTINCTBY)!=0); } } } diff --git a/test/vtabdistinct.test b/test/vtabdistinct.test index 63fa1569d3..e18e121e50 100644 --- a/test/vtabdistinct.test +++ b/test/vtabdistinct.test @@ -27,10 +27,15 @@ do_execsql_test 1.1 { } {0} do_execsql_test 1.2 { SELECT DISTINCT ix FROM qpvtab WHERE vn='sqlite3_vtab_distinct'; -} {1} +} {2} do_execsql_test 1.3 { SELECT distinct vn, ix FROM qpvtab(3) WHERE +vn IN ('sqlite3_vtab_distinct','nOrderBy'); -} {nOrderBy 2 sqlite3_vtab_distinct 1} +} {nOrderBy 2 sqlite3_vtab_distinct 2} +do_execsql_test 1.4 { + SELECT vn, ix FROM qpvtab + GROUP BY vn + HAVING vn='sqlite3_vtab_distinct'; +} {sqlite3_vtab_distinct 1} finish_test From d48e88e56db870a68fc2d9802f643c14381f6a90 Mon Sep 17 00:00:00 2001 From: larrybr Date: Mon, 24 Jan 2022 06:36:16 +0000 Subject: [PATCH 18/28] Limit CLI input redirect nesting FossilOrigin-Name: 7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5 --- manifest | 17 ++++++++--------- manifest.uuid | 2 +- src/shell.c.in | 15 +++++++++++++++ test/shell4.test | 8 ++++++++ 4 files changed, 32 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index c9f7856650..4e48b7001b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\ssupport\sfor\sthe\ssqlite3_vtab_distinct()\sinterface.\s\sVirtual\stable\nimplementations\scan\suse\sthis\sAPI\sto\sdetermine\smore\sdetail\sabout\sthe\sordering\nrequirements\sneeded\sby\sthe\squery\splan\sand\sperhaps\sreduce\sthe\samount\sof\nwork\srequired\sto\scompute\sa\scorrect\sanswer.\s\sThis\sis\san\soptimization\nopportunity\sfor\sthe\svirtual\stable\simplementation.\s\sThe\scorrect\sanswer\sshould\nstill\sbe\sobtained\s(though\sperhaps\smore\sslowly)\seven\sif\ssqlite3_vtab_distinct()\nis\signored. -D 2022-01-22T22:28:32.461 +C Limit\sCLI\sinput\sredirect\snesting +D 2022-01-24T06:36:16.156 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -553,7 +553,7 @@ F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 -F src/shell.c.in 4690f216dc4da0c104a8fd9f9e12bec0483242e630324aa7a3ccd155922e346e +F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2 F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a @@ -1388,7 +1388,7 @@ F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566 -F test/shell4.test 3ed6c4b42fd695efcbc25d69ef759dbb15855ca8e52ba6c5ee076f8b435f48be +F test/shell4.test 8427e08751d4b16100fadb29f109cc1b8cce5c3858bdf34837c6e3b35fbbfee7 F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f @@ -1941,9 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 19247e919fab9748cae561cb12c4c3c106064390a37e32e724d9a9066cfaff8e 4289edf3c5e32a05b51f232020099b33f6f5e79b0ceca2b96baf1186168d9af6 -R 8c92b45cd50ac9ababc3056da5861966 -T +closed 4289edf3c5e32a05b51f232020099b33f6f5e79b0ceca2b96baf1186168d9af6 -U drh -Z 550b4c112b6ad484a8ff339f5683365a +P e4caf1e3932b1bd0dea072df7fc9458aed98c84ea397b6948b89292603949c41 +R 3ff059f17b79f35a7110343334a8c695 +U larrybr +Z 22bca9d238f29be7cbeeb6418fbc3f83 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 4cfc6dc89d..b9b364e4c1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e4caf1e3932b1bd0dea072df7fc9458aed98c84ea397b6948b89292603949c41 \ No newline at end of file +7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index c15d2e54d4..0a903672cc 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1086,6 +1086,7 @@ struct ShellState { u8 bSafeModePersist; /* The long-term value of bSafeMode */ unsigned statsOn; /* True to display memory stats before each finalize */ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ + int inputNesting; /* Track nesting level of .read and other redirects */ int outCount; /* Revert to stdout when reaching zero */ int cnt; /* Number of records displayed so far */ int lineno; /* Line number of last line read from in */ @@ -1250,6 +1251,12 @@ static const char *modeDescr[] = { #define SEP_Unit "\x1F" #define SEP_Record "\x1E" +/* +** Limit input nesting via .read or any other input redirect. +** It's not too expensive, so a generous allowance can be made. +*/ +#define MAX_INPUT_NESTING 25 + /* ** A callback for the sqlite3_log() interface. */ @@ -10940,6 +10947,13 @@ static int process_input(ShellState *p){ int startline = 0; /* Line number for start of current input */ QuickScanState qss = QSS_Start; /* Accumulated line status (so far) */ + if( p->inputNesting==MAX_INPUT_NESTING ){ + /* This will be more informative in a later version. */ + utf8_printf(stderr,"Input nesting limit (%d) reached at line %d." + " Check recursion.\n", MAX_INPUT_NESTING, p->lineno); + return 1; + } + ++p->inputNesting; p->lineno = 0; while( errCnt==0 || !bail_on_error || (p->in==0 && stdin_is_interactive) ){ fflush(p->out); @@ -11022,6 +11036,7 @@ static int process_input(ShellState *p){ } free(zSql); free(zLine); + --p->inputNesting; return errCnt>0; } diff --git a/test/shell4.test b/test/shell4.test index 9e3c58fbec..1be2c1d9ac 100644 --- a/test/shell4.test +++ b/test/shell4.test @@ -19,6 +19,7 @@ # shell4-1.*: Basic tests specific to the "stats" command. # shell4-2.*: Basic tests for ".trace" # shell4-3.*: The ".read" command takes the shell out of interactive mode +# shell4-4.*: Input redirects cannot recurse too much # set testdir [file dirname $argv0] source $testdir/tester.tcl @@ -138,4 +139,11 @@ do_test shell4-3.2 { exec $::CLI :memory: --interactive ".read t1.txt" } {pound: £} +do_test shell4-4.1 { + set fd [open t1.txt wb] + puts $fd ".read t1.txt" + close $fd + catchcmd ":memory:" ".read t1.txt" +} {1 {Input nesting limit (25) reached at line 1. Watch recursion.}} + finish_test From f5bc44407701b4143519ecb32a547ca2f3b169ff Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 24 Jan 2022 11:25:42 +0000 Subject: [PATCH 19/28] Ensure that any error encountered while coding a trigger program is transfered to the main Parse structure before it is used with any other routine that might set the error code. FossilOrigin-Name: 4293656578811b500786335de7cc9ac0d6ccc6fb273b9419a86968a095404c43 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/trigger.c | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 4e48b7001b..9a2da6c65e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Limit\sCLI\sinput\sredirect\snesting -D 2022-01-24T06:36:16.156 +C Ensure\sthat\sany\serror\sencountered\swhile\scoding\sa\strigger\sprogram\sis\stransfered\sto\sthe\smain\sParse\sstructure\sbefore\sit\sis\sused\swith\sany\sother\sroutine\sthat\smight\sset\sthe\serror\scode. +D 2022-01-24T11:25:42.955 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -618,7 +618,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446 F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc -F src/trigger.c 40e7c3dcff57a770d5fa38ba21ed4725572fd2e224c58af61eb980598b60f9c8 +F src/trigger.c d10464bac5f1a54479be3976c9e3cbc5b5385608c2aa9c880938dbef88cd0289 F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e4caf1e3932b1bd0dea072df7fc9458aed98c84ea397b6948b89292603949c41 -R 3ff059f17b79f35a7110343334a8c695 -U larrybr -Z 22bca9d238f29be7cbeeb6418fbc3f83 +P 7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5 +R 2c794efafa2baf650e28d5560fcf6b32 +U dan +Z 46c0ff7b58abcbc9cadf1ff176f24b16 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b9b364e4c1..33ce9be0fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5 \ No newline at end of file +4293656578811b500786335de7cc9ac0d6ccc6fb273b9419a86968a095404c43 \ No newline at end of file diff --git a/src/trigger.c b/src/trigger.c index 6b71c9816e..3abfb1ba62 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -1179,6 +1179,7 @@ static TriggerPrg *codeRowTrigger( /* Code the trigger program into the sub-vdbe. */ codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); + transferParseError(pParse, pSubParse); /* Insert an OP_Halt at the end of the sub-program. */ if( iEndTrigger ){ @@ -1187,7 +1188,6 @@ static TriggerPrg *codeRowTrigger( sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); - transferParseError(pParse, pSubParse); if( db->mallocFailed==0 && pParse->nErr==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } From 3cdb1394b936cbf139d441628de7533efa895cc3 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 12:48:54 +0000 Subject: [PATCH 20/28] Make sure the sqlite3OomFault() routine sets an error in the Parse object if there is a Parse object active and linked to the database connection. FossilOrigin-Name: ad7aace761c6b21ba453eaf43c68d985be7cbd5a200fe0d2e27a0c7150f99874 --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/build.c | 2 +- src/malloc.c | 11 ++++++++++- src/select.c | 2 +- src/sqliteInt.h | 2 +- 6 files changed, 24 insertions(+), 15 deletions(-) diff --git a/manifest b/manifest index 9a2da6c65e..cabe56d8bc 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Ensure\sthat\sany\serror\sencountered\swhile\scoding\sa\strigger\sprogram\sis\stransfered\sto\sthe\smain\sParse\sstructure\sbefore\sit\sis\sused\swith\sany\sother\sroutine\sthat\smight\sset\sthe\serror\scode. -D 2022-01-24T11:25:42.955 +C Make\ssure\sthe\ssqlite3OomFault()\sroutine\ssets\san\serror\sin\sthe\sParse\sobject\nif\sthere\sis\sa\sParse\sobject\sactive\sand\slinked\sto\sthe\sdatabase\sconnection. +D 2022-01-24T12:48:54.349 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 -F src/build.c c72407a27a28982a384cd453a3a6b6992a1ceae8bd8d95e96d7fb9c0d645a32f +F src/build.c cd208d7f69318455267f1860f4af30aab459263dd789dcf934dff2107fa2564b F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 @@ -517,7 +517,7 @@ F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 657534339585ac234839e5187aa51d8802f292e0771c4f874b3af1f1223f81e2 F src/main.c 2b6b0dbfeb14d4bb57e368604b0736b2aa42b51b00339d399b01d6b1fc9b4960 -F src/malloc.c ef796bcc0e81d845d59a469f1cf235056caf9024172fd524e32136e65593647b +F src/malloc.c fec841aa0a0400a6f7d20706178a5d8e8219a6bf562b6fe712c17f6c26813266 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 F src/mem1.c c12a42539b1ba105e3707d0e628ad70e611040d8f5e38cf942cee30c867083de F src/mem2.c c8bfc9446fd0798bddd495eb5d9dbafa7d4b7287d8c22d50a83ac9daa26d8a75 @@ -552,12 +552,12 @@ F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c ab5717255420972e69b9b9ce4d1c4730fe82cfbdc14b7743e389a8bdb79ca027 +F src/select.c 70cdf84cdc17ebbe52422bd541593e09fcc56b2774b6b187bcf1d1feb93777a9 F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2 F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a -F src/sqliteInt.h 21a31abf60222f50c1d654cdc27ad9d4040249f0341129dd8286b8b5b32bcd30 +F src/sqliteInt.h 911022922c6f365d094251be68e57c3bef0cdaed587924fe1317a105f1f948de F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7a073931752d16ba71f1a606091461e427ca5ccf4d135d3c5141bfdd4e67e2d5 -R 2c794efafa2baf650e28d5560fcf6b32 -U dan -Z 46c0ff7b58abcbc9cadf1ff176f24b16 +P 4293656578811b500786335de7cc9ac0d6ccc6fb273b9419a86968a095404c43 +R 16f6390f1012ef4b9a88926fe083a45b +U drh +Z 6779c79f6c6ab94095c102ccd63f1a53 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 33ce9be0fa..35d0499eae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4293656578811b500786335de7cc9ac0d6ccc6fb273b9419a86968a095404c43 \ No newline at end of file +ad7aace761c6b21ba453eaf43c68d985be7cbd5a200fe0d2e27a0c7150f99874 \ No newline at end of file diff --git a/src/build.c b/src/build.c index ce1c720800..af6ee4e771 100644 --- a/src/build.c +++ b/src/build.c @@ -4544,10 +4544,10 @@ void sqlite3DropIndex(Parse *pParse, SrcList *pName, int ifExists){ sqlite3 *db = pParse->db; int iDb; - assert( pParse->nErr==0 ); /* Never called with prior errors */ if( db->mallocFailed ){ goto exit_drop_index; } + assert( pParse->nErr==0 ); /* Never called with prior non-OOM errors */ assert( pName->nSrc==1 ); if( SQLITE_OK!=sqlite3ReadSchema(pParse) ){ goto exit_drop_index; diff --git a/src/malloc.c b/src/malloc.c index 932cecc210..21e5245891 100644 --- a/src/malloc.c +++ b/src/malloc.c @@ -759,8 +759,15 @@ void sqlite3SetString(char **pz, sqlite3 *db, const char *zNew){ ** has happened. This routine will set db->mallocFailed, and also ** temporarily disable the lookaside memory allocator and interrupt ** any running VDBEs. +** +** Always return a NULL pointer so that this routine can be invoked using +** +** return sqlite3OomFault(db); +** +** and thereby avoid unnecessary stack frame allocations for the overwhelmingly +** common case where no OOM occurs. */ -void sqlite3OomFault(sqlite3 *db){ +void *sqlite3OomFault(sqlite3 *db){ if( db->mallocFailed==0 && db->bBenignMalloc==0 ){ db->mallocFailed = 1; if( db->nVdbeExec>0 ){ @@ -768,9 +775,11 @@ void sqlite3OomFault(sqlite3 *db){ } DisableLookaside; if( db->pParse ){ + sqlite3ErrorMsg(db->pParse, "out of memory"); db->pParse->rc = SQLITE_NOMEM_BKPT; } } + return 0; } /* diff --git a/src/select.c b/src/select.c index a0fc3d90f5..da3c78009e 100644 --- a/src/select.c +++ b/src/select.c @@ -1404,7 +1404,7 @@ KeyInfo *sqlite3KeyInfoAlloc(sqlite3 *db, int N, int X){ p->nRef = 1; memset(&p[1], 0, nExtra); }else{ - sqlite3OomFault(db); + return (KeyInfo*)sqlite3OomFault(db); } return p; } diff --git a/src/sqliteInt.h b/src/sqliteInt.h index a2724f5828..7fd0d81d09 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -4975,7 +4975,7 @@ int sqlite3CreateFunc(sqlite3 *, const char *, int, int, void *, FuncDestructor *pDestructor ); void sqlite3NoopDestructor(void*); -void sqlite3OomFault(sqlite3*); +void *sqlite3OomFault(sqlite3*); void sqlite3OomClear(sqlite3*); int sqlite3ApiExit(sqlite3 *db, int); int sqlite3OpenTempDatabase(Parse *); From b5d44732214816116942ac27ebcb062542b31296 Mon Sep 17 00:00:00 2001 From: larrybr Date: Mon, 24 Jan 2022 14:01:31 +0000 Subject: [PATCH 21/28] Fix testcase for CLI .read recursion. FossilOrigin-Name: 53d4404458fb6f0b6b2b69c2225d66b39f09099c356ba3c3e990474f14aba31a --- manifest | 14 +++++++------- manifest.uuid | 2 +- test/shell4.test | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index cabe56d8bc..f1918bccb3 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\ssure\sthe\ssqlite3OomFault()\sroutine\ssets\san\serror\sin\sthe\sParse\sobject\nif\sthere\sis\sa\sParse\sobject\sactive\sand\slinked\sto\sthe\sdatabase\sconnection. -D 2022-01-24T12:48:54.349 +C Fix\stestcase\sfor\sCLI\s.read\srecursion. +D 2022-01-24T14:01:31.089 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1388,7 +1388,7 @@ F test/sharedlock.test 5ede3c37439067c43b0198f580fd374ebf15d304 F test/shell1.test 70f46b5d07776a107335c3c2c9cbd0431d44637bfeae1f6b9ded5e33b4c7c0bf F test/shell2.test f00a0501c00583cbc46f7510e1d713366326b2b3e63d06d15937284171a8787c F test/shell3.test cb4b835a901742c9719437a89171172ecc4a8823ad97349af8e4e841e6f82566 -F test/shell4.test 8427e08751d4b16100fadb29f109cc1b8cce5c3858bdf34837c6e3b35fbbfee7 +F test/shell4.test 8f6c0fce4abed19a8a7f7262517149812a04caa905d01bdc8f5e92573504b759 F test/shell5.test b85069bfcf3159b225228629ab2c3e69aa923d098fea8ea074b5dcd743522e2c F test/shell6.test 1ceb51b2678c472ba6cf1e5da96679ce8347889fe2c3bf93a0e0fa73f00b00d3 F test/shell7.test 115132f66d0463417f408562cc2cf534f6bbc6d83a6d50f0072a9eb171bae97f @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4293656578811b500786335de7cc9ac0d6ccc6fb273b9419a86968a095404c43 -R 16f6390f1012ef4b9a88926fe083a45b -U drh -Z 6779c79f6c6ab94095c102ccd63f1a53 +P ad7aace761c6b21ba453eaf43c68d985be7cbd5a200fe0d2e27a0c7150f99874 +R 58fcdcfd00f4bb8a2367d551006829a9 +U larrybr +Z bbbe6164ac758b645539901355118a69 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 35d0499eae..0d6cbc5cc3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ad7aace761c6b21ba453eaf43c68d985be7cbd5a200fe0d2e27a0c7150f99874 \ No newline at end of file +53d4404458fb6f0b6b2b69c2225d66b39f09099c356ba3c3e990474f14aba31a \ No newline at end of file diff --git a/test/shell4.test b/test/shell4.test index 1be2c1d9ac..ee7d2b856f 100644 --- a/test/shell4.test +++ b/test/shell4.test @@ -144,6 +144,6 @@ do_test shell4-4.1 { puts $fd ".read t1.txt" close $fd catchcmd ":memory:" ".read t1.txt" -} {1 {Input nesting limit (25) reached at line 1. Watch recursion.}} +} {1 {Input nesting limit (25) reached at line 1. Check recursion.}} finish_test From c692df2784db52587fdf2a2ae20340ad8e7fc034 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 15:34:55 +0000 Subject: [PATCH 22/28] Make it so that any Parse object is always linked into the database conenction while it is active. Hence, an OOM will cause Parse.nErr to be set. FossilOrigin-Name: 6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec --- manifest | 28 ++++++++++++++-------------- manifest.uuid | 2 +- src/alter.c | 4 ++-- src/backup.c | 5 ++--- src/prepare.c | 34 +++++++++++++++++++++++++++++----- src/sqliteInt.h | 7 +++++-- src/trigger.c | 44 ++++++++++++++++++++------------------------ src/util.c | 2 ++ src/vdbeblob.c | 11 ++++++----- src/vtab.c | 5 ++--- 10 files changed, 83 insertions(+), 59 deletions(-) diff --git a/manifest b/manifest index f1918bccb3..61845611c0 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stestcase\sfor\sCLI\s.read\srecursion. -D 2022-01-24T14:01:31.089 +C Make\sit\sso\sthat\sany\sParse\sobject\sis\salways\slinked\sinto\sthe\sdatabase\sconenction\nwhile\sit\sis\sactive.\s\sHence,\san\sOOM\swill\scause\sParse.nErr\sto\sbe\sset. +D 2022-01-24T15:34:55.523 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -485,11 +485,11 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c e3943d8fbcaf60f79f39d4aecc56a6a8092f51f93d6a7c5b1db2633c5fa10c30 +F src/alter.c d5b1083127d4e1c5b0a50155d6b15c009db81d1fab17e39d28a9268922c2f752 F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516 F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf -F src/backup.c 3014889fa06e20e6adfa0d07b60097eec1f6e5b06671625f476a714d2356513d +F src/backup.c 58880b9a9adf88f1a57cb3b0db6b891626ae76113ebd0f2417a87c2634edfc65 F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 @@ -547,7 +547,7 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 F src/pragma.c c536665ce8431c8b1efbf7e0a5c01852f49f7bf28f1954f8118b2d28e4a3797f F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad -F src/prepare.c 45fe7408eb78d80eca8392669070a6e5caf231b09e5c7b1ff65c1ad64a3734c5 +F src/prepare.c 4ab9c3c716aaaa98b7985870e0b7631045dff1cea6ce814165ba8f4363dd43f7 F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 @@ -557,7 +557,7 @@ F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 5d54cf13d3406d8eb65d921a0d3c349de6126b732e695e79ecd4830ce86b4f8a -F src/sqliteInt.h 911022922c6f365d094251be68e57c3bef0cdaed587924fe1317a105f1f948de +F src/sqliteInt.h 33fbafb55b48f63b791c563378345ebdbbcb73e8fd63a1c22e4df05f435d4714 F src/sqliteLimit.h d7323ffea5208c6af2734574bae933ca8ed2ab728083caa117c9738581a31657 F src/status.c 4b8bc2a6905163a38b739854a35b826c737333fab5b1f8e03fa7eb9a4799c4c1 F src/table.c 0f141b58a16de7e2fbe81c308379e7279f4c6b50eb08efeec5892794a0ba30d1 @@ -618,23 +618,23 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446 F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc -F src/trigger.c d10464bac5f1a54479be3976c9e3cbc5b5385608c2aa9c880938dbef88cd0289 +F src/trigger.c 6732a95d132e5fe30e02f87fe94fdb245840c2a870d8ce08c37aab3a2f13f387 F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 -F src/util.c 89e51820bcb468ff3877a8d942f5cc807208087f021227e0927693e928a195bc +F src/util.c 0d0b9c58f117fa98192c6d340c20fd73ce58ae33687e3a133b1fb623b96e0cbd F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 F src/vdbe.c cfe1980fbeb87eb35297b4a41808034761f26277cf45c9cf3e4eac20edcba1d5 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5 F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a F src/vdbeaux.c c1b452cc17f5887b3d36bc277a2181914d6bed508ea45827b5f348160491e6a6 -F src/vdbeblob.c 29c4118f7ee615cdee829e8401f6ead1b96b95d545b4de0042f6de39c962c652 +F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd F src/vdbemem.c da4d594084d581be6436582bb44bb128feeb138a3e6c313eda6749ebdc3a65ec F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35 F src/vdbetrace.c fe0bc29ebd4e02c8bc5c1945f1d2e6be5927ec12c06d89b03ef2a4def34bf823 F src/vdbevtab.c f99b275366c5fc5e2d99f734729880994ab9500bdafde7fae3b02d562b9d323c -F src/vtab.c a47cc12ebaa350800c0c87b6b0095debbb5a6ed32727bcab9d82ad070a81b738 +F src/vtab.c e0eaf5b8f7f8929088485a76bea2ff6124adb12e0eb5c0997287ff5e0e4c0517 F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ad7aace761c6b21ba453eaf43c68d985be7cbd5a200fe0d2e27a0c7150f99874 -R 58fcdcfd00f4bb8a2367d551006829a9 -U larrybr -Z bbbe6164ac758b645539901355118a69 +P 53d4404458fb6f0b6b2b69c2225d66b39f09099c356ba3c3e990474f14aba31a +R db714556249a893e75568fc6543a6157 +U drh +Z 5562b6696e73f05014591d4075c2e3ff # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 0d6cbc5cc3..54f0236036 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -53d4404458fb6f0b6b2b69c2225d66b39f09099c356ba3c3e990474f14aba31a \ No newline at end of file +6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 28efd28722..096b54c042 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1132,7 +1132,7 @@ static int renameParseSql( /* Parse the SQL statement passed as the first argument. If no error ** occurs and the parse does not result in a new table, index or ** trigger object, the database must be corrupt. */ - memset(p, 0, sizeof(Parse)); + sqlite3ParseObjectInit(p, db); p->eParseMode = PARSE_MODE_RENAME; p->db = db; p->nQueryLoop = 1; @@ -1417,7 +1417,7 @@ static void renameParseCleanup(Parse *pParse){ sqlite3DeleteTrigger(db, pParse->pNewTrigger); sqlite3DbFree(db, pParse->zErrMsg); renameTokenFree(db, pParse->pRename); - sqlite3ParserReset(pParse); + sqlite3ParseObjectReset(pParse); } /* diff --git a/src/backup.c b/src/backup.c index 2b286de6bd..bfd155bcac 100644 --- a/src/backup.c +++ b/src/backup.c @@ -85,14 +85,13 @@ static Btree *findBtree(sqlite3 *pErrorDb, sqlite3 *pDb, const char *zDb){ if( i==1 ){ Parse sParse; int rc = 0; - memset(&sParse, 0, sizeof(sParse)); - sParse.db = pDb; + sqlite3ParseObjectInit(&sParse,pErrorDb); if( sqlite3OpenTempDatabase(&sParse) ){ sqlite3ErrorWithMsg(pErrorDb, sParse.rc, "%s", sParse.zErrMsg); rc = SQLITE_ERROR; } sqlite3DbFree(pErrorDb, sParse.zErrMsg); - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); if( rc ){ return 0; } diff --git a/src/prepare.c b/src/prepare.c index d2cc2d098c..56505a7174 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -568,7 +568,7 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ /* ** Free all memory allocations in the pParse object */ -void sqlite3ParserReset(Parse *pParse){ +void sqlite3ParseObjectReset(Parse *pParse){ sqlite3 *db = pParse->db; assert( pParse->nested==0 ); #ifndef SQLITE_OMIT_SHARED_CACHE @@ -588,6 +588,9 @@ void sqlite3ParserReset(Parse *pParse){ assert( db->lookaside.bDisable >= pParse->disableLookaside ); db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; + assert( pParse->db->pParse==pParse ); + pParse->db->pParse = pParse->pOuterParse; + pParse->db = 0; } pParse->disableLookaside = 0; } @@ -601,7 +604,7 @@ void sqlite3ParserReset(Parse *pParse){ ** cost for this mechansim (an extra malloc), so it should not be used ** for common cleanups that happen on most calls. But for less ** common cleanups, we save a single NULL-pointer comparison in -** sqlite3ParserReset(), which reduces the total CPU cycle count. +** sqlite3ParseObjectReset(), which reduces the total CPU cycle count. ** ** If a memory allocation error occurs, then the cleanup happens immediately. ** When either SQLITE_DEBUG or SQLITE_COVERAGE_TEST are defined, the @@ -641,6 +644,24 @@ void *sqlite3ParserAddCleanup( return pPtr; } +/* +** Turn bulk memory into a valid Parse object and link that Parse object +** into database connection db. +** +** Call sqlite3ParseObjectReset() to undo this operation. +** +** Caution: Do not confuse this routine with sqlite3ParseObjectInit() which +** is generated by Lemon. +*/ +void sqlite3ParseObjectInit(Parse *pParse, sqlite3 *db){ + memset(PARSE_HDR(pParse), 0, PARSE_HDR_SZ); + memset(PARSE_TAIL(pParse), 0, PARSE_TAIL_SZ); + assert( db->pParse!=pParse ); + pParse->pOuterParse = db->pParse; + db->pParse = pParse; + pParse->db = db; +} + /* ** Compile the UTF-8 encoded SQL statement zSql into a statement handle. */ @@ -657,8 +678,12 @@ static int sqlite3Prepare( int i; /* Loop counter */ Parse sParse; /* Parsing context */ - memset(&sParse, 0, PARSE_HDR_SZ); + /* sqlite3ParseObjectInit(&sParse, db); // inlined for performance */ + memset(PARSE_HDR(&sParse), 0, PARSE_HDR_SZ); memset(PARSE_TAIL(&sParse), 0, PARSE_TAIL_SZ); + sParse.pOuterParse = db->pParse; + db->pParse = &sParse; + sParse.db = db; sParse.pReprepare = pReprepare; assert( ppStmt && *ppStmt==0 ); /* assert( !db->mallocFailed ); // not true with SQLITE_USE_ALLOCA */ @@ -714,7 +739,6 @@ static int sqlite3Prepare( sqlite3VtabUnlockList(db); - sParse.db = db; if( nBytes>=0 && (nBytes==0 || zSql[nBytes-1]!=0) ){ char *zSqlCopy; int mxLen = db->aLimit[SQLITE_LIMIT_SQL_LENGTH]; @@ -781,7 +805,7 @@ static int sqlite3Prepare( end_prepare: - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); return rc; } static int sqlite3LockAndPrepare( diff --git a/src/sqliteInt.h b/src/sqliteInt.h index 7fd0d81d09..7a266403fb 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -3585,6 +3585,7 @@ struct Parse { **************************************************************************/ int aTempReg[8]; /* Holding area for temporary registers */ + Parse *pOuterParse; /* Outer Parse object when nested */ Token sNameToken; /* Token with unqualified schema object name */ /************************************************************************ @@ -3635,7 +3636,8 @@ struct Parse { /* ** Sizes and pointers of various parts of the Parse object. */ -#define PARSE_HDR_SZ offsetof(Parse,aTempReg) /* Recursive part w/o aColCache*/ +#define PARSE_HDR(X) (((char*)(X))+offsetof(Parse,zErrMsg)) +#define PARSE_HDR_SZ (offsetof(Parse,aTempReg)-offsetof(Parse,zErrMsg)) /* Recursive part w/o aColCache*/ #define PARSE_RECURSE_SZ offsetof(Parse,sLastToken) /* Recursive part */ #define PARSE_TAIL_SZ (sizeof(Parse)-PARSE_RECURSE_SZ) /* Non-recursive part */ #define PARSE_TAIL(X) (((char*)(X))+PARSE_RECURSE_SZ) /* Pointer to tail */ @@ -5096,7 +5098,8 @@ FuncDef *sqlite3VtabOverloadFunction(sqlite3 *,FuncDef*, int nArg, Expr*); sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); -void sqlite3ParserReset(Parse*); +void sqlite3ParseObjectInit(Parse*,sqlite3*); +void sqlite3ParseObjectReset(Parse*); void *sqlite3ParserAddCleanup(Parse*,void(*)(sqlite3*,void*),void*); #ifdef SQLITE_ENABLE_NORMALIZE char *sqlite3Normalize(Vdbe*, const char*); diff --git a/src/trigger.c b/src/trigger.c index 3abfb1ba62..19e22abcfd 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -1110,8 +1110,8 @@ static TriggerPrg *codeRowTrigger( Vdbe *v; /* Temporary VM */ NameContext sNC; /* Name context for sub-vdbe */ SubProgram *pProgram = 0; /* Sub-vdbe for trigger program */ - Parse *pSubParse; /* Parse context for sub-vdbe */ int iEndTrigger = 0; /* Label to jump to if WHEN is false */ + Parse sSubParse; /* Parse context for sub-vdbe */ assert( pTrigger->zName==0 || pTab==tableOfTrigger(pTrigger) ); assert( pTop->pVdbe ); @@ -1133,19 +1133,17 @@ static TriggerPrg *codeRowTrigger( /* Allocate and populate a new Parse context to use for coding the ** trigger sub-program. */ - pSubParse = sqlite3StackAllocZero(db, sizeof(Parse)); - if( !pSubParse ) return 0; + sqlite3ParseObjectInit(&sSubParse, db); memset(&sNC, 0, sizeof(sNC)); - sNC.pParse = pSubParse; - pSubParse->db = db; - pSubParse->pTriggerTab = pTab; - pSubParse->pToplevel = pTop; - pSubParse->zAuthContext = pTrigger->zName; - pSubParse->eTriggerOp = pTrigger->op; - pSubParse->nQueryLoop = pParse->nQueryLoop; - pSubParse->disableVtab = pParse->disableVtab; + sNC.pParse = &sSubParse; + sSubParse.pTriggerTab = pTab; + sSubParse.pToplevel = pTop; + sSubParse.zAuthContext = pTrigger->zName; + sSubParse.eTriggerOp = pTrigger->op; + sSubParse.nQueryLoop = pParse->nQueryLoop; + sSubParse.disableVtab = pParse->disableVtab; - v = sqlite3GetVdbe(pSubParse); + v = sqlite3GetVdbe(&sSubParse); if( v ){ VdbeComment((v, "Start: %s.%s (%s %s%s%s ON %s)", pTrigger->zName, onErrorText(orconf), @@ -1171,15 +1169,14 @@ static TriggerPrg *codeRowTrigger( if( db->mallocFailed==0 && SQLITE_OK==sqlite3ResolveExprNames(&sNC, pWhen) ){ - iEndTrigger = sqlite3VdbeMakeLabel(pSubParse); - sqlite3ExprIfFalse(pSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); + iEndTrigger = sqlite3VdbeMakeLabel(&sSubParse); + sqlite3ExprIfFalse(&sSubParse, pWhen, iEndTrigger, SQLITE_JUMPIFNULL); } sqlite3ExprDelete(db, pWhen); } /* Code the trigger program into the sub-vdbe. */ - codeTriggerProgram(pSubParse, pTrigger->step_list, orconf); - transferParseError(pParse, pSubParse); + codeTriggerProgram(&sSubParse, pTrigger->step_list, orconf); /* Insert an OP_Halt at the end of the sub-program. */ if( iEndTrigger ){ @@ -1187,22 +1184,21 @@ static TriggerPrg *codeRowTrigger( } sqlite3VdbeAddOp0(v, OP_Halt); VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); + transferParseError(pParse, &sSubParse); if( db->mallocFailed==0 && pParse->nErr==0 ){ pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } - pProgram->nMem = pSubParse->nMem; - pProgram->nCsr = pSubParse->nTab; + pProgram->nMem = sSubParse.nMem; + pProgram->nCsr = sSubParse.nTab; pProgram->token = (void *)pTrigger; - pPrg->aColmask[0] = pSubParse->oldmask; - pPrg->aColmask[1] = pSubParse->newmask; + pPrg->aColmask[0] = sSubParse.oldmask; + pPrg->aColmask[1] = sSubParse.newmask; sqlite3VdbeDelete(v); } - assert( !pSubParse->pTriggerPrg && !pSubParse->nMaxArg ); - sqlite3ParserReset(pSubParse); - sqlite3StackFree(db, pSubParse); - + assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg ); + sqlite3ParseObjectReset(&sSubParse); return pPrg; } diff --git a/src/util.c b/src/util.c index dec205df43..002cf65739 100644 --- a/src/util.c +++ b/src/util.c @@ -189,6 +189,8 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ char *zMsg; va_list ap; sqlite3 *db = pParse->db; + assert( db!=0 ); + assert( db->pParse==pParse ); db->errByteOffset = -2; va_start(ap, zFormat); zMsg = sqlite3VMPrintf(db, zFormat, ap); diff --git a/src/vdbeblob.c b/src/vdbeblob.c index 512442fd2a..a18ee05b52 100644 --- a/src/vdbeblob.c +++ b/src/vdbeblob.c @@ -152,10 +152,9 @@ int sqlite3_blob_open( sqlite3_mutex_enter(db->mutex); pBlob = (Incrblob *)sqlite3DbMallocZero(db, sizeof(Incrblob)); - do { - memset(&sParse, 0, sizeof(Parse)); + while(1){ + sqlite3ParseObjectInit(&sParse,db); if( !pBlob ) goto blob_open_out; - sParse.db = db; sqlite3DbFree(db, zErr); zErr = 0; @@ -332,7 +331,9 @@ int sqlite3_blob_open( goto blob_open_out; } rc = blobSeekToRow(pBlob, iRow, &zErr); - } while( (++nAttempt)=SQLITE_MAX_SCHEMA_RETRY || rc!=SQLITE_SCHEMA ) break; + sqlite3ParseObjectReset(&sParse); + } blob_open_out: if( rc==SQLITE_OK && db->mallocFailed==0 ){ @@ -343,7 +344,7 @@ blob_open_out: } sqlite3ErrorWithMsg(db, rc, (zErr ? "%s" : 0), zErr); sqlite3DbFree(db, zErr); - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); rc = sqlite3ApiExit(db, rc); sqlite3_mutex_leave(db->mutex); return rc; diff --git a/src/vtab.c b/src/vtab.c index ef86dd6bd4..11c076e4e6 100644 --- a/src/vtab.c +++ b/src/vtab.c @@ -825,9 +825,8 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ pTab = pCtx->pTab; assert( IsVirtual(pTab) ); - memset(&sParse, 0, sizeof(sParse)); + sqlite3ParseObjectInit(&sParse, db); sParse.eParseMode = PARSE_MODE_DECLARE_VTAB; - sParse.db = db; /* We should never be able to reach this point while loading the ** schema. Nevertheless, defend against that (turn off db->init.busy) ** in case a bug arises. */ @@ -881,7 +880,7 @@ int sqlite3_declare_vtab(sqlite3 *db, const char *zCreateTable){ sqlite3VdbeFinalize(sParse.pVdbe); } sqlite3DeleteTable(db, sParse.pNewTable); - sqlite3ParserReset(&sParse); + sqlite3ParseObjectReset(&sParse); db->init.busy = initBusy; assert( (rc&0xff)==rc ); From 0c7d3d399d4706db18789dbd50466e4d589e5fcd Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 16:47:12 +0000 Subject: [PATCH 23/28] Remove many redundant checks for sqlite3.mallocFailed now that any OOM should cause Parse.nErr to be non-zero. FossilOrigin-Name: 1f7fa46126ea33ed30e93186aff3df51068aeb4be6f79a102bfe8c4e44941d71 --- manifest | 40 ++++++++++++++++++++-------------------- manifest.uuid | 2 +- src/alter.c | 8 ++++++-- src/build.c | 19 ++++++++++++------- src/delete.c | 4 +++- src/expr.c | 3 +-- src/insert.c | 8 ++++++-- src/pragma.c | 4 ++++ src/prepare.c | 2 +- src/resolve.c | 8 +++++--- src/select.c | 23 +++++++++++++++-------- src/trigger.c | 11 ++++++++--- src/update.c | 4 +++- src/util.c | 4 ++++ src/vdbeaux.c | 3 +-- src/where.c | 3 ++- src/wherecode.c | 5 +++-- 17 files changed, 95 insertions(+), 56 deletions(-) diff --git a/manifest b/manifest index 61845611c0..36b1c6271f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Make\sit\sso\sthat\sany\sParse\sobject\sis\salways\slinked\sinto\sthe\sdatabase\sconenction\nwhile\sit\sis\sactive.\s\sHence,\san\sOOM\swill\scause\sParse.nErr\sto\sbe\sset. -D 2022-01-24T15:34:55.523 +C Remove\smany\sredundant\schecks\sfor\ssqlite3.mallocFailed\snow\sthat\sany\sOOM\sshould\ncause\sParse.nErr\sto\sbe\snon-zero. +D 2022-01-24T16:47:12.063 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -485,7 +485,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c d5b1083127d4e1c5b0a50155d6b15c009db81d1fab17e39d28a9268922c2f752 +F src/alter.c e8ac1df663bf4ec74920edd1299435f2a616d2404de0ac4013c151ea4e7a11f2 F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516 F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf @@ -495,15 +495,15 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 -F src/build.c cd208d7f69318455267f1860f4af30aab459263dd789dcf934dff2107fa2564b +F src/build.c db3d3e6fa32cec976142b13c8ecd2d923016c59a5d4c3142b59749174c452748 F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 F src/date.c e25773f06a8f9043bfa1e5fa0bee93483c41933adfff0891752f00eadd12ab1c F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d -F src/delete.c 19814f621cde10b1771a0dea7fe25d3d7d39975b8d4be4888537d30860e7c08c -F src/expr.c 827179c78d2ca7cc318392811de8151c60eacf7ce804b13e61bb7ef38f954846 +F src/delete.c 52897a8516dc40753503c25eed0e305f09cc50ae474f22b0b4fd31d3b879cc08 +F src/expr.c da0ba8a4cf142dbd595d40bc09663994b9ae6b1ea7b85fa2c84e4951bce7b054 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560 F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776 @@ -512,7 +512,7 @@ F src/hash.c 8d7dda241d0ebdafb6ffdeda3149a412d7df75102cecfc1021c98d6219823b19 F src/hash.h 3340ab6e1d13e725571d7cee6d3e3135f0779a7d8e76a9ce0a85971fa3953c51 F src/hwtime.h cb1d7e3e1ed94b7aa6fde95ae2c2daccc3df826be26fc9ed7fd90d1750ae6144 F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 -F src/insert.c e528416ff5d86fc5d656ea6a26f03fde39836b6175f93048c32a03cb2ee16743 +F src/insert.c 1eea44389de3768ac98588c1410171cd53e7c6ad1af74049983dcbac82093de0 F src/json.c 78fdec9af3a8bfb5ae685707b2701276fec1942b8f5f26689b2701debe32bcd2 F src/legacy.c d7874bc885906868cd51e6c2156698f2754f02d9eee1bae2d687323c3ca8e5aa F src/loadext.c 657534339585ac234839e5187aa51d8802f292e0771c4f874b3af1f1223f81e2 @@ -545,14 +545,14 @@ F src/parse.y 04f61db1cdd7036c6d74baad1c342d3e3110cb0765c48fcfd3bdf4e974a1e5bb F src/pcache.c 084e638432c610f95aea72b8509f0845d2791293f39d1b82f0c0a7e089c3bb6b F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 -F src/pragma.c c536665ce8431c8b1efbf7e0a5c01852f49f7bf28f1954f8118b2d28e4a3797f +F src/pragma.c 7c024d690a3dc93f61830f11f900e4af2357f31d081b0c79099ca5e28919cba7 F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad -F src/prepare.c 4ab9c3c716aaaa98b7985870e0b7631045dff1cea6ce814165ba8f4363dd43f7 +F src/prepare.c da7d26f51a86d09e46ecad3b656dc8e135abfcc2cf7c26b048646464606a1cf4 F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c -F src/resolve.c 359bc0e445d427583d2ab6110433a5dc777f64a0ecdf8d24826d8b475233ead9 +F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9 F src/rowset.c ba9515a922af32abe1f7d39406b9d35730ed65efab9443dc5702693b60854c92 -F src/select.c 70cdf84cdc17ebbe52422bd541593e09fcc56b2774b6b187bcf1d1feb93777a9 +F src/select.c 5799f5b15e27bcb8262caec7821f3ef89575e539237db3141be0d26cf8efd22c F src/shell.c.in e80a140e92e342e2f92d405a77155c8e3a67c9b1d0bdbacb92885960cd4fc8f2 F src/sqlite.h.in 31c2c8d737814369bd3b71f3849c4a97ef7ede0aa3ce976ecb11632fa5f1f863 F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -618,17 +618,17 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446 F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc -F src/trigger.c 6732a95d132e5fe30e02f87fe94fdb245840c2a870d8ce08c37aab3a2f13f387 -F src/update.c d6f5c7b9e072660757ac7d58175aca11c07cb95ebbb297ae7f38853700f52328 +F src/trigger.c a17cf451b8fbf6e924cb472362ef1141c0cab84db05f33b2d8bfb1c6c565ee45 +F src/update.c 7dfa3866cdfb28bf952c38054c1722720d8ff64750dea421790aecc91f640516 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 -F src/util.c 0d0b9c58f117fa98192c6d340c20fd73ce58ae33687e3a133b1fb623b96e0cbd +F src/util.c 602fe229f32a96ceccae4f40824129669582096f7c355f53dbac156c9fecef23 F src/vacuum.c 6c38ddc52f0619865c91dae9c441d4d48bf3040d7dc1bc5b22da1e45547ed0b3 F src/vdbe.c cfe1980fbeb87eb35297b4a41808034761f26277cf45c9cf3e4eac20edcba1d5 F src/vdbe.h 25dabb25c7e157b84e59260cfb5b466c3ac103ede9f36f4db371332c47601abe F src/vdbeInt.h d89d5d2150500cfb08615329fd20aea9d746bba5f2c3ecb8a17e2d2d9be029e5 F src/vdbeapi.c 22c79072ae7d8a01e9bcae8ba16e918d60d202eaa9553b5fda38f99f7464d99a -F src/vdbeaux.c c1b452cc17f5887b3d36bc277a2181914d6bed508ea45827b5f348160491e6a6 +F src/vdbeaux.c e761b8011baec7a4773f0a7594783f2cd71f699ab187c4aad917529ab8acd3fe F src/vdbeblob.c 5e61ce31aca17db8fb60395407457a8c1c7fb471dde405e0cd675974611dcfcd F src/vdbemem.c da4d594084d581be6436582bb44bb128feeb138a3e6c313eda6749ebdc3a65ec F src/vdbesort.c 43756031ca7430f7aec3ef904824a7883c4ede783e51f280d99b9b65c0796e35 @@ -639,9 +639,9 @@ F src/vxworks.h d2988f4e5a61a4dfe82c6524dd3d6e4f2ce3cdb9 F src/wal.c b9df133a705093da8977da5eb202eaadb844839f1c7297c08d33471f5491843d F src/wal.h c3aa7825bfa2fe0d85bef2db94655f99870a285778baa36307c0a16da32b226a F src/walker.c f890a3298418d7cba3b69b8803594fdc484ea241206a8dfa99db6dd36f8cbb3b -F src/where.c 9824d15f2a92cbe4d6566e2a97fa4466ce6297e68693322e64281db5e942fa92 +F src/where.c a14990c7b35e95f8f9cb0dc0d6d2e32fa99135a716a04027cefa48138d280ecb F src/whereInt.h 8a215acde0f833a4dea3d30a7bbed9f48b4b547b5d5e34cd02acee366476ab80 -F src/wherecode.c a0a5138b28550dd95916435283c507aa6bf24607ef38a0a18011e6626684330a +F src/wherecode.c 8da0f873278ed6aad42bf2028404d7178dd9cfcdc7179ecc61a87591a15a07d2 F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 53d4404458fb6f0b6b2b69c2225d66b39f09099c356ba3c3e990474f14aba31a -R db714556249a893e75568fc6543a6157 +P 6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec +R c6a1e6f8a20313848dd96ff038c5eea1 U drh -Z 5562b6696e73f05014591d4075c2e3ff +Z 9cd720c9eb51a2f1a38e40423c81c52f # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 54f0236036..868bad5ed8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec \ No newline at end of file +1f7fa46126ea33ed30e93186aff3df51068aeb4be6f79a102bfe8c4e44941d71 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 096b54c042..4de7cc51d3 100644 --- a/src/alter.c +++ b/src/alter.c @@ -324,7 +324,9 @@ void sqlite3AlterFinishAddColumn(Parse *pParse, Token *pColDef){ int r1; /* Temporary registers */ db = pParse->db; - if( pParse->nErr || db->mallocFailed ) return; + assert( db->pParse==pParse ); + if( pParse->nErr ) return; + assert( db->mallocFailed==0 ); pNew = pParse->pNewTable; assert( pNew ); @@ -735,7 +737,9 @@ struct RenameCtx { ** following a valid object, it may not be used in comparison operations. */ static void renameTokenCheckAll(Parse *pParse, const void *pPtr){ - if( pParse->nErr==0 && pParse->db->mallocFailed==0 ){ + assert( pParse==pParse->db->pParse ); + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); + if( pParse->nErr==0 ){ const RenameToken *p; u8 i = 0; for(p=pParse->pRename; p; p=p->pNext){ diff --git a/src/build.c b/src/build.c index af6ee4e771..d37ff84e83 100644 --- a/src/build.c +++ b/src/build.c @@ -143,11 +143,13 @@ void sqlite3FinishCoding(Parse *pParse){ assert( pParse->pToplevel==0 ); db = pParse->db; + assert( db->pParse==pParse ); if( pParse->nested ) return; - if( db->mallocFailed || pParse->nErr ){ + if( pParse->nErr ){ if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; return; } + assert( db->mallocFailed==0 ); /* Begin by generating some termination code at the end of the ** vdbe program @@ -280,7 +282,7 @@ void sqlite3FinishCoding(Parse *pParse){ /* Get the VDBE program ready for execution */ - if( v && pParse->nErr==0 && !db->mallocFailed ){ + if( pParse->nErr==0 && ALWAYS(v) && ALWAYS(!db->mallocFailed) ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ assert( pParse->pAinc==0 || pParse->nTab>0 ); @@ -2384,10 +2386,11 @@ static void convertToWithoutRowidTable(Parse *pParse, Table *pTab){ pTab->iPKey = -1; sqlite3CreateIndex(pParse, 0, 0, 0, pList, pTab->keyConf, 0, 0, 0, 0, SQLITE_IDXTYPE_PRIMARYKEY); - if( db->mallocFailed || pParse->nErr ){ + if( pParse->nErr ){ pTab->tabFlags &= ~TF_WithoutRowid; return; } + assert( db->mallocFailed==0 ); pPk = sqlite3PrimaryKeyIndex(pTab); assert( pPk->nKeyCol==1 ); }else{ @@ -3128,10 +3131,10 @@ int sqlite3ViewGetColumnNames(Parse *pParse, Table *pTable){ */ sqlite3ColumnsFromExprList(pParse, pTable->pCheck, &pTable->nCol, &pTable->aCol); - if( db->mallocFailed==0 - && pParse->nErr==0 + if( pParse->nErr==0 && pTable->nCol==pSel->pEList->nExpr ){ + assert( db->mallocFailed==0 ); sqlite3SelectAddColumnTypeAndCollation(pParse, pTable, pSel, SQLITE_AFF_NONE); } @@ -3750,7 +3753,7 @@ static void sqlite3RefillIndex(Parse *pParse, Index *pIndex, int memRootPage){ tnum = pIndex->tnum; } pKey = sqlite3KeyInfoOfIndex(pParse, pIndex); - assert( pKey!=0 || db->mallocFailed || pParse->nErr ); + assert( pKey!=0 || pParse->nErr ); /* Open the sorter cursor if we are to use one. */ iSorter = pParse->nTab++; @@ -3914,9 +3917,11 @@ void sqlite3CreateIndex( char *zExtra = 0; /* Extra space after the Index object */ Index *pPk = 0; /* PRIMARY KEY index for WITHOUT ROWID tables */ - if( db->mallocFailed || pParse->nErr>0 ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto exit_create_index; } + assert( db->mallocFailed==0 ); if( IN_DECLARE_VTAB && idxType!=SQLITE_IDXTYPE_PRIMARYKEY ){ goto exit_create_index; } diff --git a/src/delete.c b/src/delete.c index 9c56858e79..b51e038918 100644 --- a/src/delete.c +++ b/src/delete.c @@ -293,9 +293,11 @@ void sqlite3DeleteFrom( memset(&sContext, 0, sizeof(sContext)); db = pParse->db; - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto delete_from_cleanup; } + assert( db->mallocFailed==0 ); assert( pTabList->nSrc==1 ); diff --git a/src/expr.c b/src/expr.c index a51d37a7b7..07e81d2995 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2803,8 +2803,7 @@ int sqlite3FindInIndex( CollSeq *pReq = sqlite3BinaryCompareCollSeq(pParse, pLhs, pRhs); int j; - assert( pReq!=0 || pRhs->iColumn==XN_ROWID - || pParse->nErr || db->mallocFailed ); + assert( pReq!=0 || pRhs->iColumn==XN_ROWID || pParse->nErr ); for(j=0; jaiColumn[j]!=pRhs->iColumn ) continue; assert( pIdx->azColl[j] ); diff --git a/src/insert.c b/src/insert.c index 9a02ec6954..fd3590cb30 100644 --- a/src/insert.c +++ b/src/insert.c @@ -715,9 +715,11 @@ void sqlite3Insert( #endif db = pParse->db; - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto insert_cleanup; } + assert( db->mallocFailed==0 ); dest.iSDParm = 0; /* Suppress a harmless compiler warning */ /* If the Select object is really just a simple VALUES() list with a @@ -893,7 +895,9 @@ void sqlite3Insert( dest.nSdst = pTab->nCol; rc = sqlite3Select(pParse, pSelect, &dest); regFromSelect = dest.iSdst; - if( rc || db->mallocFailed || pParse->nErr ) goto insert_cleanup; + assert( db->pParse==pParse ); + if( rc || pParse->nErr ) goto insert_cleanup; + assert( db->mallocFailed==0 ); sqlite3VdbeEndCoroutine(v, regYield); sqlite3VdbeJumpHere(v, addrTop - 1); /* label B: */ assert( pSelect->pEList ); diff --git a/src/pragma.c b/src/pragma.c index ba84af7575..b13de54942 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1250,6 +1250,10 @@ void sqlite3Pragma( (void)sqlite3_finalize(pDummy); sqlite3DbFree(db, zSql); } + if( db->mallocFailed ){ + sqlite3ErrorMsg(db->pParse, "out of memory"); + db->pParse->rc = SQLITE_NOMEM_BKPT; + } pHash = &db->aDb[ii].pSchema->tblHash; break; } diff --git a/src/prepare.c b/src/prepare.c index 56505a7174..3c07ec12f2 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -589,7 +589,7 @@ void sqlite3ParseObjectReset(Parse *pParse){ db->lookaside.bDisable -= pParse->disableLookaside; db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; assert( pParse->db->pParse==pParse ); - pParse->db->pParse = pParse->pOuterParse; + db->pParse = pParse->pOuterParse; pParse->db = 0; } pParse->disableLookaside = 0; diff --git a/src/resolve.c b/src/resolve.c index 5bcaf8dcd6..aae046e760 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -1214,7 +1214,8 @@ static int resolveExprStep(Walker *pWalker, Expr *pExpr){ break; } } - return (pParse->nErr || pParse->db->mallocFailed) ? WRC_Abort : WRC_Continue; + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); + return pParse->nErr ? WRC_Abort : WRC_Continue; } /* @@ -1628,7 +1629,7 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ */ if( (p->selFlags & SF_Expanded)==0 ){ sqlite3SelectPrep(pParse, p, pOuterNC); - return (pParse->nErr || db->mallocFailed) ? WRC_Abort : WRC_Prune; + return pParse->nErr ? WRC_Abort : WRC_Prune; } isCompound = p->pPrior!=0; @@ -1676,7 +1677,8 @@ static int resolveSelectStep(Walker *pWalker, Select *p){ if( pItem->zName ) pParse->zAuthContext = pItem->zName; sqlite3ResolveSelectNames(pParse, pItem->pSelect, pOuterNC); pParse->zAuthContext = zSavedContext; - if( pParse->nErr || db->mallocFailed ) return WRC_Abort; + if( pParse->nErr ) return WRC_Abort; + assert( db->mallocFailed==0 ); /* If the number of references to the outer context changed when ** expressions in the sub-select were resolved, the sub-select diff --git a/src/select.c b/src/select.c index da3c78009e..b280ed2b3f 100644 --- a/src/select.c +++ b/src/select.c @@ -5588,7 +5588,8 @@ static int selectExpander(Walker *pWalker, Select *p){ /* Process NATURAL keywords, and ON and USING clauses of joins. */ - if( pParse->nErr || db->mallocFailed || sqliteProcessJoin(pParse, p) ){ + assert( db->mallocFailed==0 || pParse->nErr!=0 ); + if( pParse->nErr || sqliteProcessJoin(pParse, p) ){ return WRC_Abort; } @@ -5885,12 +5886,13 @@ void sqlite3SelectPrep( NameContext *pOuterNC /* Name context for container */ ){ assert( p!=0 || pParse->db->mallocFailed ); + assert( pParse->db->pParse==pParse ); if( pParse->db->mallocFailed ) return; if( p->selFlags & SF_HasTypeInfo ) return; sqlite3SelectExpand(pParse, p); - if( pParse->nErr || pParse->db->mallocFailed ) return; + if( pParse->nErr ) return; sqlite3ResolveSelectNames(pParse, p, pOuterNC); - if( pParse->nErr || pParse->db->mallocFailed ) return; + if( pParse->nErr ) return; sqlite3SelectAddTypeInfo(pParse, p); } @@ -5907,8 +5909,10 @@ static void resetAccumulator(Parse *pParse, AggInfo *pAggInfo){ int i; struct AggInfo_func *pFunc; int nReg = pAggInfo->nFunc + pAggInfo->nColumn; + assert( pParse->db->pParse==pParse ); + assert( pParse->db->mallocFailed==0 || pParse->nErr!=0 ); if( nReg==0 ) return; - if( pParse->nErr || pParse->db->mallocFailed ) return; + if( pParse->nErr ) return; #ifdef SQLITE_DEBUG /* Verify that all AggInfo registers are within the range specified by ** AggInfo.mnReg..AggInfo.mxReg */ @@ -6331,10 +6335,12 @@ int sqlite3Select( u8 minMaxFlag; /* Flag for min/max queries */ db = pParse->db; + assert( pParse==db->pParse ); v = sqlite3GetVdbe(pParse); - if( p==0 || db->mallocFailed || pParse->nErr ){ + if( p==0 || pParse->nErr ){ return 1; } + assert( db->mallocFailed==0 ); if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; #if SELECTTRACE_ENABLED SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); @@ -6369,9 +6375,10 @@ int sqlite3Select( p->selFlags |= SF_NoopOrderBy; } sqlite3SelectPrep(pParse, p, 0); - if( pParse->nErr || db->mallocFailed ){ + if( pParse->nErr ){ goto select_end; } + assert( db->mallocFailed==0 ); assert( p->pEList!=0 ); #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x104 ){ @@ -6415,7 +6422,7 @@ int sqlite3Select( #ifndef SQLITE_OMIT_WINDOWFUNC if( sqlite3WindowRewrite(pParse, p) ){ - assert( db->mallocFailed || pParse->nErr>0 ); + assert( pParse->nErr ); goto select_end; } #if SELECTTRACE_ENABLED @@ -7510,7 +7517,7 @@ int sqlite3Select( */ select_end: assert( db->mallocFailed==0 || db->mallocFailed==1 ); - pParse->nErr += db->mallocFailed; + assert( db->mallocFailed==0 || pParse->nErr!=0 ); sqlite3ExprListDelete(db, pMinMaxOrderBy); #ifdef SQLITE_DEBUG if( pAggInfo && !db->mallocFailed ){ diff --git a/src/trigger.c b/src/trigger.c index 19e22abcfd..801ec38ab2 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -918,6 +918,7 @@ static void codeReturningTrigger( assert( v!=0 ); assert( pParse->bReturning ); + assert( db->pParse==pParse ); pReturning = pParse->u1.pReturning; assert( pTrigger == &(pReturning->retTrig) ); memset(&sSelect, 0, sizeof(sSelect)); @@ -928,7 +929,8 @@ static void codeReturningTrigger( sFrom.a[0].pTab = pTab; sFrom.a[0].iCursor = -1; sqlite3SelectPrep(pParse, &sSelect, 0); - if( db->mallocFailed==0 && pParse->nErr==0 ){ + if( pParse->nErr==0 ){ + assert( db->mallocFailed==0 ); sqlite3GenerateColumnNames(pParse, &sSelect); } sqlite3ExprListDelete(db, sSelect.pEList); @@ -1186,7 +1188,8 @@ static TriggerPrg *codeRowTrigger( VdbeComment((v, "End: %s.%s", pTrigger->zName, onErrorText(orconf))); transferParseError(pParse, &sSubParse); - if( db->mallocFailed==0 && pParse->nErr==0 ){ + if( pParse->nErr==0 ){ + assert( db->mallocFailed==0 ); pProgram->aOp = sqlite3VdbeTakeOpArray(v, &pProgram->nOp, &pTop->nMaxArg); } pProgram->nMem = sSubParse.nMem; @@ -1195,6 +1198,8 @@ static TriggerPrg *codeRowTrigger( pPrg->aColmask[0] = sSubParse.oldmask; pPrg->aColmask[1] = sSubParse.newmask; sqlite3VdbeDelete(v); + }else{ + transferParseError(pParse, &sSubParse); } assert( !sSubParse.pTriggerPrg && !sSubParse.nMaxArg ); @@ -1253,7 +1258,7 @@ void sqlite3CodeRowTriggerDirect( Vdbe *v = sqlite3GetVdbe(pParse); /* Main VM */ TriggerPrg *pPrg; pPrg = getRowTrigger(pParse, p, pTab, orconf); - assert( pPrg || pParse->nErr || pParse->db->mallocFailed ); + assert( pPrg || pParse->nErr ); /* Code the OP_Program opcode in the parent VDBE. P4 of the OP_Program ** is a pointer to the sub-vdbe containing the trigger program. */ diff --git a/src/update.c b/src/update.c index ed96dc8b2d..ccad38df49 100644 --- a/src/update.c +++ b/src/update.c @@ -347,9 +347,11 @@ void sqlite3Update( memset(&sContext, 0, sizeof(sContext)); db = pParse->db; - if( pParse->nErr || db->mallocFailed ){ + assert( db->pParse==pParse ); + if( pParse->nErr ){ goto update_cleanup; } + assert( db->mallocFailed==0 ); /* Locate the table which we want to update. */ diff --git a/src/util.c b/src/util.c index 002cf65739..84608739ae 100644 --- a/src/util.c +++ b/src/util.c @@ -198,6 +198,10 @@ void sqlite3ErrorMsg(Parse *pParse, const char *zFormat, ...){ if( db->errByteOffset<-1 ) db->errByteOffset = -1; if( db->suppressErr ){ sqlite3DbFree(db, zMsg); + if( db->mallocFailed ){ + pParse->nErr++; + pParse->rc = SQLITE_NOMEM; + } }else{ pParse->nErr++; sqlite3DbFree(db, pParse->zErrMsg); diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 3b8b25e1d8..e586df64d4 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -1378,8 +1378,7 @@ void sqlite3VdbeSetP4KeyInfo(Parse *pParse, Index *pIdx){ */ static void vdbeVComment(Vdbe *p, const char *zFormat, va_list ap){ assert( p->nOp>0 || p->aOp==0 ); - assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->db->mallocFailed - || p->pParse->nErr>0 ); + assert( p->aOp==0 || p->aOp[p->nOp-1].zComment==0 || p->pParse->nErr>0 ); if( p->nOp ){ assert( p->aOp ); sqlite3DbFree(p->db, p->aOp[p->nOp-1].zComment); diff --git a/src/where.c b/src/where.c index 57c4808906..32ec17ec42 100644 --- a/src/where.c +++ b/src/where.c @@ -5491,9 +5491,10 @@ WhereInfo *sqlite3WhereBegin( if( pWInfo->pOrderBy==0 && (db->flags & SQLITE_ReverseOrder)!=0 ){ pWInfo->revMask = ALLBITS; } - if( pParse->nErr || db->mallocFailed ){ + if( pParse->nErr ){ goto whereBeginError; } + assert( db->mallocFailed==0 ); #ifdef WHERETRACE_ENABLED if( sqlite3WhereTrace ){ sqlite3DebugPrintf("---- Solution nRow=%d", pWInfo->nRowOut); diff --git a/src/wherecode.c b/src/wherecode.c index 77ee738f0c..b3ae06cae2 100644 --- a/src/wherecode.c +++ b/src/wherecode.c @@ -841,7 +841,8 @@ static int codeAllEqualityTerms( sqlite3VdbeAddOp2(v, OP_IsNull, regBase+j, pLevel->addrBrk); VdbeCoverage(v); } - if( pParse->db->mallocFailed==0 && pParse->nErr==0 ){ + if( pParse->nErr==0 ){ + assert( pParse->db->mallocFailed==0 ); if( sqlite3CompareAffinity(pRight, zAff[j])==SQLITE_AFF_BLOB ){ zAff[j] = SQLITE_AFF_BLOB; } @@ -2359,7 +2360,7 @@ Bitmask sqlite3WhereCodeOneLoopStart( WHERETRACE(0xffff, ("Subplan for OR-clause:\n")); pSubWInfo = sqlite3WhereBegin(pParse, pOrTab, pOrExpr, 0, 0, WHERE_OR_SUBCLAUSE, iCovCur); - assert( pSubWInfo || pParse->nErr || db->mallocFailed ); + assert( pSubWInfo || pParse->nErr ); if( pSubWInfo ){ WhereLoop *pSubLoop; int addrExplain = sqlite3WhereExplainOneScan( From 1da88b5ce634a7c53ba18d65072b5e44a415e800 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 19:38:56 +0000 Subject: [PATCH 24/28] Add ALWAYS() macros. Change some existing ALWAYS() into assert(). Other code simplifications. FossilOrigin-Name: 4aa27b4fcd1ffd06c38357a87ba3f5776367570439c49652f0903873def0bb23 --- manifest | 22 +++++++++++----------- manifest.uuid | 2 +- src/attach.c | 2 +- src/build.c | 6 ++++-- src/expr.c | 12 +++++------- src/prepare.c | 16 ++++++++-------- src/trigger.c | 2 +- src/window.c | 7 +------ 8 files changed, 32 insertions(+), 37 deletions(-) diff --git a/manifest b/manifest index 36b1c6271f..087c27ec6f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\smany\sredundant\schecks\sfor\ssqlite3.mallocFailed\snow\sthat\sany\sOOM\sshould\ncause\sParse.nErr\sto\sbe\snon-zero. -D 2022-01-24T16:47:12.063 +C Add\sALWAYS()\smacros.\s\sChange\ssome\sexisting\sALWAYS()\sinto\sassert().\s\sOther\ncode\ssimplifications. +D 2022-01-24T19:38:56.880 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -487,7 +487,7 @@ F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c e8ac1df663bf4ec74920edd1299435f2a616d2404de0ac4013c151ea4e7a11f2 F src/analyze.c 7518b99e07c5494111fe3bd867f28f804b6c5c1ad0703ec3d116de9bab3fa516 -F src/attach.c e3f9d9a2a4a844750f3f348f37afb244535f21382cbfcd840152cb21cb41cfaf +F src/attach.c f26d400f3ffe2cdca01406bca70e5f58c5488bf165b4fc37c228136dfcf1b583 F src/auth.c f4fa91b6a90bbc8e0d0f738aa284551739c9543a367071f55574681e0f24f8cf F src/backup.c 58880b9a9adf88f1a57cb3b0db6b891626ae76113ebd0f2417a87c2634edfc65 F src/bitvec.c 7c849aac407230278445cb069bebc5f89bf2ddd87c5ed9459b070a9175707b3d @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 -F src/build.c db3d3e6fa32cec976142b13c8ecd2d923016c59a5d4c3142b59749174c452748 +F src/build.c 698bf1c90f914d003025cd1dafa4322e6b7ec04d97436700adec083093d8c07b F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 @@ -503,7 +503,7 @@ F src/date.c e25773f06a8f9043bfa1e5fa0bee93483c41933adfff0891752f00eadd12ab1c F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c 52897a8516dc40753503c25eed0e305f09cc50ae474f22b0b4fd31d3b879cc08 -F src/expr.c da0ba8a4cf142dbd595d40bc09663994b9ae6b1ea7b85fa2c84e4951bce7b054 +F src/expr.c 81c8fad48125eca7b4016499ef6fd2d0d02a070be0d8d9a5d9a8f26d13cf4861 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560 F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776 @@ -547,7 +547,7 @@ F src/pcache.h 4f87acd914cef5016fae3030343540d75f5b85a1877eed1a2a19b9f284248586 F src/pcache1.c 54881292a9a5db202b2c0ac541c5e3ef9a5e8c4f1c1383adb2601d5499a60e65 F src/pragma.c 7c024d690a3dc93f61830f11f900e4af2357f31d081b0c79099ca5e28919cba7 F src/pragma.h 87330ed2fbfa2a1274de93ca0ab850fba336189228cb256089202c3b52766fad -F src/prepare.c da7d26f51a86d09e46ecad3b656dc8e135abfcc2cf7c26b048646464606a1cf4 +F src/prepare.c 1e23522c934d90ff42de1b9b4f782fdf0fb690b06b92d7480b471ccb2b5899ea F src/printf.c 975f1f5417f2526365b6e6d7f22332e3e11806dad844701d92846292b654ba9a F src/random.c 097dc8b31b8fba5a9aca1697aeb9fd82078ec91be734c16bffda620ced7ab83c F src/resolve.c 24032ae57aec10df2f3fa2e20be0aae7d256bc704124b76c52d763440c7c0fe9 @@ -618,7 +618,7 @@ F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c F src/tokenize.c b74d878aa7c82ec8460779468061a96185e22257f68ab785b69abce354b70446 F src/treeview.c 9dfdb7ff7f6645d0a6458dbdf4ffac041c071c4533a6db8bb6e502b979ac67bc -F src/trigger.c a17cf451b8fbf6e924cb472362ef1141c0cab84db05f33b2d8bfb1c6c565ee45 +F src/trigger.c 692972e4393dfc8017a1a527c1ea1b96ce3d101e84584cd832fcfb83d22b50b2 F src/update.c 7dfa3866cdfb28bf952c38054c1722720d8ff64750dea421790aecc91f640516 F src/upsert.c 8789047a8f0a601ea42fa0256d1ba3190c13746b6ba940fe2d25643a7e991937 F src/utf.c ee39565f0843775cc2c81135751ddd93eceb91a673ea2c57f61c76f288b041a0 @@ -643,7 +643,7 @@ F src/where.c a14990c7b35e95f8f9cb0dc0d6d2e32fa99135a716a04027cefa48138d280ecb F src/whereInt.h 8a215acde0f833a4dea3d30a7bbed9f48b4b547b5d5e34cd02acee366476ab80 F src/wherecode.c 8da0f873278ed6aad42bf2028404d7178dd9cfcdc7179ecc61a87591a15a07d2 F src/whereexpr.c 9f64c39e53070584e99e4d20c1dd3397e125fabbae8fd414ffec574c410ac7d3 -F src/window.c 5d3b397b0c026d0ff5890244ac41359e524c01ae31e78782e1ff418c3e271a9e +F src/window.c dfaec4abc6012cbc18e4a202ca3a5d5a0efcc4011d86a06d882ddaab8aedee4d F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test ce1aafc86e110685b324e9a763eab4f2a73f737842ec3b687bd965867de90627 F test/affinity3.test eecb0dabee4b7765a8465439d5e99429279ffba23ca74a7eae270a452799f9e7 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6a45d8fe8bfbc11a5b86d25237e1f8bccfb0f22f3dcaf004ba797aeb57b365ec -R c6a1e6f8a20313848dd96ff038c5eea1 +P 1f7fa46126ea33ed30e93186aff3df51068aeb4be6f79a102bfe8c4e44941d71 +R 75a506e3512f6c01f4ae9fd1a90d1003 U drh -Z 9cd720c9eb51a2f1a38e40423c81c52f +Z cfea9f4507c9cc524cff456f67a6c3d9 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 868bad5ed8..38d1cdd653 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1f7fa46126ea33ed30e93186aff3df51068aeb4be6f79a102bfe8c4e44941d71 \ No newline at end of file +4aa27b4fcd1ffd06c38357a87ba3f5776367570439c49652f0903873def0bb23 \ No newline at end of file diff --git a/src/attach.c b/src/attach.c index 2123278c47..e587f6cc5e 100644 --- a/src/attach.c +++ b/src/attach.c @@ -354,7 +354,7 @@ static void codeAttach( } #ifndef SQLITE_OMIT_AUTHORIZATION - if( pAuthArg ){ + if( ALWAYS(pAuthArg) ){ char *zAuthArg; if( pAuthArg->op==TK_STRING ){ assert( !ExprHasProperty(pAuthArg, EP_IntValue) ); diff --git a/src/build.c b/src/build.c index d37ff84e83..5e71afbb26 100644 --- a/src/build.c +++ b/src/build.c @@ -146,7 +146,7 @@ void sqlite3FinishCoding(Parse *pParse){ assert( db->pParse==pParse ); if( pParse->nested ) return; if( pParse->nErr ){ - if( pParse->rc==SQLITE_OK ) pParse->rc = SQLITE_ERROR; + if( NEVER(pParse->rc==SQLITE_OK) ) pParse->rc = SQLITE_ERROR; return; } assert( db->mallocFailed==0 ); @@ -282,7 +282,9 @@ void sqlite3FinishCoding(Parse *pParse){ /* Get the VDBE program ready for execution */ - if( pParse->nErr==0 && ALWAYS(v) && ALWAYS(!db->mallocFailed) ){ + assert( v!=0 || pParse->nErr ); + assert( db->mallocFailed==0 || pParse->nErr ); + if( pParse->nErr==0 ){ /* A minimum of one cursor is required if autoincrement is used * See ticket [a696379c1f08866] */ assert( pParse->pAinc==0 || pParse->nTab>0 ); diff --git a/src/expr.c b/src/expr.c index 07e81d2995..373b4a6346 100644 --- a/src/expr.c +++ b/src/expr.c @@ -209,7 +209,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( ExprUseXList(p) ); assert( p->x.pList==0 || p->pRight==0 ); - if( p->x.pList!=0 && !db->mallocFailed ){ + if( p->x.pList!=0 && ALWAYS(!db->mallocFailed) ){ int i; for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ @@ -3279,10 +3279,8 @@ int sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){ } pSel->iLimit = 0; if( sqlite3Select(pParse, pSel, &dest) ){ - if( pParse->nErr ){ - pExpr->op2 = pExpr->op; - pExpr->op = TK_ERROR; - } + pExpr->op2 = pExpr->op; + pExpr->op = TK_ERROR; return 0; } pExpr->iTable = rReg = dest.iSDParm; @@ -3499,10 +3497,10 @@ static void sqlite3ExprCodeIN( }else{ destStep2 = destStep6 = sqlite3VdbeMakeLabel(pParse); } - if( pParse->nErr ) goto sqlite3ExprCodeIN_finished; +// if( pParse->nErr ) goto sqlite3ExprCodeIN_finished; for(i=0; ipLeft, i); - if( pParse->db->mallocFailed ) goto sqlite3ExprCodeIN_oom_error; + if( pParse->nErr ) goto sqlite3ExprCodeIN_oom_error; if( sqlite3ExprCanBeNull(p) ){ sqlite3VdbeAddOp2(v, OP_IsNull, rLhs+i, destStep2); VdbeCoverage(v); diff --git a/src/prepare.c b/src/prepare.c index 3c07ec12f2..4499e9a413 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -570,6 +570,8 @@ int sqlite3SchemaToIndex(sqlite3 *db, Schema *pSchema){ */ void sqlite3ParseObjectReset(Parse *pParse){ sqlite3 *db = pParse->db; + assert( db!=0 ); + assert( db->pParse==pParse ); assert( pParse->nested==0 ); #ifndef SQLITE_OMIT_SHARED_CACHE sqlite3DbFree(db, pParse->aTableLock); @@ -584,14 +586,12 @@ void sqlite3ParseObjectReset(Parse *pParse){ if( pParse->pConstExpr ){ sqlite3ExprListDelete(db, pParse->pConstExpr); } - if( db ){ - assert( db->lookaside.bDisable >= pParse->disableLookaside ); - db->lookaside.bDisable -= pParse->disableLookaside; - db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; - assert( pParse->db->pParse==pParse ); - db->pParse = pParse->pOuterParse; - pParse->db = 0; - } + assert( db->lookaside.bDisable >= pParse->disableLookaside ); + db->lookaside.bDisable -= pParse->disableLookaside; + db->lookaside.sz = db->lookaside.bDisable ? 0 : db->lookaside.szTrue; + assert( pParse->db->pParse==pParse ); + db->pParse = pParse->pOuterParse; + pParse->db = 0; pParse->disableLookaside = 0; } diff --git a/src/trigger.c b/src/trigger.c index 801ec38ab2..420ef7061c 100644 --- a/src/trigger.c +++ b/src/trigger.c @@ -948,7 +948,7 @@ static void codeReturningTrigger( pParse->eTriggerOp = pTrigger->op; pParse->pTriggerTab = pTab; if( sqlite3ResolveExprListNames(&sNC, pNew)==SQLITE_OK - && !db->mallocFailed + && ALWAYS(!db->mallocFailed) ){ int i; int nCol = pNew->nExpr; diff --git a/src/window.c b/src/window.c index d7c412a3a6..2b2e856ec9 100644 --- a/src/window.c +++ b/src/window.c @@ -1106,12 +1106,7 @@ int sqlite3WindowRewrite(Parse *pParse, Select *p){ sqlite3ParserAddCleanup(pParse, sqlite3DbFree, pTab); } - if( rc ){ - if( pParse->nErr==0 ){ - assert( pParse->db->mallocFailed ); - sqlite3ErrorToParser(pParse->db, SQLITE_NOMEM); - } - } + assert( rc==SQLITE_OK || pParse->nErr!=0 ); return rc; } From b32b30930f10c852c70f99bc8a7b3d13f359b04a Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 20:16:37 +0000 Subject: [PATCH 25/28] One of the ALWAYS() macros in the previous check-in could sometimes be false, following an OOM. Remove it. Problem found by dbsqlfuzz. FossilOrigin-Name: 11df9187dad0eb33b0f6288b76d74f9700420ec855e8106b0bc71df48c485ad1 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/expr.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 087c27ec6f..cc062ff0c6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sALWAYS()\smacros.\s\sChange\ssome\sexisting\sALWAYS()\sinto\sassert().\s\sOther\ncode\ssimplifications. -D 2022-01-24T19:38:56.880 +C One\sof\sthe\sALWAYS()\smacros\sin\sthe\sprevious\scheck-in\scould\ssometimes\sbe\nfalse,\sfollowing\san\sOOM.\s\sRemove\sit.\s\sProblem\sfound\sby\sdbsqlfuzz. +D 2022-01-24T20:16:37.116 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -503,7 +503,7 @@ F src/date.c e25773f06a8f9043bfa1e5fa0bee93483c41933adfff0891752f00eadd12ab1c F src/dbpage.c 8a01e865bf8bc6d7b1844b4314443a6436c07c3efe1d488ed89e81719047833a F src/dbstat.c 861e08690fcb0f2ee1165eff0060ea8d4f3e2ea10f80dab7d32ad70443a6ff2d F src/delete.c 52897a8516dc40753503c25eed0e305f09cc50ae474f22b0b4fd31d3b879cc08 -F src/expr.c 81c8fad48125eca7b4016499ef6fd2d0d02a070be0d8d9a5d9a8f26d13cf4861 +F src/expr.c 9658bccd1598211ace848c8ca9480dbf8be08dfee1db5cf03897b34b7b6e8fef F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 5b73f7a7c00f06017531a5bd258cbc2c7a294e55a7f84a729fe27aa525242560 F src/func.c 8fddc42bce95d17938252a543f86fe29e479366e80fbd112a1822913b6247776 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1f7fa46126ea33ed30e93186aff3df51068aeb4be6f79a102bfe8c4e44941d71 -R 75a506e3512f6c01f4ae9fd1a90d1003 +P 4aa27b4fcd1ffd06c38357a87ba3f5776367570439c49652f0903873def0bb23 +R b59e5f1cc647c07cf190b232b2351dd5 U drh -Z cfea9f4507c9cc524cff456f67a6c3d9 +Z a3bee7e8f0cdba00e9fb11d4c00d9b7c # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index 38d1cdd653..dc18e83950 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4aa27b4fcd1ffd06c38357a87ba3f5776367570439c49652f0903873def0bb23 \ No newline at end of file +11df9187dad0eb33b0f6288b76d74f9700420ec855e8106b0bc71df48c485ad1 \ No newline at end of file diff --git a/src/expr.c b/src/expr.c index 373b4a6346..d58097cb61 100644 --- a/src/expr.c +++ b/src/expr.c @@ -209,7 +209,7 @@ CollSeq *sqlite3ExprCollSeq(Parse *pParse, const Expr *pExpr){ /* The Expr.x union is never used at the same time as Expr.pRight */ assert( ExprUseXList(p) ); assert( p->x.pList==0 || p->pRight==0 ); - if( p->x.pList!=0 && ALWAYS(!db->mallocFailed) ){ + if( p->x.pList!=0 && !db->mallocFailed ){ int i; for(i=0; ALWAYS(ix.pList->nExpr); i++){ if( ExprHasProperty(p->x.pList->a[i].pExpr, EP_Collate) ){ From a2417ec75c35eb9c0a0fe7331eb5bae93bd5c60b Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 20:20:35 +0000 Subject: [PATCH 26/28] New dbsqlfuzz cases added to test/fuzzdata8.db. FossilOrigin-Name: d1fbf63330830c4b9549d0e67f6cdc19fe7a9dc3fcf509795fd1175499fddc82 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/fuzzdata8.db | Bin 3067904 -> 3113984 bytes 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index cc062ff0c6..38e4ef4766 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C One\sof\sthe\sALWAYS()\smacros\sin\sthe\sprevious\scheck-in\scould\ssometimes\sbe\nfalse,\sfollowing\san\sOOM.\s\sRemove\sit.\s\sProblem\sfound\sby\sdbsqlfuzz. -D 2022-01-24T20:16:37.116 +C New\sdbsqlfuzz\scases\sadded\sto\stest/fuzzdata8.db. +D 2022-01-24T20:20:35.373 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -1069,7 +1069,7 @@ F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e4 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7 F test/fuzzdata7.db 0166b56fd7a6b9636a1d60ef0a060f86ddaecf99400a666bb6e5bbd7199ad1f2 -F test/fuzzdata8.db a0c7af954bcbb226ed7ae087b3b6d6e48eaac8fac5671150ffd23c35b55bffe6 +F test/fuzzdata8.db 738ed275638f2423cdef240a44eba3b9bc272eec619e68b00429d4575a15e50b F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14 F test/fuzzerfault.test f64c4aef4c9e9edf1d6dc0d3f1e65dcc81e67c996403c88d14f09b74807a42bc @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4aa27b4fcd1ffd06c38357a87ba3f5776367570439c49652f0903873def0bb23 -R b59e5f1cc647c07cf190b232b2351dd5 +P 11df9187dad0eb33b0f6288b76d74f9700420ec855e8106b0bc71df48c485ad1 +R b48ccd0a3450fb2e2635a0f6656fea13 U drh -Z a3bee7e8f0cdba00e9fb11d4c00d9b7c +Z 0541b4713eb6cccbe3683a1d204808b1 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index dc18e83950..fef38ec952 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -11df9187dad0eb33b0f6288b76d74f9700420ec855e8106b0bc71df48c485ad1 \ No newline at end of file +d1fbf63330830c4b9549d0e67f6cdc19fe7a9dc3fcf509795fd1175499fddc82 \ No newline at end of file diff --git a/test/fuzzdata8.db b/test/fuzzdata8.db index 960b15762510e89b40395c13f4ce6cc24be0678f..46112fff5f035e2387a28177aaf1c7a80e4a0fa9 100644 GIT binary patch delta 70480 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 delta 56604 zcmeFZcW@NP(>H#z;dU?Yo+Ol|I}o58P#}XuG8qX2#zcu^ktGn(1nmJP7>tBK4VWO= zF((XJw2bE z!X?L9VcAhu6s$T82FpRifBwnEvB}I?nY~+LM@y{oc4%H7I)1*vz>m_hh-PbIU;Y3A@as(BCm}i^6Cg88-@{CHk61qh{)`LM5a7LWNd#T&-EiR`e`CL zeTfVuqq4zdO*XJ6kpVr3WOXOflkCZ!>P(`uPGm^dlI+OR$c!wNtjLmD6Nx7qvN$px zizeH#s1zb@vK;ekM#Py&#GF7K>~}Jq;nx@M8iU|p+O5EGKcJF$ZtR-&zDFpnbOc- zA(Ck;`M?rk8t0+*Y#*Oh&WYAid)_#%T1&Ze_*a+W91Di{`~ zL2aca2-;8ab>j2w*dj*eH1vgO-B<)vuV+S#@5DZmy@Z7LYaIL`R59uoz;s*sRk!QofJ%Rb*=Cv%J;j&q5mXYN^@fEiDKhkU)!#Joe zWYMLe!cx8V5pePvOULTfteoLDi&z-PMnZYEDG63yXUFiwM3%vU>oU8b7aoOo=dv&c zHBE&?Xg8nb!nw~_3O<}>o5f)67i^tgXf$ZAvgaZFXv{GrPH_x|-3ls!#OK&S*k8i> zu`yVEmZdZ36(*GbvoQwXXVchbuLYk2g$~GoFnHZ9(LG$Q#83JfV?# zSh$+CU{!kpzKT5ABgjM zTyus^;`oAYy`i>%`o!^j0TRZYV;}Qu+J9^SWP{0=UCUnO*mTG^6w@2h|KR&z-Juv4 z2QM$+I>S|4tPJ)~*e`4bWZiK$gcA?kAyBb1)(Ofgw*(2X4Mohp#9rmuOmH=h^Mmk- zwis+b-PV#J+3f|6&GL3os5#A^)$KI`Z`83Mp3Mez9D5GOf6dnNWYpRjEEMt*gO>tz z&vKYQo3)3{tE>{3AG$*!J32(hsv9g$68#0k@-|SsgY$*k6&4k3ciFETn}@>B>>(uM=fy71u zHkf=p#)vCLE{_vwel{!s)t?JNm&_%}VxVBy*VS7V$0}SYFM6oN3ovY0Y#285<*xCT z#dDgvy7cYS%T6!$I1mcz#Mh9wBG+ytJjfZN%Yr;uJB=GjZo`#EkY zu1Mjg^U}(`t`5(-a!SY39F)+4`;ccvaB^;x3to!jy5poa+!~%0!^y>w?P21Jkq-QJ zS!57{qAuJtoV7eM+&dqvg7Plh7<}+jB*(zsmNP+7C+-9sEsAV|d0n^?#!7Jgs>m@6 zV!Lxukhvx@825GK`g3eG7MDg&WKi)mmx)c)KB;)HKxaXAe3Y>#x}jAyy!99s+NyCP#TaR}!pQ%CPIihG?Gmr^}1 zVNz@;z->x{yP?V__;~?GU1Kx2z!3_GNn8V{zwh#a`cj7z@;;LV%$~_nmo9_q30x_h zYZvDLWqNQpo}R-Elf_WMa4;7hHgh$AHFdJ^?jxVw;% z4okQXc(w(!CER?t-<|n^(!kLaPb}w(Ei4?f)^g=c4igM(?fR@!_dN~P<;z$Q+*!{> z;n4NmD~xR|-N3D6E-c!>(W0;ua;6I|sQEz}jZ4e)ja&>!IRf_6;;dg&v)25O%Uj=_XBJWV~dknu%y^OEo;vCz6}fU{(16EpOA z(?0=R_lRWr29!hnJ^u@s*?~X6*!$pm+P5JL^$##(Vke%4%LgcQ)n)k*uJu(?OKM7F z$m9YB;<}zZ^@oq3y3W5Z4#?#9^6XcykgT$k-PpIY9$(P#(XNXIDyl2Zut!CtLt1CxRB> zu>yXD%o=0&x%?qc{EU8o4e!3uz`{Z1$=IQgJ>Jm-ijKrhzy}^)Wb8}0+cIIgK9Jhs z;e~t;o_z)GH34L`CA!tV#_)v!&+zcDl;5g1^*6x2_a{%Hh$m0tTgYD*?h9o_0Sazj z7_gDUw@dkUjC}{?cl^m7Yjt~E2eyt+1A6a^y*Ka?Ce{R}ZslpFt*hF>&lH46!B7m9 zw`1I}aSxwmzx9%_sbJWkq(;qK#0-!*mv0SGp?o}!-pjA&*v+a6ezir65)4IsODe~> zphvXO04^To6UEykUp=%s%~QJ`-`f51mz{AoTz zX3>~e!>{DoovIJ{t)dts7}iBTsTS)l^WmKM3)OoMh0pm7CKdHbV^X3B~ViZ2-H-v&S4V6 zvRpQYt;rS|L0l=jqw_L>JH?g{6}x>>AhDS(6s`bksJpQVNNy~nZuPg%^i)-Z&|ef2 z1jGB29yj4|xEv*PGg;nBi>E&Rg7-O+#SSu&qq?o|AX<2UQ*ZFC8MciV-eJrJsztct zRRgH;=HZGYVLHd`P~AZA!;STPEyJ6sLLkQ+Q05T)VB^nx5!C(4n;`8Mz5tuF6uvMr z6@_f!PpS07C{Z9roW9HYjY%c>iGpGKn8(uj;H@FT+f1aL8uJDB7U3hjoGZ+bSu@DW z7sd$-8#w^n*8_Z^W}0BZMl*#viIz-FYT%0jg~Ind`3%BB zy;ul*v|LEUlqJGNp8U&%#X=;;E*C!GSr`gMdWmqT+)Nr|t`f}HXthws(?Tn(6&}jQ zWNNJ!n?06O#a89Q+nh-IP1XpmP8C9-^=G^SzPZBN`0EzI#&Z!ZVf{yZ29#|Sd?0U| zpp?EQh_LwzFXGf4LJ?2fw%Ywd1V-)=XtU4+YWE5OPKBVpi&LNfkxO)zt!zR6Ff-SG~Y6@V@YuDAKT7pYo(&G*k>#WvJgHTOjkA8n?Adm~Gb~dJv4bwvvt)cim=XfZ)N5gQLAkN}h8z|3J>G5yp|gh%!Bf-@tQso)8XW5s4-h-^ECVu52hu_iBGN+80W!`7p2HfK zn9P$8THi9Hh(UEkP%KtA7JW@(N5QZv_mL##1aYCC#-KFI(V@Q$L)wbljjRV|W{SxiHt!;u zjO;1Q=qVm!La&mkU6Az_A23mm=JbYQw=oq%2Z}Zx_FLsp@PA5t5r24E^b=Snx-!Kk zJVp-|+lyj%!LVhfE?En>lOq}_L?8yhsci9k`ROHNyU~g<;K|Drxo=6Yt~9R0o;)%` ze2Hy%X_DLm3eUxQpsbfD!iyut0@kN$lt>%mesHpFLIPCZaMJ2-=Z#n~Hf{=o{YOLP zlDak`R*x0qEu_?)0#V^v|Eif{oXC1&{9Lh?6Q3bf2Cb=#K8bG^is7=@TQIElcA~#! zU0Ou4wqGi~D-S6dM-IyNflmZ8f@5h^IF4T?u4e4ns^wxALCB<~49f2XCPALdXoC72 zl9j56l!m>~qmN)%0dVEPtuidA@8Fl+>O zp7l|2tgj&Bvr$zC#d1ODr@zZdn6?sl^OM;RH8$MJ!RdGP48QA1Pph^8LtELcjJ2I)|QJCB8(uhMVMb?oWx-M87Tt~#2GU=_5!fI zK`GcG(fA(E7K1x9C;^5Ik7*3)eT@?#d$AcrG|Kf_~Lj*(Jlz%>b@ems<7;YLLDMV$n zIdLJCUJh9^gD>M3U5!ojxJ1^R;6XU7r*W$um#FLhZMKE{y1BysC#J z*!|!IxOkv(j>J~!6X~+yx8~?B(@G6i`lb`uX6mll+lp) zbWjmg1dAr9_&C^s`{o$?^Zfdeso;Lv=!-#xM)DS4#_}$~jG?&5NCBo{)IX@lQ-{UL z%Z)|62&C;MRM!XJp@7MG9}^Vr3IZ%yWz1s~Ldal0G+z<;7bvuLZ>dVkJsNEIR<EFu(D*vf zc0lFA;P>(4!^SuY7*w?iDg1jCs(8crw2|$`;Ot1z8Gu-!)vD(f?;pDH4 z4SD&%5}%PYpGH4XQG~hIDFS}wJEL2yBY-dO~!|){O3*Awt z7y#QFvJox{=3vOX9uk6=>WwjaAfPrfbSv(4Nl){TU27Do?ipzzc^%m1&^(-Q-MHLa z-4Rrmhcxw8_mQ`{qfmLwwe?ALF8n-13h@>_2JQzjm3oam_$sUPwIGfb44<2kjN`-W zF2Z5@ocNcx)&Cavg68yoTBajNcZ$iY~et70XZtKPx8 ziDA@&r25w!ZR3+phphXjpb?K{}*afKF z8MYBOzaUX;E@7i|4~iOw2ZN)L=_WpWT5^ai7ah+^^_+N?YOe)#kn{kP_ep0M)^(CX z7<@OJ==-3~k?1@lTbinG>(xRjln3{7(wDTi&zK&Pg1r|?ukm{Q4Rj4Zf{fWAsnBPM zWWo*;q~j(w4%l?*7x|OQabpF;SKd{;9ZXI)RqJ}y(B~4eL6V*QhjnA7*K`@9ilv4O z0&}DS0i^HbqO-Dw$x~AAnv*>E+8=locv0&~Gi3=nNv)4)#GQ0-0E>nMSwGST$ z^Ttaa2wEZ)Kv}FS9Im_@MlqCzl0Vi=kQUI0jEx-*XZuMuUEVLDHo`Oj2zf zeZ$ySC~T49WnsKvcmU-`d>+{s$-cCg_@b&p5}7zbFuXVuv?EeG>{=-u;W*m(=dTZL z4cSv;{Bgi(i9#gTA*;8sKR$a-+QqXQkk!}dhk-THO`hF^c2O}D4Ej)_(AoFEB-1pw z+ABsz?UHm;7AFdZ8wF6ABq!sm*Q6nw_$>+ggYI(r!(YApWcaOK+KAO(OXFp6vS4_1 zie5GY@}m9eaO<|TPpU8JFo}FGeSJ@cm5H+B$-CWBuiTaX`U6fT$nBwQimYP2 zB2VF_{W+ zlOp7A>92=yZHi1A)JQo-77NHTdJT#vn7u8xM=+m`oeJ%f4yh#5o?yFUH10Ttm4Sj#*^|((RC$yj*_F7GMRnqq?d8S+Z# zGfK{f!fx(Qz_rlc2P$Gn4r2HRRF9G`RP~c-mbd&KWIAORT+Na}XKDv^x*Yvq#KB>Oa)MWP2VTpQThQ4>u-p^UyU0`U{#e<>F$K!! z$`nwTAX7j=rNbF{E|fhdXJcL`Ib2^oI45XxT6W6fbir_(x+(nxH*C<&6i`(rj}XNfv`LPCRMq4UDg02) ziwXGIRyl%WAyqr%#ez7Kwg-PRdtAcbyGKCUOVbuJj5xdT%053IhW?fEEsjD>*M>Bt z7|9LMhD{F2*|IQOFnkK^51Y4d+I9E2H5%WLdvkKcx`0`<1AinMkh4EhbWw$kA!n1j zCuUa52lUWK-DxvTwx?v8Y@0$wfZt^3bDpZ$cUtbxn<5ialT*@ClbSap7TkJ69>%dm9QQFj(K(OhSQ6BH6BP-CpUDy?*UL2$qvOA}F_WN14eo^} z?#Z1f9)cMiV!AQx^_N`5u~f+D60`l#Zqq;>GFuuCV3lC%#k1y+)z+8`b&F$MP}#6*s4 zTe$X`V=vUbED@YwhbaZxwlKM|iQ80X6z&@g_vx&up5Hru9{v?+;&_puJ6t+mn=OUY zRPc?-j1T=x6qGDX49n3u7Ep}j+B~U1=R`Z2?3Y3+abu}8l0jWh$*2#c4p2KKtOGne z72X)frxEf zGw}INrX@Uk3fN!9U?>|Ko(r^O`$F|!rrvm?t0{}@tffP~dfL$_8 zZ}67xDXFy2NJ~jgNrS=|mp?Y{XL8E|ITPoe^mG{)4KZ1GQ_uZ_H3O|dt$;)ssSDAW zKD|I)DhH!7jG`})o@*Kbf3*rs#3K_;nG9@WO~31^_J+GTrqNhG)U=Ud-Z+!{zZ3;3 z`jlR%53)%n6GQsZuSRoL%jCr7DalFtva~dczy^7y7_&e#5Cs$-D5)^C(qw{}*KJMc z@Pd1KRgy-w-!euQtu^c{u!lnU^QJm6lV0}2P1kL1hK=W%t{B+>$mk?BL6@)jWAAkK z44&K(GMoYVqFteAo$D$V2GK567ib_wGo&;~3^52`7V#{q4`RsIJ6~+-CF$M69*H!5t!8` zZZyL_oz38_U?djz4x@hd4~?dHH5vt3bz!ZZFqC*U8nU8Ym!B|-;i^uV!bF1kgr70h zabgZJ$o*G~js4$SY@D~nXgrzU@oG8#zt#S^DM%Eh|K4zf=Hezn?W-X%G!@X^$F(HH z>DB2~uTGOuJM4PqUpme6>XZj3r-sDqJZXDOwd6mx(Opw#NtB6I{9_wcdTm6AD6RmQ z#{25#spFyMdm|My5GWv{ovYWsn9wFNZ)=$M{d7=+r3jr<4G)O{!QO{6pf)w`TRKP$ zzpPs-nS*+ZWUjKBWl=N{^A3-hAN4YyN_=Kx?WWKKI;Xi88i?tg%?G_IJ`e6b;a9+_VE=Bc?*J3ValKRd`G+SfKRSBuPyYLxj0PMk%23NfcmTz_vX zZuhd#u)KHJ)BjCDV`37O_CR^xFmGpk6YEpVK0I6SxFuVfGbCm~M~0a;J_L#5UO>gy zT<>i;!i*WX#Zak)rRlx9g1jZ_*!sgIP|nj-NHpSdMgfdv!XNV9 zks8(eS@*|nM}hf8rP=1q%!Xyz=3Rnlr?9<#rqcqB+@urh$ro%U+&tPmpAKLke1dtL zxN3c}rVuv5+<}=^E^nkc2yCEN*8-yZ+f{5h$@~QqSCA}4B^AB4z^!L|6sUgNNNwEH z$B)C`rePRU|ww@w8vbH9-_V2{G0K=ob3oDd72aFt}y>WNRiUD=3|7c zdSk6QLZH~PVGALQ-Zb}wW*f~vo7OJquldrULcI4GKEKJlgt2u{d?AvyCS~TE5_=i6 z?R*~Q8I8+X)h;u6#~Z-)qu3hT?=hd!K_0GO#i0~jv|D$O5rY!kTdi#gD)h2I{O zYRz{z3TbhhlM)ltk`vRweNjGz7Y~~^OLT-Zx!Qb&iRA~HY7MaMo8~vYfDP^yDDM_N z<`KtjyUc`5`%(1T=v6G*8C}3&(@)|EJ4xSf>Tjly*^MQ-;* zg4)GGQQ2E&+S~0#p`M;n)F$Va`69F$?65-KZL}kR2<~2%X4pK_a*jeR;QEPT)&c!2_o?(~1@>8Wt4k(U|mqHKAV8 zrZ0?yIpNMjl4SA6&wq@LVAww2a*7i#5QH=Vu6gL#%vE6dihvkv2FH9sK{LS*2tz63 zgP9hQXEkf`VkkyD#{#^$w%b#^`}FM`71b6B7n9-Lg%*N;ypNr2F-JK(@q(pDWMPoG z+_Fsk@CCOPidUCgB6R#j`59{k9xSr-(eV?RHP*J6vD)&c#9vBGgv~K=ff&BQa@H)m z$We|4?WT2L={(;iFkw5vXg@7tTDV{+Gd_N9(RKQSKA*u47c7Hu_zue!J%mzxix7N8 zsWE9d`E^S%?a8VvonZfu7Avg$%90NWb(U0p0{jBhBjGwM(sD>*SE2n?%Sm`|w@-md)768oqUhb{VbocD%h5l3;CjG-=y9aLKuNTORX zTu6H?pjUAB6XAAy7oRIs-Pe%hQo^w770Y4vgy+wUeFIsqSvo`FQA^Fgr6z_ual!kR zNk*}eU^tonn1@q$y}sKhYYhd%5#Ps8|HZkK=}q+&eXirl)0RFApZ>y9!BI%&UkW2B z{50ckj-XS1+dRE(=JHk7EdxX`f+qU`kE>6Byk9K>etTQ*pp9u(e`2cyq&F)WyH$G6 zGLJRI`SuVSmYW0%Ql~psybPV z1VX12ceUOSrE;?t3-h~KH;Vkx_F4?OyIa3tM(z))M1a~=qQ1Ub$%hfqy}|k_Z3ItR z>5#}kK{0ok^$=8avomQ#a=kV)`M*W?kjcJj7G1GEJCg??7{=qWUrWmEB$d~1#l2FX8T{Q|EQSR3*L1G)C1 zH5?rKt#`35(@GJT7oNAyr3lKkmGn4slU0CpA8QuGueJ1o-PzroZ=)mWO# z3$3)``#`yDr6ay2))5py0rjf&4kRd63x?NPyK(T;O6xH~PpV&8`-75f?F!X%tTOZ* zWgUX1aw`p{eygneMOxj9&sfJXoV3omhGPL3T4Sx|;nZepdsPoxF2W)0t@_j?`77V3{JSMcF1g#FajoT28>4XwIlC2uAY-M6iW zD5AFBdJD#uSU_K6PU#gzq5H12IfI95Ed8viPfU5J;xGCWm`G{UovFdQ-aWj z&gr1IG|=0W5`18_xlAc9$Qq$vmV0aMgFS4v*%lq(vLP4pBWxLH3AFvpiK!%L3-Wht zxiV{q6C-S^D7sS>X*(?FAeJJ|>qu4<&-7BzCohGgHTnAzBAouKuo9vjsu)z-T+3=w?gjSo^A; zwqML*XNu+N*dhYsYc?00D~gdJU5hnBbcr|Kz;{_(pmm~#n((+#2%X%gr3_6RMF%Z> zC;B`EnI*Qi{{VvYLyE;8Na+*8C>wcgJz!Aps30JH8e_*?TQ$#mLiq&SG#p%DTg>ys6t00e96GMH z#$c~JTfWS?;E9>Gbc*>@&9My@MGCX5_bQI0S2jnOl!dnLg3whkY|@Wf(sgy4Kz*>? z3`(@06Kj^(5_pzXwcNH%5D8CGH0rUw5&C2?Xvr{*27Gb)Kb}6j%&zqyV2bPU)4yxf z`y!=J*p`U{*NxD+(`sV7YwEvvmPVkOmD3*=j?hOd}VT_6;t*nMNs1jAt+ z$l~QmQ|d(ukPiFQR?b*X>F2f*u`j`8hCJ562XB6E3*;%!L#VSw$U1aotsZ1er_);7 zH_SA?Bupcy%eE)&=7W1~+MZ_W7?B{Iv)N3dd^7$J{?`&ke)Vx4qT$H@%R~Hsd5Hh_ z6G3#Rry zAiV6MtV^N96HIiehaj-Rd=L3T!W<8!S_=6dLgoq+JSx##k3uxZ;~+ZNVJJrdD29wX6&`5qeYg3Ciww-Dl?R9Qjs(9jo*+B}*7{?aH> zmj6SWP4uQl@jU*rHjU_cjbe!WS#1*0lNtpxdDN(d_#N6fqFc4+h`yrfi|ZzBG|`u} zkwiP_5!8o`FPb zJOhZH^-$g7Tk}2r=<78PP50s!PZrV5o<2m^dwLNCPYqH(PupwM4$H1X^5EaX-Bk$rw!30PivwP9^GXat@S1PKP7R`r@Y_)lPqq-p#Ps) z-2Y1wcNlFg|CcOoV;9f(s#`X4D<{H*>-MWKW|7x}Ln}V{{ zK9k`b(Z1No3MjT^Cud_Cl$q@Wl2GiLS;zJjhv_Uv>dXGjC9O5uv=z=655hCj5mKQyu-_(LZEbZYXbQK@is6?qd;J?$&J zkicWpb)J)f{B1k7=x=|Q)6*RJ#S|^mn_>yfn_wp-$q@S(nGM70QFg*wyg&tBgwttu z%0J4rQvhl?Ry3i+RCsZSeLZfTXkVZsWtD68A&-2KigUIws3@>+m0#M}KpRdT=%XDb z*`+1aEQ?iP(+1h8E8CVq+6?;{wybKVo$OzP!W>=t;+)tKu_N2HO=<=wM{yl7v(SEk zXRFZN)!l(%mqqqFMqvc`t&jE)c`1ZFDZH+@;hp97X5#9tleHZDYq_1yEmxA{YoO-3 z(iE;Z_=eE_1_Ane#|XaQSY?+er_J6JHy7DQ@vIcSn5!$k+P;f`hA3>%TVovxW%~De z!s*yEOu|UYCVk|MxpLz|D4EnIL;Nh85fALO_vCaKA-@rZ9J4=zgDdQmu`n9qRsW7a zh224}!9K#kpR>0ziO*3Cr-ip3f?qiNADNW$q2d{s2k`_N-O4V|Y|Ot(pY3sR z7`l~N={)3|y#pMdMw{}nm+j3Zf?t)_*~f{ymc?jek!;wE$vaEpv|RGp9{I^6LK;?o zX>ZTiwyLjnGwp`EK`!#$6DX8HXoeO@K!;Z)!V~Ua8rK0_+bFLw(d~Gi!<#?aDUWI& z9*=Nz;NhZKoesx-vp>c5qnq(pIe1trwt(P2?AKWZvTg1^7(V>VPB@xM$oY+qi(J>- zbsS~6xhds_bRcs}4aQ^MCU+4P6dhFX03L6lS6w~KeMB#E5RbRf|9;rcu@mk%9KP%j zY_>TlRZ?+$q-P%H@8k)L_F`|nG^R=4X;DS5T0 zF3}s9vBQ0WhrA78{@~&rP4tJyF=LOrA%zpH4bPH)?(mUMv`k8Ep45^;n#fAhUj z+62-Lx!(VvJJLT9D4#9`H)c7;a1?US|I|Xsd5w7s&gkb@t|uxkkM!^3 zEdx}>jKu>TQzXh#jIWM!!_bcYey}e)J_54Gi9;~G#xb44#F36hqDVNheVrZ&T#@VO z!;7a$+H;WOCh`8x&HV65?f?`H<VvcbTD)55Z#uyj+Z_!>3aRs-!SSt*pP<)}CatmAPDd@rKF69bDeVIj z_c}h{*cT{N=%QSKyANXOvFzD!TD=mxyXF$Kyiu6H-kGk#T`o4hbbGKbb~)^LgSXWs zrlpNe8D+`YNE{X481v3JN;tY@p}4O< z1sP}Z*|_GMV-ioX^}=x?B{|eM-qLdywMk+$ltuct{=3(F=orHjg0c3hk^o8#}=8>X2IR-jMI&Qw{ z$Y$boYJgjyeD9zkdrKd(x3TU=hl^5me{&4R`F9-)j2wRl%Hw!nm~g|<3#w-Zhn9>V zJ05S}bNKNbUk^ERf-|7bM{&XJ9*Pg85IC06^Se;gM;U);vO>^A{zp*G`_sH3C~=uWGnB2iFOA?I4!80L)|i!MBFFy%`M%;4hCXy6_%P7R zts%$%ilhH@yv*y2a&$xfwq~?40%{8V!w-F{P-wedYCs|^<&_y;?m*nT(OotCz2w9e zl;lld5pzlLn<3CXJRlxl7ZiUAhEEKp!gfmX&J8_8qftBLQjQyzF1N_DR51Z(%joJI5kuG zN}^4JV7T8(A4?RsrVNo-Fw`1F3M*%-gP|oV7A)MMR7+&x zj0)vAF9wk+VPGGoQeyK#Wg+EWVw;`HDGu6KsVe-?Po0fVA61G(Bd@Pc6ZEF=dcW!u zjW_6RLXnZTz_88AD|+)hfHuCWKeV~3yvw4nJVbS{ z(w7w{Ja|QE5ARKh^WeAFlu#p!fsmEtOtreMoZ(q4-N6&L7+<`l%+!P06<{aKdA&lI z^LX5UOQE}ODyGNTvHdSfcZtwY25l=SL)9r&e<^`XOx)ewBVgDA$pfgEvygD|AlS` z0qQdf^tY({2;Mm7p1mc9ZS5+h52r%@2g*vl6E!0c#U;8up!LVfeArm3_`nb!bvs=~ zl>dpc5-zM$=(zZj@+J90{%SI7j_Dhfw$xh!RYJM6fb?>O3>Bi1p<0r=s!*<Lz#0%{FQRLgliI4-oqqzLC*9KM^Twqbnx7AdHuIma-Z z&{74Cr9=L9iNL6BRN6OWz}+u{Xhlj_X+fz118hwxtR?Lz2xo z1!@k6u~1Z{?8F{f>S2ze%I?|f2nH+mDD5EcPLPDV`>XqmI^5~~W>9`gol*LiqC#~w zj?{>X`)=3r;{2Cn_D@X zKy@b-s`6BF%6mgbk{Si=DwPh9xWTyxGILZ1wth`H$sjROoeINds9RYdxPUa_fAK2~ z@*X?&3oA6ih($BisXWVsT8B>ptnBJs2`d&m2f*aLN&~3dr3PcSxoV9`$I84#1L2gq z8_q0N(?p6~2v38yUyg?Tehn3Dw?v&Qix$DKr$8@t8}}BgeL0ar62bt?->1GvPRlRq zI*cq;KV$3}a5s0-6(4KWmrWuepbn=Y{fP2BC?nWMcUJ`poCt&9WTu*cS5utL8IIek zUNZ`mO+krD`TTU{m&Nj$|qIpqSP_&CK7Ri1gY6y;bUERph-d6k7 z5eUQIQU~I+V`@{GIdJ1CwVKHzb{joZ$H%(+S@39;%--+Z0EJ2FEL{T%Hwhy_`AW!y z`VCGS=A2evp)5}t8A+Ga4^|Cjo-B=`u1A0K%m zWYF3A3NU3$goiHbI^FYMGBnj?pfI2?6_hW9{`$c3CrpspNtmDl$jDJOTx505(?dGy z$7*=#RVR5tWzGN&J2;&u8ReC_kI+70UJRYFuLyRAz@~=I!H{OM`{Sp+&L}<2w04_% z`rrKpslTK!N;{1-+2gV3jA|sHVX9N*VC8pev(iKAqAHh@#^7vJ3Y-r(uTt=rv~)R%}%ThS|-X zk)qguFv!vRGN?zRgu*p*JOs4cJ?CG|@|)f)bLpc!+N9`x5UCH&p(%Wm^BvtP9>_Z3 z^v4qo8fFl}p@q8DD|*!-^}KgQTma=x=M7L^Qdg&G|OR7DCc4m9iRpI^X6g zVO7X``coF7ra1KS9yiz$xxA;thx;>%*g)^LmpoBT| zbzaL+3vij`SoMN)r6>fG z3XjnFg?rR1K;3VL?wPE9IoCtLI`qy;sCQ!TC~dAQRYadPsOG2z|I)|HXt%CUDO{bY zwuPFR&doZvMtY_zS?>~lzQIXZhU+kYs~XAur&9*Q*jJtF*?PEk&G`&u%Ay3zR?%%~ z8=Ay5#+SD^$pa0gpj#`Tw!VRZd!27kjOi8C69R=f?vDDbc}16u!d1dXyj$d~VtAy| z*-b}Ss)uyf>7esliIwSBCalLz$DE^iRu1J3=Ww9DoC@bA(>fGCOU=UHs+~b5k-%cb zQ*>T4bhEy?ez1pbyE^oUI}mr;Y#4;iRp)dQZ3VVpr3;U0oUh3Oq0e?b@si{4oo}3J zWHCvt`1CdD;I7x3 z>3U`14{jfoV~46Dd_ELK3Ky;Iu0QXA5z#)MG4XX`PC2b{?xj%kn%@GX6#1Vx_67|5 zNqohdA`g@zPoalqbfn!n$>%i3j>D$%n1iUCk!dQvkm^Hz{|PQ5&DDItp`TurUhq-tp@Ok>L$4V&@DW$^&RB82$>=1xm+Hy81-& z;!zUl6qJAGL!MqwpUox~x&2{(A5MIWp1%vlvnVVPFwo~MlYW`djugoM#-{^JD36vg zdW6qMOnirmoyDYSe)kzZ80{l+>^;~&%a6h;xjqE{JO}&d`ekCj2|oMv6xRJ3WdWio z--qs)y8sn?eY0^?fzM|BPOEE`z8Tngrq3NojHYzTK{}@_Tvq5ajTg@lllMW}WpqK< zMDzZCqM(6L(BIK2>Sw2@rSCxRboc=zO*LI*(EW80-Z?{JjNs#<*S(8Xb9N>h8) zXD*(oiC*Mg?>+)`CLs}OWZx3H7{;doo-6WcPOwX?oM!GrcRybC`NaDi(!u8~_6Zh# z=re+_n>Eqvy{s+)v-m!IQt=>o;{&>KOfmZUBGtCZ$l|d57N2;|^m%cfCzf(BN9meT zurI}Kfy>)`R+~Sq9_NXn{ed>Xt23P5?$cbX{r~uS6S%6X?tPqd=X)Ihx$`_b017zI zpyoV4nptW>shJ~KnVJJ|(buvR#8_peP^RVxPRm&^8?A)W-ZD!tD|3Xh+4BGFgZb9` zet-WyAC8@K&)M@{d+)WL^(<8RbL#P0+$VfyQ(UVi3e}f%G|`3`aVYK^ZF8szqm)sz zqm)a*5H}m%J`+{DpU6+*8DGb(QmD@t&d6^^YY)WD)z=nI&2J0E)tKA4x}wcuc7B1s zI;xl)Hk0>ITmnzXHK$Ab(&0Fu7*4+x*H#UEQF#nJ`L7s_MkVz=8FyT|0DM6lX5ZHw zTNL*t&SbaZZ2bEtaXLx*hU?}TJPJm&zmQwyTP}Mg?g2YC_M7ZuJm4B_cF<4W-8I@dfK*A6O{Ck-A(UvHO-SjWJ%9G^!sCj>u2p*cQfXlKL{L zb%T9N;-C&sAE=Mz6~p5|UW=zclJBWF2UP})VZO_1Jgilyel9MX+WDV#cu}VUAZ%0P zei)QytwdXZ$LV}?9S>_`tUz`@A+g^mdQ9Ax#g)UG^0frx4xQAI*LE~!Dm1EJ@#`N{ z_C&i0R6Rgrr}V|v^5XO%G2FAO@nM|`P_5S+!OkLaj_HF!YgADAsH3Q1jAihy%(JD+ z;@tJvtwpIN05vV2?y6pt1l-*3<_5}5H^x!S5aSP$g7f+tv1Wfc#{$u}WVmsWBq=Fx zuyG~b+HUc4%zVpIX;*oEx>Q`5{kTX>MX@(6#$BaXZc22nzcO~$!o#}&qElL0iC@)} zoo==4DqNPWEPnZ>{DEdy&inV{_%Po18uURAb?A`PaT4IpHAYJudoqm|z`sRxPlDmZ zKGBFpK~J$EfC(K_j2DF-s3`1#bKA+;#-&`?C$Ts5D7_OC$T-V*9m=7!EAHLAFWWdo zD2HNSkM>c!CT$X_XE4sllOHoy>NK4(0ipN(Yc!g8(?a8DH192xHM+RW)a#C;Ll!C# zF`klQz+h#>bchA2Fb?cw%Zw(a)Pkxz#ldC&8RL7x;k3FN=2lXn@t|HH-M+=KsZxZm5zyE5)a%10b{7wOc zdd(k3=JfZCIN6SS!#JEDIbvKRfthQIHs`}R6n=&_Qn~5B7-VadDwAhtY ze$bds-qS|-L|5VeY9Eg|edkzxb?+%-wMyznHJ=(^)rW2l$nT2&`?b-EP}|xRrqfBW zvHW6g9GpwhG$#Co`9N;mVg;{x$+%EVP<6{YOolOJlfG3yOQmD|UOw@H3DUP-GR47x73Vx1d^l95 zEjl&ejEArtYi)|qTEWe;pqVM6P`5=D+Ebd=e2`#L>&Cyvm<+;?HL1XujpN9cHYGHo z!L*%*uZy2Si+@yqF6!Kol9m~dP<9LRc=pZgzS9Bpq-qxusD9SC8}Uji!aHhn5V z*8@M8(NJRDQoHETO_PIH`Ah~KsKH)tZF*34XH|EDlZ5$%$o?b7ZU#~#w~cuQ^=fB& zQ|ivXcMR|`EsZvhr#7A9Vt9htv_fw99_)MH04cI#dz(QxGQX=UA?$0K@%Np;-UHWG zU$x;Iz`a4IfNjphoZr=yr;vJ4+DTmnr`yfIQ`h$tjntcy-Zb@>cyO92TC3@W5wN~3 z`BdhA(TLBCenNK_iq20vl$zg@O9z=ID0E$M-=|AT5~YP&$8ly}+*cBVC_$r;`qIm5 zjUQ3`!SsAXO?cA)A5M) zPK`70%lDXIPrHj&ZZJMi?!~6_C6|ovl6zKMo08W-%DM1<(^5(5FOML)m5mQ}=bMH~ zylA`$z7YfH@MCdMx@MZ7bREbmo;J;vO6JE6;-iyH{S?w5Ua=rKOj$hdG1JpZX&5caFug;rhvOdM9e0~DB>H?x99FZx7d}ZE zey8|^;xD0Jr^X%TbE8c@=}tAimPY(fMI!ha6X8xZMo2&=et8wcj;}pnY9Yy$p>y@d zWJ>v$sYc2unG=`H`tKo($nlWrYf-<)CF$P;n-@G+`XX-3nhmrXVtoz(YlnVk=S@V}>sLHLxI zt8OmaZhAmc3+&KXDt*Abg?E&jMk#^$sA^$?$~$I{3EThiRAn~(O!cQsOHFJH04R0I>rpfht#)C zZ>XdPDd(`RRAiR{t5q8_)Ou0shuC`z+ciSAPf_{z>NGxCW5QWxBE^1hy22&TVfa~^p1qwFA*)Ji_l~K_-V3JpH0nNR9C-%ry3;T% zgV_aNWIxVPDR&GeN7omOm9&2yBV6nB|=n@#ihj|MRfVN{6GK&5)a1eNLx zjx}mpfnI(?d}jhTn2kQz5D(^(y@ro?{BNcWk~EW!dQBfws>57K6IL1T;VXZb+G#Lh zohtJ|efC~meqT7`gSJv-mdi9_uf~icAk<*$98P|~+*;y9y&2AlvnjTX`4%mV7$a2O zHZGAW;{n=T3|B_x=H{U?i#wYD>y0sgrG&03HpToJxBFDcJa`bs@OLJ&T>-UK(NR+z zTdd|QN+_#hyP2<2_g-;bsl3*-g7>-1LljU^B`*f8Wc6&DmJX)4>{MCfhWT-AY&?y7 z*y*9lIIoG4Mz&G$4zGEX7W`;CG@AGL!&c^w;AH2V0wcynb`sW@dlJpt6+%t5%(##t z(hIT1cZ_?D_okSK2|rwEXB*g!I+!EE4>zaK2xpKk=ErmbGJeS`HwkC@HSrR4>1%#l zJr`|~%gG5Q&<@r%H3#XLEr!R0izPr?QR+O-c*k&4+B?_`N6&oDc;E0GYQDs%<Ao0$|7uj5 zrC&BJgPf1sg?Y8smx5RYJ5562q+UklO`sgE+-%s$y{?(&NFd@hVj7?oSBT%AqBJ&5 z=j&-bz^>aw$1xkL^cH+N$SQT*BH~VDB{6^uf-=C+Kn+qiU zi^Yrc0hr$;Tp{|v4q-knsh>w8FY(n^Y|&WhZ+pV#OZ>uK^HjC8mNUu}N@*uf_*6Tl z?NrV_W?d@r&7J;_}I3sQztpv>;DYm$AFrJX_*9@0y?0 zNZ@5(r3Of<+WfjsouP`lAl%Y(WvYM!#hD|V$$oh?z> z&*ldKpQ>wV#q@nu*+$Nx*gZqTale}D71H)y6*DXnJN__VR7g9DN5oeYe|h!DU#B8i zy)G#%09ut7k7!pxg^Cy}S6(qsRuo^m`GF`!MR88`cq%Nl7>Xxk9_2QA3t);P8Q8R4 zl783z`T0Qf{~(-#pSaUVCF(8sa5p90YboOAjFy>NsIaPy79(IB#usRz$&=`l*0)&^_JP|GEqW|Vx; zLu2I;e=Y-CPGSp7Do-43c~MgDK?}aQD|reGSKaTkKoj>?aq{#Z zibn)-#u{(w1~NEqm}hxI9x}-D9cowzn-&I(frn4D>=DfF4SAL~HoiT@Vi1&{7kccf zn4BaG2kPVadmm$`5+~Mk=44JSv|N{pM}*+S9Hst%qR*RW@A@JXP!!La`3Eg9Tc?WW z9|Gyu22i*KmeWFE){txs7k58WK@-wrj8uLv&Pcb9)SDH13oP(t0;2ZpgWM1+f!4h6 zh)%yN)eFN3QaXXZkErNc8&`4t+@_rPjO7z>zwJu9I9@7FTJ#~+8{yDcI@~ydhR?N( z}|<>aJ6Nia8RzfWrla_T}plNxty2y)8{Q<|NDe$l$Lf>I#{VHF5g;K zocY_=eE4MxYt(?-e)b^ct+!6#PuE)l3iYQI6Z7va*=V^X6kY1is3B+t2i+#iqlo!K z4Xvy&vTwD#tJHixu~Tx=L)^@4y&q?qe##hrw8B!TP@HXFT#?|X`u@sw^q$?ijUU}( zDbxUFRpGaViqp%QbN4>hHziK$q0E+w3(fkH&)e8&#Zk-SaA7W+WOY$xto1s_R9Ue7 zs->KBZQ_b6N9oyn-13!DQTqrAW47rv92{l_|a!f{`H@EmFyc*55^k zenUlbtkrbuK;lSl`Gw`IpoS~kr07bE>nx|aMV+NV0cyCsGZv_3FId(KYPg0^6r%-$ z{r$ZAq6Ips%apCR0#n)4`piEm|IdjGu29lu3*yc6L*$h7p5n)a{n`JmMG2E~P?!jWgb|?2wB8IMjlU*sPNYO%p6m-Q1MZ zcUuC`RSZ&gr*kP*tl&}V>(nqv`O%(Ftixr#&f0Er8^t7bNP@?M`p<)b{PC)&p9bG) zIWYF>t^Fl~`sa!c`Qubk=chOR)UJ~wKqI;+`-^egP|-1eEL1nvYV{@De*auuG(un8 zj(KnlMf`!Yj#$=Vq@Y5K9`2*isBa{7?wSm?QZs-w+byTK!Dx-et3PtiQ0p=*Rc~9o zqDqV^^;0O+KXFdFb&!IGxvhKD3iU6P_HWB9K9pt!oyNkDbqQYim5RR6B>gp_?&bBZ ztPdc?-w5Ks!zEqi!>l64T?xLKTB8RYAOMJ$S@ZfhFP?`U0y zxBj4$2P_~m=wdyiRj6-Kau+3{km#++Vh~|nMD7EC$||mU(nZ61D7Vn!mexF~KGSB9 z7}Edgzs0=1zjXpkm&Ijw!!ke63gnBTxGEb5rlD3Gn3PV3OlEVSo1(4mow9faXbWeox&HaTllBB)@DlhI_K?B z0s^$a3J6d%`JQxi6!A&QLH%a{iB>n`5~|#v0KL;9D^Sk!+O?&m4_qqRc2A6!XXaa< zlLVLCx0Vo9zNk#);m;_s2d>|#XeC0LJSYkmOEpDStW3+SSeaUI@)GMwST6S{CeijK zaP;&pw+^D~%d7~)k*RD!Po9pB7hlB{7p?5KcdZimlgfEY6_>BDLaBCqm9@7Tu&%U& z)}vH95G1#$bF6)^ojjPB%!Aih_e&B8=)OnZ>Za;1PwQFayYdO72e6$WwLo7Uf<59FL2>#Gt!eM(He zb|jouN|?tANN{Os4(*$Pb%DYgdOrv(CTBwe)5)2k*4 zy|{diFHE#`5MsMI;{zaxTjAXVN^9zKaZiKo4UFXLZJc|567@?2_{SEc9?fkPv~HAN z%eB9V@!yuDEdAJ$rA<3fZZF$?eC4JURL_%DQ6D@eiZh>@du;o8i`q6yp^8W9d`@k1 zDcEbUeI4w64Z2c8ZZC?rXT*gd2{3d$XU=Nzgv-;V#Nb1xrgYq9?Pk&pjBtT!9H1fS_ zYsDYDV#5*kuLHz-1wdUf-zLCHIMlX7EA`{L4Q2-%>j&9>FDXNsx-Mn~>Ee|`vt!6DGlr5THeAf28PMXOpN^Cij;DyuNLm6ic z7Jlg|TT=iD7T7+M_P%6OsdS1cfVh5+8U_nsns&b?KU+X?1eU&JmfcCO9kTV;-}~IW z{8<2<2)E@S^hJryNVQqE7MxvXTd5G5Da{zln(IKgo=O|IXzvq%>Vbl1dMXtI&=eEwvncYhEms=PbqDNNGXQQkahKD!6B=m( zXLNB5RQ|IFZK?E}?I9@>EOIV@LQ{J=*3#s!Y%fb$oRR8+;He&|wNh;-XGbAIKsMLU zg=1Ih7mhuM4RguXUXmW7toxnQM8Jm(oUv?u0p_Bt2b`~S%qOLfS290J*kwY zP}x4mfIUO(`;^inT+z|q3*aS<9pI&@T+!7Ygc5A2BaI)?+t(&^>` zSIT5s&DK3o;%v?A1Wlo987V}}CmCti0}?BrdJ9y@efgnF9_yycHG|_p zW?Srv=hAWZhv1aQIoE6}u`hbok*uKXl=!xkxy%k=V3a10s)oD5baqo|qfJH0;QH%B%-TKI}kX~-9>B`mb+Y5xMSF@CpOYGVIRj-Hy1XuDJdl^@5 zv-N@!uCrzUSKep;M3$4wDE4Iy=&ZkVl=Aj*_KR{lPf=`{#>z>r*sn zRg^ilHI9wkRL4zrt+8X_SV_t2wC$+&HOD;u^8=eg!I{50Q~N?NFvXM>U1dr{~%$rI)CDuKl=>ka7HZwH=CxmnpWd>-rt>lpuE+ zq0_)P{hiIu&wXN_DFMC}(@pab07&tr6x zO>}BOt5tw>$0t$kMC_|h=0gVt3bSaMFhxq>*4ON3)QD)1SEy;Bpb0yo^`bXwDLuvh zG7PmgY_y^@8@Q_0_8OeO{*n*C2SsT%a@7SJY|ZG1^8bj1x5Q7Ixay)U8bG}v@huuB zU%JAvOG3EBsw=j7n(A?amUh1#CPOR(MCg;Ldvy+#T9Xd|+T~P6XZRrV7g@cORA{dd zlWINwwsO&6J75FVCi}l2gX)|BPb_c%O&#Yr2Ay2;Fiiuu`_Nv4en+R2^mfb#n_1Wic0Wj{)}KRXt4AD5#_0nf&w@%CB30qwCh;YEJO5=pAy zqAc+!wa{^clHM>!)0~!$XQiE-EUBs_ezUcs7hD@DD@zfiQis%%lHxrso}S}(n+>oj{gb{kys$UDYyFFm`({^*_d2FDXNjZ|?8Q{nnn`;%ziv5s

BtlV8;f?<*&5cM1i3j(;Vik-HvsLyp(Lm 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 A)Bpeg From 15b01def1eebd423e6fc3d70bc78dea9b9c33a63 Mon Sep 17 00:00:00 2001 From: drh <> Date: Mon, 24 Jan 2022 21:47:00 +0000 Subject: [PATCH 27/28] Remove an unnecessary assert() that is sometimes not true following an OOM. FossilOrigin-Name: e9361d72f362b390a31f667363b01cf9d4b78aa19ed5c97f21afe9da764b89c0 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 1 - 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 38e4ef4766..8d13f4f3e6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C New\sdbsqlfuzz\scases\sadded\sto\stest/fuzzdata8.db. -D 2022-01-24T20:20:35.373 +C Remove\san\sunnecessary\sassert()\sthat\sis\ssometimes\snot\strue\sfollowing\san\sOOM. +D 2022-01-24T21:47:00.416 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 -F src/build.c 698bf1c90f914d003025cd1dafa4322e6b7ec04d97436700adec083093d8c07b +F src/build.c 6037f01800741633853e4b1f8079bf0172a9f583bfde2d680d5874629c09e926 F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 11df9187dad0eb33b0f6288b76d74f9700420ec855e8106b0bc71df48c485ad1 -R b48ccd0a3450fb2e2635a0f6656fea13 +P d1fbf63330830c4b9549d0e67f6cdc19fe7a9dc3fcf509795fd1175499fddc82 +R cdee37d1ef86d53b092ac478f4ac2ad6 U drh -Z 0541b4713eb6cccbe3683a1d204808b1 +Z fb8b5f1d8af8dfa985fd290959ee5924 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index fef38ec952..b6312d78f8 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d1fbf63330830c4b9549d0e67f6cdc19fe7a9dc3fcf509795fd1175499fddc82 \ No newline at end of file +e9361d72f362b390a31f667363b01cf9d4b78aa19ed5c97f21afe9da764b89c0 \ No newline at end of file diff --git a/src/build.c b/src/build.c index 5e71afbb26..b9d47bb266 100644 --- a/src/build.c +++ b/src/build.c @@ -3987,7 +3987,6 @@ void sqlite3CreateIndex( pDb = &db->aDb[iDb]; assert( pTab!=0 ); - assert( pParse->nErr==0 ); if( sqlite3StrNICmp(pTab->zName, "sqlite_", 7)==0 && db->init.busy==0 && pTblName!=0 From a5c9a707578add09ac07fef85799a2378ee4a89a Mon Sep 17 00:00:00 2001 From: drh <> Date: Tue, 25 Jan 2022 00:03:25 +0000 Subject: [PATCH 28/28] Minor adjustment to error handling in sqlite3FinishCoding(). FossilOrigin-Name: a8db69411b0d1275909adeb21027784ada17af24efe3a59ae0ae2a897659ff17 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 8d13f4f3e6..f8d24f4d54 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Remove\san\sunnecessary\sassert()\sthat\sis\ssometimes\snot\strue\sfollowing\san\sOOM. -D 2022-01-24T21:47:00.416 +C Minor\sadjustment\sto\serror\shandling\sin\ssqlite3FinishCoding(). +D 2022-01-25T00:03:25.602 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F LICENSE.md df5091916dbb40e6e9686186587125e1b2ff51f022cc334e886c19a0e9982724 @@ -495,7 +495,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c ddab31c38d5f16114bc68392430556b1063fe14e0020f9a56d2c35ddd58ba7e3 F src/btree.h 74d64b8f28cfa4a894d14d4ed64fa432cd697b98b61708d4351482ae15913e22 F src/btreeInt.h ee9348c4cb9077243b049edc93a82c1f32ca48baeabf2140d41362b9f9139ff7 -F src/build.c 6037f01800741633853e4b1f8079bf0172a9f583bfde2d680d5874629c09e926 +F src/build.c 9329120c4522d1ad881b9e62108870c8a5e994e31f4d813d0eb3de323d25e362 F src/callback.c 4c19af69835787bfe790ac560f3071a824eb629f34e41f97b52ce5235c77de1c F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 2cce39df1a13e05b7633e6d21b651f21492471f991dd7b323a4ee4e7b7f0b7f1 @@ -1941,8 +1941,8 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d1fbf63330830c4b9549d0e67f6cdc19fe7a9dc3fcf509795fd1175499fddc82 -R cdee37d1ef86d53b092ac478f4ac2ad6 +P e9361d72f362b390a31f667363b01cf9d4b78aa19ed5c97f21afe9da764b89c0 +R 2f204671367b290a50dcca5128a83ae4 U drh -Z fb8b5f1d8af8dfa985fd290959ee5924 +Z 303c6274f1d08ea5df8933a6d290bc89 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.uuid b/manifest.uuid index b6312d78f8..b1380388fa 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -e9361d72f362b390a31f667363b01cf9d4b78aa19ed5c97f21afe9da764b89c0 \ No newline at end of file +a8db69411b0d1275909adeb21027784ada17af24efe3a59ae0ae2a897659ff17 \ No newline at end of file diff --git a/src/build.c b/src/build.c index b9d47bb266..cfff85cf9e 100644 --- a/src/build.c +++ b/src/build.c @@ -146,7 +146,7 @@ void sqlite3FinishCoding(Parse *pParse){ assert( db->pParse==pParse ); if( pParse->nested ) return; if( pParse->nErr ){ - if( NEVER(pParse->rc==SQLITE_OK) ) pParse->rc = SQLITE_ERROR; + if( db->mallocFailed ) pParse->rc = SQLITE_NOMEM; return; } assert( db->mallocFailed==0 );