From ca9a5faf70ae430d5c74442b6b5dbc6853eeac75 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 28 Sep 2018 23:53:24 +0000 Subject: [PATCH 001/109] Fix test cases so that they work with ICU. FossilOrigin-Name: d04b2013b5436430ebbf7053d637fd89c1b15affcb42787dcf1cf5ffc3ae54e2 --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- test/like3.test | 2 ++ test/window6.test | 31 ++++++++++++++++--------------- 4 files changed, 27 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index dfdb94b268..061e3b222d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Have\ssqlite3changegroup_output_strm()\scall\sits\soutput\sfunction\smore\sregularly. -D 2018-09-28T20:46:41.755 +C Fix\stest\scases\sso\sthat\sthey\swork\swith\sICU. +D 2018-09-28T23:53:24.160 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -1055,7 +1055,7 @@ F test/lastinsert.test 42e948fd6442f07d60acbd15d33fb86473e0ef63 F test/laststmtchanges.test ae613f53819206b3222771828d024154d51db200 F test/like.test 11cfd7d4ef8625389df9efc46735ff0b0b41d5e62047ef0f3bc24c380d28a7a6 F test/like2.test 3b2ee13149ba4a8a60b59756f4e5d345573852da -F test/like3.test cf0ff2d06c9d8456283aeff405b911642298441206306aeaeaa93973233b1195 +F test/like3.test 430691e6057e11a59e934be74c06b85605b80061d45af5714d52886a811efeb7 F test/limit.test 0c99a27a87b14c646a9d583c7c89fd06c352663e F test/limit2.test 9409b033284642a859fafc95f29a5a6a557bd57c1f0d7c3f554bd64ed69df77e F test/loadext.test d077450695ddb5c1ea3ad7d48e5f5850fe732ad9 @@ -1652,7 +1652,7 @@ F test/window3.test e274b7f8952ca4ed25996e0e45c047192b066e0aaff2a822d4293c8c4f1d F test/window4.tcl 511425f6b0abf9b953df54cc9c7295cc7c25d78f4ed6f7a74b094eec0120eccb F test/window4.test c5d6bf3403e4ade2f19df2afe4c16f29fb817c392c6c1c8017edb7165c191a62 F test/window5.test 8187f46597c90b73e8f96659e893353cbda337479cc582f7a488eab351ba08d3 -F test/window6.test 7574778c79cae89f1781df237bf9ff5063886deca91a36efc53934315f0e7612 +F test/window6.test 5eae4ae7a590ccf1e605880969ca0bad3955616ac91cad3031baea38748badb3 F test/windowfault.test 23abad97b72c6f609002255ddd41ef5c8922408f918f9b98ad6005ab316e482f F test/with1.test 2465d98ffce80d00553ac7135697c18b0369275b6ecc750daa2af320b8c812ca F test/with2.test e0030e2f0267a910d6c0e4f46f2dfe941c1cc0d4f659ba69b3597728e7e8f1ab @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8a758a872175b0c74e631c231240c5c733fbec708d0cff23eb9c4025e4a800ec -R bc7e7923bdbbf4167e1d0ea65b2cbd1a -U dan -Z 4710e29744ea4e9b01b11660462afc67 +P 8467c31aa0bf24e597f680748460a99f425c49f5ab741c3574c339aa56857146 +R 08311a219ed5b2f0f2f27b2fa84a2c37 +U drh +Z 7aa1cea9abc47bd4971180b786cf5455 diff --git a/manifest.uuid b/manifest.uuid index 687004ba90..c2c3af7508 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8467c31aa0bf24e597f680748460a99f425c49f5ab741c3574c339aa56857146 \ No newline at end of file +d04b2013b5436430ebbf7053d637fd89c1b15affcb42787dcf1cf5ffc3ae54e2 \ No newline at end of file diff --git a/test/like3.test b/test/like3.test index a7225ee055..575faaf104 100644 --- a/test/like3.test +++ b/test/like3.test @@ -130,12 +130,14 @@ do_eqp_test like3-5.101 { do_execsql_test like3-5.110 { SELECT x FROM t5a WHERE x LIKE '/a%'; } {/abc} +ifcapable !icu { do_eqp_test like3-5.111 { SELECT x FROM t5a WHERE x LIKE '/a%'; } { QUERY PLAN `--SEARCH TABLE t5a USING COVERING INDEX sqlite_autoindex_t5a_1 (x>? AND x Date: Sat, 29 Sep 2018 19:38:42 +0000 Subject: [PATCH 002/109] Add the PRAGMA table_vinfo command (with an extra "v" before "info") that works like PRAGMA table_info (without the "v") except that it also shows hidden columns on virtual tables. FossilOrigin-Name: 8bcd1a59560aa7ea73e6529e5c14ece8ac09bf7e99efdcfd388fead39846b6bf --- manifest | 19 +++++++++++-------- manifest.uuid | 2 +- src/pragma.c | 2 +- src/pragma.h | 9 +++++++-- tool/mkpragmatab.tcl | 8 ++++++++ 5 files changed, 28 insertions(+), 12 deletions(-) diff --git a/manifest b/manifest index c8e41160c0..1a507037bd 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improve\s"PRAGMA\svdbe_trace=ON"\sto\salways\sshow\sthe\skey\svalues\sfor\sthe\nOP_IdxGT\sand\srelated\sopcodes. -D 2018-08-03T13:56:26.671 +C Add\sthe\sPRAGMA\stable_vinfo\scommand\s(with\san\sextra\s"v"\sbefore\s"info")\sthat\nworks\slike\sPRAGMA\stable_info\s(without\sthe\s"v")\sexcept\sthat\sit\salso\sshows\nhidden\scolumns\son\svirtual\stables. +D 2018-09-29T19:38:42.265 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 0a3a6c81e6fcb969ff9106e882f0a08547014ba463cb6beca4c4efaecc924ee6 @@ -491,8 +491,8 @@ F src/parse.y 704c94624d41d7d46a5467574130e55aa8029a563f4df538f0121475eae46e34 F src/pcache.c 135ef0bc6fb2e3b7178d49ab5c9176254c8a691832c1bceb1156b2fbdd0869bd F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 -F src/pragma.c 71c585f1d26e14b931fa4573f587933d6dfddecd9d9001b0f126f74f7306bf87 -F src/pragma.h bb83728944b42f6d409c77f5838a8edbdb0fe83046c5496ffc9602b40340a324 +F src/pragma.c afd09f81b987f1d6db91b1414a48dea750bd0bf02b7ce48f92b6c3fbbdc29829 +F src/pragma.h 32f09ef76532b0bf2c82970dab0dd68dc204b414ebf9c3e9e8641daa6cc506ea F src/prepare.c e966ecc97c3671ff0e96227c8c877b83f2d33ea371ee190bbf1698b36b5605c0 F src/printf.c 7f6f3cba8e0c49c19e30a1ff4e9aeda6e06814dcbad4b664a69e1b6cb6e7e365 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 @@ -1686,7 +1686,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl 2144bc8550a6471a029db262a132d2df4b9e0db61b90398bf64f5b7b3f8d92cd +F tool/mkpragmatab.tcl 228172329b4d7dbb8898b0147bf717f938667ee6906339af872c3305165b2d73 F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1753,7 +1753,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P e390023c8e70961661fd9e29674dedacd1b941b6b8d9cd88f8cfa8f787f030f9 -R 42c2ba852bcdcd5b618ab0afe0f401df +P 0f881955ed173c7c35dfca2d4aeca855858e40bb951e6fb6fedd9a2fff6a5a86 +R 35c75da33444f38727c331e96f4190a5 +T *branch * pragma-table-vinfo +T *sym-pragma-table-vinfo * +T -sym-trunk * U drh -Z aecb34e96579e406e10bba0b12f9710a +Z be1def3d568c6c74fb53c9827e6ce9d7 diff --git a/manifest.uuid b/manifest.uuid index 5b70c3c775..9209ea52e0 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0f881955ed173c7c35dfca2d4aeca855858e40bb951e6fb6fedd9a2fff6a5a86 \ No newline at end of file +8bcd1a59560aa7ea73e6529e5c14ece8ac09bf7e99efdcfd388fead39846b6bf \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index 02510188f3..04043f3e8a 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1094,7 +1094,7 @@ void sqlite3Pragma( sqlite3CodeVerifySchema(pParse, iDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - if( IsHiddenColumn(pCol) ){ + if( IsHiddenColumn(pCol) && pPragma->iArg==0 ){ nHidden++; continue; } diff --git a/src/pragma.h b/src/pragma.h index c9ece2dc87..a9bb19ffc8 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -69,7 +69,7 @@ */ static const char *const pragCName[] = { /* 0 */ "cache_size", /* Used by: default_cache_size */ - /* 1 */ "cid", /* Used by: table_info */ + /* 1 */ "cid", /* Used by: table_info table_vinfo */ /* 2 */ "name", /* 3 */ "type", /* 4 */ "notnull", @@ -572,6 +572,11 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, /* ColNames: */ 1, 6, /* iArg: */ 0 }, + {/* zName: */ "table_vinfo", + /* ePragTyp: */ PragTyp_TABLE_INFO, + /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, + /* ColNames: */ 1, 6, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "temp_store", @@ -646,4 +651,4 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_WriteSchema }, #endif }; -/* Number of pragmas: 60 on by default, 77 total. */ +/* Number of pragmas: 61 on by default, 78 total. */ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 1bfbeb7c58..61e0d4828e 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -220,6 +220,14 @@ set pragma_def { NAME: table_info FLAG: NeedSchema Result1 SchemaOpt + ARG: 0 + COLS: cid name type notnull dflt_value pk + IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) + + NAME: table_vinfo + TYPE: TABLE_INFO + FLAG: NeedSchema Result1 SchemaOpt + ARG: 1 COLS: cid name type notnull dflt_value pk IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) From 5351e884aa2c118ae6a68f02b6b2d5fd66fa73db Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 1 Oct 2018 07:04:12 +0000 Subject: [PATCH 003/109] Fix a problem with ALTER TABLE commands when the schema features an INSTEAD of trigger that uses NEW.* or OLD.*. FossilOrigin-Name: c52f457e56eb9d573eb67093731eb231aaf6fd6dbdc397e6f948b82736fbe3ab --- manifest | 16 ++++++++-------- manifest.uuid | 2 +- src/alter.c | 5 ++++- test/altertab.test | 43 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 56 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 061e3b222d..b5a3086cb6 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\stest\scases\sso\sthat\sthey\swork\swith\sICU. -D 2018-09-28T23:53:24.160 +C Fix\sa\sproblem\swith\sALTER\sTABLE\scommands\swhen\sthe\sschema\sfeatures\san\sINSTEAD\sof\ntrigger\sthat\suses\sNEW.*\sor\sOLD.*. +D 2018-10-01T07:04:12.490 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -437,7 +437,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c 65fc93f6de5e9706e70d5ff823d831223b784f6c5766ef902a3235b8525de507 +F src/alter.c b929e4daabe215300aa9b4e353977714c1751d91aaa63e52f0a475b840ce245e F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9 F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114 @@ -609,7 +609,7 @@ F test/altercol.test 53fb5e218c9296afc160f2c4fcbeaf42bd0604815d9b3896a7d2eec583a F test/alterlegacy.test e7c07d605c2a85e7d1696c89e6bf64dfc932fc6d9320fe8708c8f5fc0b524d41 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9 F test/altermalloc2.test fa7b1c1139ea39b8dec407cf1feb032ca8e0076bd429574969b619175ad0174b -F test/altertab.test 3b830144c18ae00abd2a27e3d2851c8bb1ee8fe655fa16d8a5971066dc71b58a +F test/altertab.test fb8a9a2ab6deb5f860d27675f6213d14ab79b705e0d6350eead4ef3a3f73bf3e F test/altertab2.test 159fd5f7b23ddc841fe678f579f9b1b8e69f44296f3ff75d1b4c155d37a59832 F test/amatch1.test b5ae7065f042b7f4c1c922933f4700add50cdb9f F test/analyze.test b3a9c67d00e1df7588a5b7be9a0292899f94fe8cac1f94a017277474ca2e59df @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8467c31aa0bf24e597f680748460a99f425c49f5ab741c3574c339aa56857146 -R 08311a219ed5b2f0f2f27b2fa84a2c37 -U drh -Z 7aa1cea9abc47bd4971180b786cf5455 +P d04b2013b5436430ebbf7053d637fd89c1b15affcb42787dcf1cf5ffc3ae54e2 +R 479306dd49205e8d1f89a577af9e0033 +U dan +Z 3eb383fba7fc036a1656cc373d9dc1ea diff --git a/manifest.uuid b/manifest.uuid index c2c3af7508..e3f42f7fe9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d04b2013b5436430ebbf7053d637fd89c1b15affcb42787dcf1cf5ffc3ae54e2 \ No newline at end of file +c52f457e56eb9d573eb67093731eb231aaf6fd6dbdc397e6f948b82736fbe3ab \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index ec1cf0e9fe..3e2a5f1f08 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1061,9 +1061,12 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){ db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName ); pParse->eTriggerOp = pNew->op; + if( pParse->pTriggerTab ){ + rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); + } /* Resolve symbols in WHEN clause */ - if( pNew->pWhen ){ + if( rc==SQLITE_OK && pNew->pWhen ){ rc = sqlite3ResolveExprNames(&sNC, pNew->pWhen); } diff --git a/test/altertab.test b/test/altertab.test index 008ac1153d..819aa67201 100644 --- a/test/altertab.test +++ b/test/altertab.test @@ -459,6 +459,49 @@ do_execsql_test 14.6 { ALTER TABLE t1 RENAME TO tt1; } +#------------------------------------------------------------------------- +reset_db +do_execsql_test 15.0 { + CREATE TABLE t1(a integer NOT NULL PRIMARY KEY); + CREATE VIEW v1 AS SELECT a FROM t1; + CREATE TRIGGER tr1 INSTEAD OF INSERT ON v1 BEGIN + UPDATE t1 SET a = NEW.a; + END; + CREATE TRIGGER tr2 INSTEAD OF INSERT ON v1 BEGIN + SELECT new.a; + END; + CREATE TABLE t2 (b); +} + +do_execsql_test 15.1 { + INSERT INTO v1 VALUES(1); + ALTER TABLE t2 RENAME TO t3; +} + +do_execsql_test 15.2 { + CREATE TABLE x(f1 integer NOT NULL); + CREATE VIEW y AS SELECT f1 AS f1 FROM x; + CREATE TRIGGER t INSTEAD OF UPDATE OF f1 ON y BEGIN + UPDATE x SET f1 = NEW.f1; + END; + CREATE TABLE z (f1 integer NOT NULL PRIMARY KEY); + ALTER TABLE z RENAME TO z2; +} + +do_execsql_test 15.3 { + INSERT INTO x VALUES(1), (2), (3); + ALTER TABLE x RENAME f1 TO f2; + SELECT * FROM x; +} {1 2 3} + +do_execsql_test 15.4 { + UPDATE y SET f1 = 'x' WHERE f1 = 1; + SELECT * FROM x; +} {x x x} + +do_execsql_test 15.5 { + SELECT sql FROM sqlite_master WHERE name = 'y'; +} {{CREATE VIEW y AS SELECT f2 AS f1 FROM x}} finish_test From 44d068532ef5fca98e0d7243addb13cd50d07596 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Oct 2018 13:54:30 +0000 Subject: [PATCH 004/109] Fix a potential crash that can occur while reading an index from a corrupt database file. The corruption is a record-header-size that is larger than 0x7fffffff. Problem detected by OSSFuzz against GDAL and reported to us (with a suggested fix) by Even Rouault. The test case is in TH3. FossilOrigin-Name: 8ac2cdda68f92b0352bc7f0b4be5fca4bb58565ca65055fb34153cc284ed6922 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/vdbeaux.c | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index b5a3086cb6..3cea376d3c 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\sALTER\sTABLE\scommands\swhen\sthe\sschema\sfeatures\san\sINSTEAD\sof\ntrigger\sthat\suses\sNEW.*\sor\sOLD.*. -D 2018-10-01T07:04:12.490 +C Fix\sa\spotential\scrash\sthat\scan\soccur\swhile\sreading\san\sindex\sfrom\sa\scorrupt\ndatabase\sfile.\s\sThe\scorruption\sis\sa\srecord-header-size\sthat\sis\slarger\sthan\n0x7fffffff.\s\sProblem\sdetected\sby\sOSSFuzz\sagainst\sGDAL\sand\sreported\sto\sus\s\n(with\sa\ssuggested\sfix)\sby\sEven\sRouault.\s\sThe\stest\scase\sis\sin\sTH3. +D 2018-10-01T13:54:30.911 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -578,7 +578,7 @@ F src/vdbe.c 005e691ea4c7d51e6c1a69d9389aeb34700884c85f51681817ddea3fdc2fc39b F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827 F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 -F src/vdbeaux.c c3c397274380f13db702baa3506ba87379446a4d71135a1177b624f73dd3c830 +F src/vdbeaux.c 9fe7760a6b9739f21f3e19ad5364330b0f681998fc52c32358243b0060423474 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641 F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d04b2013b5436430ebbf7053d637fd89c1b15affcb42787dcf1cf5ffc3ae54e2 -R 479306dd49205e8d1f89a577af9e0033 -U dan -Z 3eb383fba7fc036a1656cc373d9dc1ea +P c52f457e56eb9d573eb67093731eb231aaf6fd6dbdc397e6f948b82736fbe3ab +R c75c41f8def35162ce620ba59792b15c +U drh +Z 2db3890d5903ac5d614f7b18f951a8a9 diff --git a/manifest.uuid b/manifest.uuid index e3f42f7fe9..d9b29688df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c52f457e56eb9d573eb67093731eb231aaf6fd6dbdc397e6f948b82736fbe3ab \ No newline at end of file +8ac2cdda68f92b0352bc7f0b4be5fca4bb58565ca65055fb34153cc284ed6922 \ No newline at end of file diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 5ec3d131e0..99df435966 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -4557,7 +4557,9 @@ int sqlite3VdbeIdxRowid(sqlite3 *db, BtCursor *pCur, i64 *rowid){ (void)getVarint32((u8*)m.z, szHdr); testcase( szHdr==3 ); testcase( szHdr==m.n ); - if( unlikely(szHdr<3 || (int)szHdr>m.n) ){ + testcase( szHdr>0x7fffffff ); + assert( m.n>=0 ); + if( unlikely(szHdr<3 || szHdr>(unsigned)m.n) ){ goto idx_rowid_corruption; } From 49f84ce1cde53b03a92f3bf00c47d37a7f609c7e Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 1 Oct 2018 17:33:35 +0000 Subject: [PATCH 005/109] Speed up xAccess() calls made on an RBU VFS when there are lots of open connections. FossilOrigin-Name: 310b4b65b8c8ee080760c7efb4c7e20244c6063a5dba37a4f40490105aafd29f --- ext/rbu/sqlite3rbu.c | 100 ++++++++++++++++++++++++++++++++----------- manifest | 14 +++--- manifest.uuid | 2 +- 3 files changed, 82 insertions(+), 34 deletions(-) diff --git a/ext/rbu/sqlite3rbu.c b/ext/rbu/sqlite3rbu.c index 065b13c7fa..cd2f96c51b 100644 --- a/ext/rbu/sqlite3rbu.c +++ b/ext/rbu/sqlite3rbu.c @@ -405,7 +405,8 @@ struct rbu_vfs { sqlite3_vfs *pRealVfs; /* Underlying VFS */ sqlite3_mutex *mutex; /* Mutex to protect pMain */ sqlite3rbu *pRbu; /* Owner RBU object */ - rbu_file *pMain; /* Linked list of main db files */ + rbu_file *pMain; /* List of main db files */ + rbu_file *pMainRbu; /* List of main db files with pRbu!=0 */ }; /* @@ -434,6 +435,7 @@ struct rbu_file { const char *zWal; /* Wal filename for this main db file */ rbu_file *pWalFd; /* Wal file descriptor for this main db */ rbu_file *pMainNext; /* Next MAIN_DB file */ + rbu_file *pMainRbuNext; /* Next MAIN_DB file with pRbu!=0 */ }; /* @@ -4030,6 +4032,69 @@ static int rbuUpdateTempSize(rbu_file *pFd, sqlite3_int64 nNew){ return SQLITE_OK; } +/* +** Add an item to the main-db lists, if it is not already present. +** +** There are two main-db lists. One for all file descriptors, and one +** for all file descriptors with rbu_file.pDb!=0. If the argument has +** rbu_file.pDb!=0, then it is assumed to already be present on the +** main list and is only added to the pDb!=0 list. +*/ +static void rbuMainlistAdd(rbu_file *p){ + rbu_vfs *pRbuVfs = p->pRbuVfs; + rbu_file *pIter; + assert( (p->openFlags & SQLITE_OPEN_MAIN_DB) ); + sqlite3_mutex_enter(pRbuVfs->mutex); + if( p->pRbu==0 ){ + for(pIter=pRbuVfs->pMain; pIter; pIter=pIter->pMainNext); + p->pMainNext = pRbuVfs->pMain; + pRbuVfs->pMain = p; + }else{ + for(pIter=pRbuVfs->pMainRbu; pIter && pIter!=p; pIter=pIter->pMainRbuNext){} + if( pIter==0 ){ + p->pMainRbuNext = pRbuVfs->pMainRbu; + pRbuVfs->pMainRbu = p; + } + } + sqlite3_mutex_leave(pRbuVfs->mutex); +} + +/* +** Remove an item from the main-db lists. +*/ +static void rbuMainlistRemove(rbu_file *p){ + rbu_file **pp; + sqlite3_mutex_enter(p->pRbuVfs->mutex); + for(pp=&p->pRbuVfs->pMain; *pp && *pp!=p; pp=&((*pp)->pMainNext)){} + if( *pp ) *pp = p->pMainNext; + p->pMainNext = 0; + for(pp=&p->pRbuVfs->pMainRbu; *pp && *pp!=p; pp=&((*pp)->pMainRbuNext)){} + if( *pp ) *pp = p->pMainRbuNext; + p->pMainRbuNext = 0; + sqlite3_mutex_leave(p->pRbuVfs->mutex); +} + +/* +** Given that zWal points to a buffer containing a wal file name passed to +** either the xOpen() or xAccess() VFS method, search the main-db list for +** a file-handle opened by the same database connection on the corresponding +** database file. +** +** If parameter bRbu is true, only search for file-descriptors with +** rbu_file.pDb!=0. +*/ +static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal, int bRbu){ + rbu_file *pDb; + sqlite3_mutex_enter(pRbuVfs->mutex); + if( bRbu ){ + for(pDb=pRbuVfs->pMainRbu; pDb && pDb->zWal!=zWal; pDb=pDb->pMainRbuNext){} + }else{ + for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} + } + sqlite3_mutex_leave(pRbuVfs->mutex); + return pDb; +} + /* ** Close an rbu file. */ @@ -4047,17 +4112,14 @@ static int rbuVfsClose(sqlite3_file *pFile){ sqlite3_free(p->zDel); if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ - rbu_file **pp; - sqlite3_mutex_enter(p->pRbuVfs->mutex); - for(pp=&p->pRbuVfs->pMain; *pp!=p; pp=&((*pp)->pMainNext)); - *pp = p->pMainNext; - sqlite3_mutex_leave(p->pRbuVfs->mutex); + rbuMainlistRemove(p); rbuUnlockShm(p); p->pReal->pMethods->xShmUnmap(p->pReal, 0); } else if( (p->openFlags & SQLITE_OPEN_DELETEONCLOSE) && p->pRbu ){ rbuUpdateTempSize(p, 0); } + assert( p->pMainNext==0 && p->pRbuVfs->pMain!=p ); /* Close the underlying file handle */ rc = p->pReal->pMethods->xClose(p->pReal); @@ -4316,6 +4378,9 @@ static int rbuVfsFileControl(sqlite3_file *pFile, int op, void *pArg){ }else if( rc==SQLITE_NOTFOUND ){ pRbu->pTargetFd = p; p->pRbu = pRbu; + if( p->openFlags & SQLITE_OPEN_MAIN_DB ){ + rbuMainlistAdd(p); + } if( p->pWalFd ) p->pWalFd->pRbu = pRbu; rc = SQLITE_OK; } @@ -4477,20 +4542,6 @@ static int rbuVfsShmUnmap(sqlite3_file *pFile, int delFlag){ return rc; } -/* -** Given that zWal points to a buffer containing a wal file name passed to -** either the xOpen() or xAccess() VFS method, return a pointer to the -** file-handle opened by the same database connection on the corresponding -** database file. -*/ -static rbu_file *rbuFindMaindb(rbu_vfs *pRbuVfs, const char *zWal){ - rbu_file *pDb; - sqlite3_mutex_enter(pRbuVfs->mutex); - for(pDb=pRbuVfs->pMain; pDb && pDb->zWal!=zWal; pDb=pDb->pMainNext){} - sqlite3_mutex_leave(pRbuVfs->mutex); - return pDb; -} - /* ** A main database named zName has just been opened. The following ** function returns a pointer to a buffer owned by SQLite that contains @@ -4569,7 +4620,7 @@ static int rbuVfsOpen( pFd->zWal = rbuMainToWal(zName, flags); } else if( flags & SQLITE_OPEN_WAL ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zName, 0); if( pDb ){ if( pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ /* This call is to open a *-wal file. Intead, open the *-oal. This @@ -4621,10 +4672,7 @@ static int rbuVfsOpen( ** mutex protected linked list of all such files. */ pFile->pMethods = &rbuvfs_io_methods; if( flags & SQLITE_OPEN_MAIN_DB ){ - sqlite3_mutex_enter(pRbuVfs->mutex); - pFd->pMainNext = pRbuVfs->pMain; - pRbuVfs->pMain = pFd; - sqlite3_mutex_leave(pRbuVfs->mutex); + rbuMainlistAdd(pFd); } }else{ sqlite3_free(pFd->zDel); @@ -4672,7 +4720,7 @@ static int rbuVfsAccess( ** file opened instead. */ if( rc==SQLITE_OK && flags==SQLITE_ACCESS_EXISTS ){ - rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath); + rbu_file *pDb = rbuFindMaindb(pRbuVfs, zPath, 1); if( pDb && pDb->pRbu && pDb->pRbu->eStage==RBU_STAGE_OAL ){ if( *pResOut ){ rc = SQLITE_CANTOPEN; diff --git a/manifest b/manifest index 3cea376d3c..8c7dc34921 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\spotential\scrash\sthat\scan\soccur\swhile\sreading\san\sindex\sfrom\sa\scorrupt\ndatabase\sfile.\s\sThe\scorruption\sis\sa\srecord-header-size\sthat\sis\slarger\sthan\n0x7fffffff.\s\sProblem\sdetected\sby\sOSSFuzz\sagainst\sGDAL\sand\sreported\sto\sus\s\n(with\sa\ssuggested\sfix)\sby\sEven\sRouault.\s\sThe\stest\scase\sis\sin\sTH3. -D 2018-10-01T13:54:30.911 +C Speed\sup\sxAccess()\scalls\smade\son\san\sRBU\sVFS\swhen\sthere\sare\slots\sof\sopen\nconnections. +D 2018-10-01T17:33:35.846 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -348,7 +348,7 @@ F ext/rbu/rbusplit.test 69271c790732b28bd465551d80b0a9a3f074e189896ee8490ce56d22 F ext/rbu/rbutemplimit.test cd553a9288d515d0b5f87d277e76fd18c4aa740b761e7880fab11ce986ea18d1 F ext/rbu/rbuvacuum.test ff357e9b556ca7ad4673da0ff7f244def919ff858e0f9f350d3e30fdd83a62a8 F ext/rbu/rbuvacuum2.test 2074ab14fe66e1c7e7210c62562650dcd215bbaa -F ext/rbu/sqlite3rbu.c f438fea899d15d13ff3e3133242b9e378c37b5a3d76add8c342c68bdd65c6819 +F ext/rbu/sqlite3rbu.c 71f8c09948d09ec9c5a8dbe7127e8ef61ef0853e698b2650be2485ac7b9c75c8 F ext/rbu/sqlite3rbu.h b42bcd4d8357268c6c39ab2a60b29c091e89328fa8cc49c8fac5ab8d007e79b2 F ext/rbu/test_rbu.c baa23eb28457580673d2175e5f0c29ced0cd320ee819b13ad362398c53b96e90 F ext/repair/README.md 92f5e8aae749a4dae14f02eea8e1bb42d4db2b6ce5e83dbcdd6b1446997e0c15 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P c52f457e56eb9d573eb67093731eb231aaf6fd6dbdc397e6f948b82736fbe3ab -R c75c41f8def35162ce620ba59792b15c -U drh -Z 2db3890d5903ac5d614f7b18f951a8a9 +P 8ac2cdda68f92b0352bc7f0b4be5fca4bb58565ca65055fb34153cc284ed6922 +R a63f057a754c642de8f2617ecd7043d5 +U dan +Z c6e86f7777ba1872e2992f69103701bb diff --git a/manifest.uuid b/manifest.uuid index d9b29688df..8b77660070 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8ac2cdda68f92b0352bc7f0b4be5fca4bb58565ca65055fb34153cc284ed6922 \ No newline at end of file +310b4b65b8c8ee080760c7efb4c7e20244c6063a5dba37a4f40490105aafd29f \ No newline at end of file From d7dc0a36cc94e4b1e00751404997006b8c85edc0 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Oct 2018 18:28:42 +0000 Subject: [PATCH 006/109] Add the extra "hidden" column to the end of the PRAGMA table_vinfo output. FossilOrigin-Name: cf1b76135f511530dcc7b82f78c952bf97ebcddb40be06f713f9f2326915fabe --- manifest | 16 +++--- manifest.uuid | 2 +- src/pragma.c | 10 ++-- src/pragma.h | 131 +++++++++++++++++++++++-------------------- tool/mkpragmatab.tcl | 2 +- 5 files changed, 85 insertions(+), 76 deletions(-) diff --git a/manifest b/manifest index f617858a9c..25f7ffaa95 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bring\sthe\sPRAGMA\stable_vinfo\sstatement\sup\sto\sdate\swith\strunk. -D 2018-10-01T17:15:17.712 +C Add\sthe\sextra\s"hidden"\scolumn\sto\sthe\send\sof\sthe\sPRAGMA\stable_vinfo\soutput. +D 2018-10-01T18:28:42.916 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -496,8 +496,8 @@ F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179 F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 -F src/pragma.c e49a1f19fba8cf73cc021d3603ea78ab4fd014387eb8e6d9254df7a92a4d2b5b -F src/pragma.h 6eefd8c5b4313106ec739189cf0e496fc654e2eeb42040471d564dd6cf219b7a +F src/pragma.c a656ff043a03bd94153e6d731a3fbf1bb420207edc969d8fc04b4d2448387901 +F src/pragma.h 32e7736d98684ecb190765eb51bc60aff6b30e081c03a0325ec768344e3fc495 F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 @@ -1703,7 +1703,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl 75de913fcf553b7a2e824cfa1ec7def195a18bd5454a3d1a31363531440ddb80 +F tool/mkpragmatab.tcl 03d3373f6f98a6a195a5bc78ee4b2b276eb4b692e991304c49c8f03f35c75755 F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 8bcd1a59560aa7ea73e6529e5c14ece8ac09bf7e99efdcfd388fead39846b6bf 8ac2cdda68f92b0352bc7f0b4be5fca4bb58565ca65055fb34153cc284ed6922 -R bd732e5d21844f33cc33bac99fb310a8 +P 6f606f99231f88ae5ff719d0ce21afc4b844490102c27ac20aa606baaf78d8d6 +R 8168cb89d6e5deec90702b5288566db2 U drh -Z dbdcb40d11c49c4a64c4b70e1aed2a0b +Z a68eabb459073457887cbb002b95bf23 diff --git a/manifest.uuid b/manifest.uuid index bc4f7bafb3..2122c4fb06 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -6f606f99231f88ae5ff719d0ce21afc4b844490102c27ac20aa606baaf78d8d6 \ No newline at end of file +cf1b76135f511530dcc7b82f78c952bf97ebcddb40be06f713f9f2326915fabe \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index b0884895b4..fd08cc202c 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1090,11 +1090,12 @@ void sqlite3Pragma( int nHidden = 0; Column *pCol; Index *pPk = sqlite3PrimaryKeyIndex(pTab); - pParse->nMem = 6; + pParse->nMem = 7; sqlite3CodeVerifySchema(pParse, iDb); sqlite3ViewGetColumnNames(pParse, pTab); for(i=0, pCol=pTab->aCol; inCol; i++, pCol++){ - if( IsHiddenColumn(pCol) && pPragma->iArg==0 ){ + int isHidden = IsHiddenColumn(pCol); + if( isHidden && pPragma->iArg==0 ){ nHidden++; continue; } @@ -1106,13 +1107,14 @@ void sqlite3Pragma( for(k=1; k<=pTab->nCol && pPk->aiColumn[k-1]!=i; k++){} } assert( pCol->pDflt==0 || pCol->pDflt->op==TK_SPAN ); - sqlite3VdbeMultiLoad(v, 1, "issisi", + sqlite3VdbeMultiLoad(v, 1, pPragma->iArg ? "issisii" : "issisi", i-nHidden, pCol->zName, sqlite3ColumnType(pCol,""), pCol->notNull ? 1 : 0, pCol->pDflt ? pCol->pDflt->u.zToken : 0, - k); + k, + isHidden); } } } diff --git a/src/pragma.h b/src/pragma.h index 389f2f4117..371453649a 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -69,57 +69,64 @@ */ static const char *const pragCName[] = { /* 0 */ "cache_size", /* Used by: default_cache_size */ - /* 1 */ "cid", /* Used by: table_info table_vinfo */ + /* 1 */ "cid", /* Used by: table_info */ /* 2 */ "name", /* 3 */ "type", /* 4 */ "notnull", /* 5 */ "dflt_value", /* 6 */ "pk", - /* 7 */ "tbl", /* Used by: stats */ - /* 8 */ "idx", - /* 9 */ "wdth", - /* 10 */ "hght", - /* 11 */ "flgs", - /* 12 */ "seqno", /* Used by: index_info */ - /* 13 */ "cid", - /* 14 */ "name", - /* 15 */ "seqno", /* Used by: index_xinfo */ - /* 16 */ "cid", - /* 17 */ "name", - /* 18 */ "desc", - /* 19 */ "coll", - /* 20 */ "key", - /* 21 */ "seq", /* Used by: index_list */ - /* 22 */ "name", - /* 23 */ "unique", - /* 24 */ "origin", - /* 25 */ "partial", - /* 26 */ "seq", /* Used by: database_list */ - /* 27 */ "name", - /* 28 */ "file", - /* 29 */ "name", /* Used by: function_list */ - /* 30 */ "builtin", - /* 31 */ "name", /* Used by: module_list pragma_list */ - /* 32 */ "seq", /* Used by: collation_list */ - /* 33 */ "name", - /* 34 */ "id", /* Used by: foreign_key_list */ - /* 35 */ "seq", - /* 36 */ "table", - /* 37 */ "from", - /* 38 */ "to", - /* 39 */ "on_update", - /* 40 */ "on_delete", - /* 41 */ "match", - /* 42 */ "table", /* Used by: foreign_key_check */ - /* 43 */ "rowid", - /* 44 */ "parent", - /* 45 */ "fkid", - /* 46 */ "busy", /* Used by: wal_checkpoint */ - /* 47 */ "log", - /* 48 */ "checkpointed", - /* 49 */ "timeout", /* Used by: busy_timeout */ - /* 50 */ "database", /* Used by: lock_status */ - /* 51 */ "status", + /* 7 */ "cid", /* Used by: table_vinfo */ + /* 8 */ "name", + /* 9 */ "type", + /* 10 */ "notnull", + /* 11 */ "dflt_value", + /* 12 */ "pk", + /* 13 */ "hidden", + /* 14 */ "tbl", /* Used by: stats */ + /* 15 */ "idx", + /* 16 */ "wdth", + /* 17 */ "hght", + /* 18 */ "flgs", + /* 19 */ "seqno", /* Used by: index_info */ + /* 20 */ "cid", + /* 21 */ "name", + /* 22 */ "seqno", /* Used by: index_xinfo */ + /* 23 */ "cid", + /* 24 */ "name", + /* 25 */ "desc", + /* 26 */ "coll", + /* 27 */ "key", + /* 28 */ "seq", /* Used by: index_list */ + /* 29 */ "name", + /* 30 */ "unique", + /* 31 */ "origin", + /* 32 */ "partial", + /* 33 */ "seq", /* Used by: database_list */ + /* 34 */ "name", + /* 35 */ "file", + /* 36 */ "name", /* Used by: function_list */ + /* 37 */ "builtin", + /* 38 */ "name", /* Used by: module_list pragma_list */ + /* 39 */ "seq", /* Used by: collation_list */ + /* 40 */ "name", + /* 41 */ "id", /* Used by: foreign_key_list */ + /* 42 */ "seq", + /* 43 */ "table", + /* 44 */ "from", + /* 45 */ "to", + /* 46 */ "on_update", + /* 47 */ "on_delete", + /* 48 */ "match", + /* 49 */ "table", /* Used by: foreign_key_check */ + /* 50 */ "rowid", + /* 51 */ "parent", + /* 52 */ "fkid", + /* 53 */ "busy", /* Used by: wal_checkpoint */ + /* 54 */ "log", + /* 55 */ "checkpointed", + /* 56 */ "timeout", /* Used by: busy_timeout */ + /* 57 */ "database", /* Used by: lock_status */ + /* 58 */ "status", }; /* Definitions of all built-in pragmas */ @@ -165,7 +172,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 49, 1, + /* ColNames: */ 56, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -202,7 +209,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 32, 2, + /* ColNames: */ 39, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -237,7 +244,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 26, 3, + /* ColNames: */ 33, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) @@ -274,14 +281,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 42, 4, + /* ColNames: */ 49, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 34, 8, + /* ColNames: */ 41, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -317,7 +324,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 29, 2, + /* ColNames: */ 36, 2, /* iArg: */ 0 }, #endif #endif @@ -353,17 +360,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 12, 3, + /* ColNames: */ 19, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 21, 5, + /* ColNames: */ 28, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 15, 6, + /* ColNames: */ 22, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -415,7 +422,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 50, 2, + /* ColNames: */ 57, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -441,7 +448,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 31, 1, + /* ColNames: */ 38, 1, /* iArg: */ 0 }, #endif #endif @@ -474,7 +481,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "pragma_list", /* ePragTyp: */ PragTyp_PRAGMA_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 31, 1, + /* ColNames: */ 38, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -561,7 +568,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 7, 5, + /* ColNames: */ 14, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -580,7 +587,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_vinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 1, 6, + /* ColNames: */ 7, 7, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -645,7 +652,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 46, 3, + /* ColNames: */ 53, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -656,4 +663,4 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_WriteSchema }, #endif }; -/* Number of pragmas: 61 on by default, 78 total. */ +/* Number of pragmas: 62 on by default, 79 total. */ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 26b7e6e0b6..dd0836fba5 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -228,7 +228,7 @@ set pragma_def { TYPE: TABLE_INFO FLAG: NeedSchema Result1 SchemaOpt ARG: 1 - COLS: cid name type notnull dflt_value pk + COLS: cid name type notnull dflt_value pk hidden IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) NAME: stats From bdc9744f603eadefcd0afb783accf2fc211cc627 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Oct 2018 21:26:30 +0000 Subject: [PATCH 007/109] Change the name of the pragma to PRAGMA table_xinfo. Improve the mkpragmatab.tcl script to reuse column names where appropriate. FossilOrigin-Name: 2fdd068987e59b979045d71ae64e700600ef07e54ae340f30c2064e5dcccb8ea --- manifest | 14 ++--- manifest.uuid | 2 +- src/pragma.h | 146 ++++++++++++++++++++----------------------- tool/mkpragmatab.tcl | 38 ++++++++--- 4 files changed, 106 insertions(+), 94 deletions(-) diff --git a/manifest b/manifest index 25f7ffaa95..5f496d1dd4 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sextra\s"hidden"\scolumn\sto\sthe\send\sof\sthe\sPRAGMA\stable_vinfo\soutput. -D 2018-10-01T18:28:42.916 +C Change\sthe\sname\sof\sthe\spragma\sto\sPRAGMA\stable_xinfo.\s\sImprove\sthe\nmkpragmatab.tcl\sscript\sto\sreuse\scolumn\snames\swhere\sappropriate. +D 2018-10-01T21:26:30.705 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -497,7 +497,7 @@ F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 F src/pragma.c a656ff043a03bd94153e6d731a3fbf1bb420207edc969d8fc04b4d2448387901 -F src/pragma.h 32e7736d98684ecb190765eb51bc60aff6b30e081c03a0325ec768344e3fc495 +F src/pragma.h 0ea639401ed7b8275c145e3a814119831e296118b545421e76ae2e1516f10ad8 F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 @@ -1703,7 +1703,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl 03d3373f6f98a6a195a5bc78ee4b2b276eb4b692e991304c49c8f03f35c75755 +F tool/mkpragmatab.tcl fc895d5a40e725b19b866b058b3994bfc45db3e7fef40db9e6c6fd921bf8a337 F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 6f606f99231f88ae5ff719d0ce21afc4b844490102c27ac20aa606baaf78d8d6 -R 8168cb89d6e5deec90702b5288566db2 +P cf1b76135f511530dcc7b82f78c952bf97ebcddb40be06f713f9f2326915fabe +R ba010eae61cf933e84f1d1c261299063 U drh -Z a68eabb459073457887cbb002b95bf23 +Z 03cca8b8402459da514c7ddddb7143b7 diff --git a/manifest.uuid b/manifest.uuid index 2122c4fb06..5f1369d3fb 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cf1b76135f511530dcc7b82f78c952bf97ebcddb40be06f713f9f2326915fabe \ No newline at end of file +2fdd068987e59b979045d71ae64e700600ef07e54ae340f30c2064e5dcccb8ea \ No newline at end of file diff --git a/src/pragma.h b/src/pragma.h index 371453649a..3d1ba4f341 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -68,65 +68,57 @@ ** result column is different from the name of the pragma */ static const char *const pragCName[] = { - /* 0 */ "cache_size", /* Used by: default_cache_size */ - /* 1 */ "cid", /* Used by: table_info */ - /* 2 */ "name", - /* 3 */ "type", - /* 4 */ "notnull", - /* 5 */ "dflt_value", - /* 6 */ "pk", - /* 7 */ "cid", /* Used by: table_vinfo */ - /* 8 */ "name", - /* 9 */ "type", - /* 10 */ "notnull", - /* 11 */ "dflt_value", - /* 12 */ "pk", - /* 13 */ "hidden", - /* 14 */ "tbl", /* Used by: stats */ - /* 15 */ "idx", - /* 16 */ "wdth", - /* 17 */ "hght", - /* 18 */ "flgs", - /* 19 */ "seqno", /* Used by: index_info */ - /* 20 */ "cid", - /* 21 */ "name", - /* 22 */ "seqno", /* Used by: index_xinfo */ - /* 23 */ "cid", - /* 24 */ "name", - /* 25 */ "desc", - /* 26 */ "coll", - /* 27 */ "key", - /* 28 */ "seq", /* Used by: index_list */ - /* 29 */ "name", - /* 30 */ "unique", - /* 31 */ "origin", - /* 32 */ "partial", - /* 33 */ "seq", /* Used by: database_list */ - /* 34 */ "name", - /* 35 */ "file", - /* 36 */ "name", /* Used by: function_list */ - /* 37 */ "builtin", - /* 38 */ "name", /* Used by: module_list pragma_list */ - /* 39 */ "seq", /* Used by: collation_list */ - /* 40 */ "name", - /* 41 */ "id", /* Used by: foreign_key_list */ - /* 42 */ "seq", - /* 43 */ "table", - /* 44 */ "from", - /* 45 */ "to", - /* 46 */ "on_update", - /* 47 */ "on_delete", - /* 48 */ "match", - /* 49 */ "table", /* Used by: foreign_key_check */ - /* 50 */ "rowid", - /* 51 */ "parent", - /* 52 */ "fkid", - /* 53 */ "busy", /* Used by: wal_checkpoint */ - /* 54 */ "log", - /* 55 */ "checkpointed", - /* 56 */ "timeout", /* Used by: busy_timeout */ - /* 57 */ "database", /* Used by: lock_status */ - /* 58 */ "status", + /* 0 */ "id", /* Used by: foreign_key_list */ + /* 1 */ "seq", + /* 2 */ "table", + /* 3 */ "from", + /* 4 */ "to", + /* 5 */ "on_update", + /* 6 */ "on_delete", + /* 7 */ "match", + /* 8 */ "cid", /* Used by: table_xinfo */ + /* 9 */ "name", + /* 10 */ "type", + /* 11 */ "notnull", + /* 12 */ "dflt_value", + /* 13 */ "pk", + /* 14 */ "hidden", + /* table_info reuses 8 */ + /* 15 */ "seqno", /* Used by: index_xinfo */ + /* 16 */ "cid", + /* 17 */ "name", + /* 18 */ "desc", + /* 19 */ "coll", + /* 20 */ "key", + /* 21 */ "tbl", /* Used by: stats */ + /* 22 */ "idx", + /* 23 */ "wdth", + /* 24 */ "hght", + /* 25 */ "flgs", + /* 26 */ "seq", /* Used by: index_list */ + /* 27 */ "name", + /* 28 */ "unique", + /* 29 */ "origin", + /* 30 */ "partial", + /* 31 */ "table", /* Used by: foreign_key_check */ + /* 32 */ "rowid", + /* 33 */ "parent", + /* 34 */ "fkid", + /* index_info reuses 15 */ + /* 35 */ "seq", /* Used by: database_list */ + /* 36 */ "name", + /* 37 */ "file", + /* 38 */ "busy", /* Used by: wal_checkpoint */ + /* 39 */ "log", + /* 40 */ "checkpointed", + /* 41 */ "name", /* Used by: function_list */ + /* 42 */ "builtin", + /* collation_list reuses 26 */ + /* 43 */ "database", /* Used by: lock_status */ + /* 44 */ "status", + /* 45 */ "cache_size", /* Used by: default_cache_size */ + /* module_list pragma_list reuses 9 */ + /* 46 */ "timeout", /* Used by: busy_timeout */ }; /* Definitions of all built-in pragmas */ @@ -172,7 +164,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "busy_timeout", /* ePragTyp: */ PragTyp_BUSY_TIMEOUT, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 56, 1, + /* ColNames: */ 46, 1, /* iArg: */ 0 }, #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) {/* zName: */ "cache_size", @@ -209,7 +201,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "collation_list", /* ePragTyp: */ PragTyp_COLLATION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 39, 2, + /* ColNames: */ 26, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_COMPILEOPTION_DIAGS) @@ -244,14 +236,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "database_list", /* ePragTyp: */ PragTyp_DATABASE_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 33, 3, + /* ColNames: */ 35, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) && !defined(SQLITE_OMIT_DEPRECATED) {/* zName: */ "default_cache_size", /* ePragTyp: */ PragTyp_DEFAULT_CACHE_SIZE, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq|PragFlg_NoColumns1, - /* ColNames: */ 0, 1, + /* ColNames: */ 45, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -281,14 +273,14 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "foreign_key_check", /* ePragTyp: */ PragTyp_FOREIGN_KEY_CHECK, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0, - /* ColNames: */ 49, 4, + /* ColNames: */ 31, 4, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FOREIGN_KEY) {/* zName: */ "foreign_key_list", /* ePragTyp: */ PragTyp_FOREIGN_KEY_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 41, 8, + /* ColNames: */ 0, 8, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -324,7 +316,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "function_list", /* ePragTyp: */ PragTyp_FUNCTION_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 36, 2, + /* ColNames: */ 41, 2, /* iArg: */ 0 }, #endif #endif @@ -360,17 +352,17 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "index_info", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 19, 3, + /* ColNames: */ 15, 3, /* iArg: */ 0 }, {/* zName: */ "index_list", /* ePragTyp: */ PragTyp_INDEX_LIST, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 28, 5, + /* ColNames: */ 26, 5, /* iArg: */ 0 }, {/* zName: */ "index_xinfo", /* ePragTyp: */ PragTyp_INDEX_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 22, 6, + /* ColNames: */ 15, 6, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_INTEGRITY_CHECK) @@ -422,7 +414,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "lock_status", /* ePragTyp: */ PragTyp_LOCK_STATUS, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 57, 2, + /* ColNames: */ 43, 2, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -448,7 +440,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "module_list", /* ePragTyp: */ PragTyp_MODULE_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 1, + /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #endif @@ -481,7 +473,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "pragma_list", /* ePragTyp: */ PragTyp_PRAGMA_LIST, /* ePragFlg: */ PragFlg_Result0, - /* ColNames: */ 38, 1, + /* ColNames: */ 9, 1, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) @@ -568,7 +560,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "stats", /* ePragTyp: */ PragTyp_STATS, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result0|PragFlg_SchemaReq, - /* ColNames: */ 14, 5, + /* ColNames: */ 21, 5, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -582,12 +574,12 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "table_info", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 1, 6, + /* ColNames: */ 8, 6, /* iArg: */ 0 }, - {/* zName: */ "table_vinfo", + {/* zName: */ "table_xinfo", /* ePragTyp: */ PragTyp_TABLE_INFO, /* ePragFlg: */ PragFlg_NeedSchema|PragFlg_Result1|PragFlg_SchemaOpt, - /* ColNames: */ 7, 7, + /* ColNames: */ 8, 7, /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_PAGER_PRAGMAS) @@ -652,7 +644,7 @@ static const PragmaName aPragmaName[] = { {/* zName: */ "wal_checkpoint", /* ePragTyp: */ PragTyp_WAL_CHECKPOINT, /* ePragFlg: */ PragFlg_NeedSchema, - /* ColNames: */ 53, 3, + /* ColNames: */ 38, 3, /* iArg: */ 0 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index dd0836fba5..c40e3f5b77 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -224,7 +224,7 @@ set pragma_def { COLS: cid name type notnull dflt_value pk IF: !defined(SQLITE_OMIT_SCHEMA_PRAGMAS) - NAME: table_vinfo + NAME: table_xinfo TYPE: TABLE_INFO FLAG: NeedSchema Result1 SchemaOpt ARG: 1 @@ -418,20 +418,20 @@ set cols {} set cols_list {} set arg 0 proc record_one {} { - global name type if arg allbyname typebyif flags cols allcols + global name type if arg allbyname typebyif flags cols all_cols global cols_list colUsedBy if {$name==""} return if {$cols!=""} { - if {![info exists allcols($cols)]} { + if {![info exists all_cols($cols)]} { + set all_cols($cols) 1 lappend cols_list $cols - set allcols($cols) [llength $cols_list] } - set cx $allcols($cols) + set cx $cols lappend colUsedBy($cols) $name } else { set cx 0 } - set allbyname($name) [list $type $arg $if $flags $cx] + set allbyname($name) [list $type $arg $if $flags $cols] set name {} set type {} set if {} @@ -513,6 +513,13 @@ foreach f [lsort [array names allflags]] { set fv [expr {$fv*2}] } +# Sort the column lists so that longer column lists occur first +# +proc colscmp {a b} { + return [expr {[llength $b] - [llength $a]}] +} +set cols_list [lsort -command colscmp $cols_list] + # Generate the array of column names used by pragmas that act like # queries. # @@ -521,10 +528,23 @@ puts $fd "** or that return single-column results where the name of the" puts $fd "** result column is different from the name of the pragma\n*/" puts $fd "static const char *const pragCName\[\] = {" set offset 0 +set allcollist {} foreach cols $cols_list { - set cols_offset($allcols($cols)) $offset + set n [llength $cols] + set limit [expr {[llength $allcollist] - $n}] + for {set i 0} {$i<$limit} {incr i} { + set sublist [lrange $allcollist $i [expr {$i+$n-1}]] + if {$sublist==$cols} { + puts $fd [format "%27s/* $colUsedBy($cols) reuses $i */" ""] + set cols_offset($cols) $i + break + } + } + if {$i<$limit} continue + set cols_offset($cols) $offset set ub " /* Used by: $colUsedBy($cols) */" foreach c $cols { + lappend allcollist $c puts $fd [format " /* %3d */ %-14s%s" $offset \"$c\", $ub] set ub "" incr offset @@ -550,12 +570,12 @@ set current_if {} set spacer [format { %26s } {}] foreach name $allnames { foreach {type arg if flag cx} $allbyname($name) break - if {$cx==0} { + if {$cx==0 || $cx==""} { set cy 0 set nx 0 } else { set cy $cols_offset($cx) - set nx [llength [lindex $cols_list [expr {$cx-1}]]] + set nx [llength $cx] } if {$if!=$current_if} { if {$current_if!=""} { From bfbf7d9daa177e9bc61fbddeb13958f5a727ad97 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 1 Oct 2018 21:36:38 +0000 Subject: [PATCH 008/109] Test case for PRAGMA table_xinfo. FossilOrigin-Name: 7694b9bc3003db6ba0b41c5029c8f7b84c07724e7a518e835e98b3c46e4ea227 --- manifest | 12 ++++++------ manifest.uuid | 2 +- test/tabfunc01.test | 3 +++ 3 files changed, 10 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 5f496d1dd4..7febae11fa 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sthe\sname\sof\sthe\spragma\sto\sPRAGMA\stable_xinfo.\s\sImprove\sthe\nmkpragmatab.tcl\sscript\sto\sreuse\scolumn\snames\swhere\sappropriate. -D 2018-10-01T21:26:30.705 +C Test\scase\sfor\sPRAGMA\stable_xinfo. +D 2018-10-01T21:36:38.715 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -1334,7 +1334,7 @@ F test/sync.test 89539f4973c010eda5638407e71ca7fddbcd8e0594f4c9980229f804d433309 F test/sync2.test 8f9f7d4f6d5be8ca8941a8dadcc4299e558cb6a1ff653a9469146c7a76ef2039 F test/syscall.test a39d9a36f852ae6e4800f861bc2f2e83f68bbc2112d9399931ecfadeabd2d69d F test/sysfault.test c9f2b0d8d677558f74de750c75e12a5454719d04 -F test/tabfunc01.test c47171c36b3d411df2bd49719dcaa5d034f8d277477fd41d253940723b969a51 +F test/tabfunc01.test 5ddfdcda81f362d54cf301a65678edea2a02a570760a4c88051fc2730aafcd81 F test/table.test b708f3e5fa2542fa51dfab21fc07b36ea445cb2f F test/tableapi.test ecbcc29c4ab62c1912c3717c48ea5c5e59f7d64e4a91034e6148bd2b82f177f4 F test/tableopts.test dba698ba97251017b7c80d738c198d39ab747930 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cf1b76135f511530dcc7b82f78c952bf97ebcddb40be06f713f9f2326915fabe -R ba010eae61cf933e84f1d1c261299063 +P 2fdd068987e59b979045d71ae64e700600ef07e54ae340f30c2064e5dcccb8ea +R f25affb049e7e387101b1afc916c6b2e U drh -Z 03cca8b8402459da514c7ddddb7143b7 +Z 9b806ae5358896ee00b1faf1a3216949 diff --git a/manifest.uuid b/manifest.uuid index 5f1369d3fb..02ce067f82 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -2fdd068987e59b979045d71ae64e700600ef07e54ae340f30c2064e5dcccb8ea \ No newline at end of file +7694b9bc3003db6ba0b41c5029c8f7b84c07724e7a518e835e98b3c46e4ea227 \ No newline at end of file diff --git a/test/tabfunc01.test b/test/tabfunc01.test index 7e6a4b10be..f3cc39cdbb 100644 --- a/test/tabfunc01.test +++ b/test/tabfunc01.test @@ -28,6 +28,9 @@ load_static_extension db remember do_execsql_test tabfunc01-1.1 { SELECT *, '|' FROM generate_series WHERE start=1 AND stop=9 AND step=2; } {1 | 3 | 5 | 7 | 9 |} +do_execsql_test tabfunc01-1.1b { + PRAGMA table_xinfo(generate_series); +} {0 value {} 0 {} 0 0 1 start {} 0 {} 0 1 2 stop {} 0 {} 0 1 3 step {} 0 {} 0 1} do_execsql_test tabfunc01-1.2 { SELECT *, '|' FROM generate_series LIMIT 5; } {0 | 1 | 2 | 3 | 4 |} From 24efa5444df0378c8747ffc8e53ea2e126532ba1 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Oct 2018 19:36:40 +0000 Subject: [PATCH 009/109] Fix comments and refactor some names associated with shared-memory locking in the Unix VFS. No logical changes. FossilOrigin-Name: 3e9f1635271c92dce5324728b4ee1cc1a1856ec3c60b1b512a652c21e010e63e --- manifest | 13 +++++------ manifest.uuid | 2 +- src/os_unix.c | 61 ++++++++++++++++++++++++++------------------------- 3 files changed, 38 insertions(+), 38 deletions(-) diff --git a/manifest b/manifest index 87e0657611..8f36e316da 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\s"PRAGMA\stable_xinfo"\scommand\sthat\sworks\slike\stable_info\sbut\salso\nshows\shidden\scolumns\sin\svirtual\stables\sand\sadds\sthe\s"hidden"\sboolean\scolumn. -D 2018-10-01T21:41:15.265 +C Fix\scomments\sand\srefactor\ssome\snames\sassociated\swith\sshared-memory\slocking\nin\sthe\sUnix\sVFS.\s\sNo\slogical\schanges. +D 2018-10-02T19:36:40.212 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -487,7 +487,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 7cfd67db0e2f926243f646db7ec1caa33ca9bee45799b0160ddfcd6ccfc175d2 +F src/os_unix.c 3acd41af1334d7d2af8ca8ce684ccc73eeab7fe907ddab630963fd54102b4be4 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b @@ -1770,8 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 310b4b65b8c8ee080760c7efb4c7e20244c6063a5dba37a4f40490105aafd29f 7694b9bc3003db6ba0b41c5029c8f7b84c07724e7a518e835e98b3c46e4ea227 -R 4421b937cd53dd313f71ab5caa0a0109 -T +closed 7694b9bc3003db6ba0b41c5029c8f7b84c07724e7a518e835e98b3c46e4ea227 +P defa0515b8fd50ed9be699542f8c6695dd4a60c02f310665db6657ec5b6b67d0 +R 9097a8d83ca39760ec0a01128c0dade1 U drh -Z e0b06ff9de331820a7420ba45b53f562 +Z 3fc014f602248e5c82ae5fe3e9828c74 diff --git a/manifest.uuid b/manifest.uuid index b4be3bca8b..31f7167738 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -defa0515b8fd50ed9be699542f8c6695dd4a60c02f310665db6657ec5b6b67d0 \ No newline at end of file +3e9f1635271c92dce5324728b4ee1cc1a1856ec3c60b1b512a652c21e010e63e \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 6a1195041b..b0e5f825dc 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -136,12 +136,10 @@ #define SQLITE_FSFLAGS_IS_MSDOS 0x1 /* -** If we are to be thread-safe, include the pthreads header and define -** the SQLITE_UNIX_THREADS macro. +** If we are to be thread-safe, include the pthreads header. */ #if SQLITE_THREADSAFE # include -# define SQLITE_UNIX_THREADS 1 #endif /* @@ -1119,8 +1117,7 @@ struct unixFileId { /* ** An instance of the following structure is allocated for each open -** inode. Or, on LinuxThreads, there is one of these structures for -** each inode opened by each thread. +** inode. ** ** A single inode can have multiple file descriptors, so each unixFile ** structure contains a pointer to an instance of this object and this @@ -1166,13 +1163,16 @@ struct unixInodeInfo { /* ** A lists of all unixInodeInfo objects. +** +** Must hold unixBigLock in order to read or write this variable. */ static unixInodeInfo *inodeList = 0; /* All unixInodeInfo objects */ #ifdef SQLITE_DEBUG /* -** True if the inode mutex is held, or not. Used only within assert() -** to help verify correct mutex usage. +** True if the inode mutex (on the unixFile.pFileMutex field) is held, or not. +** This routine is used only within assert() to help verify correct mutex +** usage. */ int unixFileMutexHeld(unixFile *pFile){ assert( pFile->pInode ); @@ -1300,8 +1300,8 @@ static void closePendingFds(unixFile *pFile){ /* ** Release a unixInodeInfo structure previously allocated by findInodeInfo(). ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must be held when this routine is called, but the mutex +** on the inode being deleted must NOT be held. */ static void releaseInodeInfo(unixFile *pFile){ unixInodeInfo *pInode = pFile->pInode; @@ -1336,8 +1336,7 @@ static void releaseInodeInfo(unixFile *pFile){ ** describes that file descriptor. Create a new one if necessary. The ** return value might be uninitialized if an error occurs. ** -** The mutex entered using the unixEnterMutex() function must be held -** when this function is called. +** The global mutex must held when calling this routine. ** ** Return an appropriate error code. */ @@ -1398,6 +1397,7 @@ static int findInodeInfo( #else fileId.ino = (u64)statbuf.st_ino; #endif + assert( unixMutexHeld() ); pInode = inodeList; while( pInode && memcmp(&fileId, &pInode->fileId, sizeof(fileId)) ){ pInode = pInode->pNext; @@ -1417,6 +1417,7 @@ static int findInodeInfo( } } pInode->nRef = 1; + assert( unixMutexHeld() ); pInode->pNext = inodeList; pInode->pPrev = 0; if( inodeList ) inodeList->pPrev = pInode; @@ -4223,7 +4224,7 @@ static int unixGetpagesize(void){ */ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ - sqlite3_mutex *mutex; /* Mutex to access this object */ + sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ int h; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ @@ -4247,16 +4248,16 @@ struct unixShmNode { ** The following fields are initialized when this object is created and ** are read-only thereafter: ** -** unixShm.pFile +** unixShm.pShmNode ** unixShm.id ** -** All other fields are read/write. The unixShm.pFile->mutex must be held -** while accessing any read/write fields. +** All other fields are read/write. The unixShm.pShmNode->pShmMutex must +** be held while accessing any read/write fields. */ struct unixShm { unixShmNode *pShmNode; /* The underlying unixShmNode object */ unixShm *pNext; /* Next unixShm with the same unixShmNode */ - u8 hasMutex; /* True if holding the unixShmNode mutex */ + u8 hasMutex; /* True if holding the unixShmNode->pShmMutex */ u8 id; /* Id of this connection within its unixShmNode */ u16 sharedMask; /* Mask of shared locks held */ u16 exclMask; /* Mask of exclusive locks held */ @@ -4286,7 +4287,7 @@ static int unixShmSystemLock( /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; - assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->mutex) ); + assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); @@ -4372,7 +4373,7 @@ static void unixShmPurge(unixFile *pFd){ int nShmPerMap = unixShmRegionPerMap(); int i; assert( p->pInode==pFd->pInode ); - sqlite3_mutex_free(p->mutex); + sqlite3_mutex_free(p->pShmMutex); for(i=0; inRegion; i+=nShmPerMap){ if( p->h>=0 ){ osMunmap(p->apRegion[i], p->szRegion); @@ -4543,8 +4544,8 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ - pShmNode->mutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); - if( pShmNode->mutex==0 ){ + pShmNode->pShmMutex = sqlite3_mutex_alloc(SQLITE_MUTEX_FAST); + if( pShmNode->pShmMutex==0 ){ rc = SQLITE_NOMEM_BKPT; goto shm_open_err; } @@ -4587,13 +4588,13 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** the cover of the unixEnterMutex() mutex and the pointer from the ** new (struct unixShm) object to the pShmNode has been set. All that is ** left to do is to link the new object into the linked list starting - ** at pShmNode->pFirst. This must be done while holding the pShmNode->mutex - ** mutex. + ** at pShmNode->pFirst. This must be done while holding the + ** pShmNode->pShmMutex. */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); p->pNext = pShmNode->pFirst; pShmNode->pFirst = p; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; /* Jump here on any error */ @@ -4645,7 +4646,7 @@ static int unixShmMap( p = pDbFd->pShm; pShmNode = p->pShmNode; - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( pShmNode->isUnlocked ){ rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK ) goto shmpage_out; @@ -4754,7 +4755,7 @@ shmpage_out: *pp = 0; } if( pShmNode->isReadonly && rc==SQLITE_OK ) rc = SQLITE_READONLY; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); return rc; } @@ -4793,7 +4794,7 @@ static int unixShmLock( mask = (1<<(ofst+n)) - (1<1 || mask==(1<mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); if( flags & SQLITE_SHM_UNLOCK ){ u16 allMask = 0; /* Mask of locks held by siblings */ @@ -4866,7 +4867,7 @@ static int unixShmLock( } } } - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); OSTRACE(("SHM-LOCK shmid-%d, pid-%d got %03x,%03x\n", p->id, osGetpid(0), p->sharedMask, p->exclMask)); return rc; @@ -4916,14 +4917,14 @@ static int unixShmUnmap( /* Remove connection p from the set of connections associated ** with pShmNode */ - sqlite3_mutex_enter(pShmNode->mutex); + sqlite3_mutex_enter(pShmNode->pShmMutex); for(pp=&pShmNode->pFirst; (*pp)!=p; pp = &(*pp)->pNext){} *pp = p->pNext; /* Free the connection p */ sqlite3_free(p); pDbFd->pShm = 0; - sqlite3_mutex_leave(pShmNode->mutex); + sqlite3_mutex_leave(pShmNode->pShmMutex); /* If pShmNode->nRef has reached 0, then close the underlying ** shared-memory file, too */ From 8820c8d3eea5e9305064657f5be4ed96fa122014 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Oct 2018 19:58:08 +0000 Subject: [PATCH 010/109] Additional field name changes and commit fixes associated with shared-memory locking in the unix VFS, to improve maintainability. No logic changes. FossilOrigin-Name: 9280774a4bbc665d70f346d258768cbcca3e0e77791473aecfd7d0e87810ab31 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 54 +++++++++++++++++++++++++-------------------------- 3 files changed, 34 insertions(+), 34 deletions(-) diff --git a/manifest b/manifest index 8f36e316da..c0a6b1a606 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\scomments\sand\srefactor\ssome\snames\sassociated\swith\sshared-memory\slocking\nin\sthe\sUnix\sVFS.\s\sNo\slogical\schanges. -D 2018-10-02T19:36:40.212 +C Additional\sfield\sname\schanges\sand\scommit\sfixes\sassociated\swith\sshared-memory\nlocking\sin\sthe\sunix\sVFS,\sto\simprove\smaintainability.\s\sNo\slogic\schanges. +D 2018-10-02T19:58:08.325 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -487,7 +487,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c 3acd41af1334d7d2af8ca8ce684ccc73eeab7fe907ddab630963fd54102b4be4 +F src/os_unix.c fd755a51cc621b14c6b5816912e8e103ccc28c46d64f8173f22ba992ddbe9fd3 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P defa0515b8fd50ed9be699542f8c6695dd4a60c02f310665db6657ec5b6b67d0 -R 9097a8d83ca39760ec0a01128c0dade1 +P 3e9f1635271c92dce5324728b4ee1cc1a1856ec3c60b1b512a652c21e010e63e +R 4c540d033fc87107981e8569f09af526 U drh -Z 3fc014f602248e5c82ae5fe3e9828c74 +Z d5d2b74c6598d9bd4b46abde946440e8 diff --git a/manifest.uuid b/manifest.uuid index 31f7167738..50977535b7 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3e9f1635271c92dce5324728b4ee1cc1a1856ec3c60b1b512a652c21e010e63e \ No newline at end of file +9280774a4bbc665d70f346d258768cbcca3e0e77791473aecfd7d0e87810ab31 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index b0e5f825dc..1b18e874e8 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4215,10 +4215,10 @@ static int unixGetpagesize(void){ ** ** The following fields are read-only after the object is created: ** -** fid +** hShm ** zFilename ** -** Either unixShmNode.mutex must be held or unixShmNode.nRef==0 and +** Either unixShmNode.pShmMutex must be held or unixShmNode.nRef==0 and ** unixMutexHeld() is true when reading or writing any other field ** in this structure. */ @@ -4226,7 +4226,7 @@ struct unixShmNode { unixInodeInfo *pInode; /* unixInodeInfo that owns this SHM node */ sqlite3_mutex *pShmMutex; /* Mutex to access this object */ char *zFilename; /* Name of the mmapped file */ - int h; /* Open file descriptor */ + int hShm; /* Open file descriptor */ int szRegion; /* Size of shared-memory regions */ u16 nRegion; /* Size of array apRegion */ u8 isReadonly; /* True if read-only */ @@ -4295,13 +4295,13 @@ static int unixShmSystemLock( /* Locks are within range */ assert( n>=1 && n<=SQLITE_SHM_NLOCK ); - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* Initialize the locking parameters */ f.l_type = lockType; f.l_whence = SEEK_SET; f.l_start = ofst; f.l_len = n; - rc = osSetPosixAdvisoryLock(pShmNode->h, &f, pFile); + rc = osSetPosixAdvisoryLock(pShmNode->hShm, &f, pFile); rc = (rc!=(-1)) ? SQLITE_OK : SQLITE_BUSY; } @@ -4375,16 +4375,16 @@ static void unixShmPurge(unixFile *pFd){ assert( p->pInode==pFd->pInode ); sqlite3_mutex_free(p->pShmMutex); for(i=0; inRegion; i+=nShmPerMap){ - if( p->h>=0 ){ + if( p->hShm>=0 ){ osMunmap(p->apRegion[i], p->szRegion); }else{ sqlite3_free(p->apRegion[i]); } } sqlite3_free(p->apRegion); - if( p->h>=0 ){ - robust_close(pFd, p->h, __LINE__); - p->h = -1; + if( p->hShm>=0 ){ + robust_close(pFd, p->hShm, __LINE__); + p->hShm = -1; } p->pInode->pShmNode = 0; sqlite3_free(p); @@ -4426,7 +4426,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ lock.l_start = UNIX_SHM_DMS; lock.l_len = 1; lock.l_type = F_WRLCK; - if( osFcntl(pShmNode->h, F_GETLK, &lock)!=0 ) { + if( osFcntl(pShmNode->hShm, F_GETLK, &lock)!=0 ) { rc = SQLITE_IOERR_LOCK; }else if( lock.l_type==F_UNLCK ){ if( pShmNode->isReadonly ){ @@ -4434,7 +4434,7 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); - if( rc==SQLITE_OK && robust_ftruncate(pShmNode->h, 0) ){ + if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 0) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); } } @@ -4540,7 +4540,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ sqlite3_snprintf(nShmFilename, zShm, "%s-shm", zBasePath); sqlite3FileSuffix3(pDbFd->zPath, zShm); #endif - pShmNode->h = -1; + pShmNode->hShm = -1; pDbFd->pInode->pShmNode = pShmNode; pShmNode->pInode = pDbFd->pInode; if( sqlite3GlobalConfig.bCoreMutex ){ @@ -4553,11 +4553,11 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ if( pInode->bProcessLock==0 ){ if( 0==sqlite3_uri_boolean(pDbFd->zPath, "readonly_shm", 0) ){ - pShmNode->h = robust_open(zShm, O_RDWR|O_CREAT, (sStat.st_mode&0777)); + pShmNode->hShm = robust_open(zShm, O_RDWR|O_CREAT,(sStat.st_mode&0777)); } - if( pShmNode->h<0 ){ - pShmNode->h = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); - if( pShmNode->h<0 ){ + if( pShmNode->hShm<0 ){ + pShmNode->hShm = robust_open(zShm, O_RDONLY, (sStat.st_mode&0777)); + if( pShmNode->hShm<0 ){ rc = unixLogError(SQLITE_CANTOPEN_BKPT, "open", zShm); goto shm_open_err; } @@ -4568,7 +4568,7 @@ static int unixOpenSharedMemory(unixFile *pDbFd){ ** is owned by the same user that owns the original database. Otherwise, ** the original owner will not be able to connect. */ - robustFchown(pShmNode->h, sStat.st_uid, sStat.st_gid); + robustFchown(pShmNode->hShm, sStat.st_uid, sStat.st_gid); rc = unixLockSharedMemory(pDbFd, pShmNode); if( rc!=SQLITE_OK && rc!=SQLITE_READONLY_CANTINIT ) goto shm_open_err; @@ -4654,8 +4654,8 @@ static int unixShmMap( } assert( szRegion==pShmNode->szRegion || pShmNode->nRegion==0 ); assert( pShmNode->pInode==pDbFd->pInode ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); /* Minimum number of regions required to be mapped. */ nReqRegion = ((iRegion+nShmPerMap) / nShmPerMap) * nShmPerMap; @@ -4667,12 +4667,12 @@ static int unixShmMap( pShmNode->szRegion = szRegion; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ /* The requested region is not mapped into this processes address space. ** Check to see if it has been allocated (i.e. if the wal-index file is ** large enough to contain the requested region). */ - if( osFstat(pShmNode->h, &sStat) ){ + if( osFstat(pShmNode->hShm, &sStat) ){ rc = SQLITE_IOERR_SHMSIZE; goto shmpage_out; } @@ -4700,7 +4700,7 @@ static int unixShmMap( assert( (nByte % pgsz)==0 ); for(iPg=(sStat.st_size/pgsz); iPg<(nByte/pgsz); iPg++){ int x = 0; - if( seekAndWriteFd(pShmNode->h, iPg*pgsz + pgsz-1, "", 1, &x)!=1 ){ + if( seekAndWriteFd(pShmNode->hShm, iPg*pgsz + pgsz-1,"",1,&x)!=1 ){ const char *zFile = pShmNode->zFilename; rc = unixLogError(SQLITE_IOERR_SHMSIZE, "write", zFile); goto shmpage_out; @@ -4723,10 +4723,10 @@ static int unixShmMap( int nMap = szRegion*nShmPerMap; int i; void *pMem; - if( pShmNode->h>=0 ){ + if( pShmNode->hShm>=0 ){ pMem = osMmap(0, nMap, pShmNode->isReadonly ? PROT_READ : PROT_READ|PROT_WRITE, - MAP_SHARED, pShmNode->h, szRegion*(i64)pShmNode->nRegion + MAP_SHARED, pShmNode->hShm, szRegion*(i64)pShmNode->nRegion ); if( pMem==MAP_FAILED ){ rc = unixLogError(SQLITE_IOERR_SHMMAP, "mmap", pShmNode->zFilename); @@ -4789,8 +4789,8 @@ static int unixShmLock( || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_SHARED) || flags==(SQLITE_SHM_UNLOCK | SQLITE_SHM_EXCLUSIVE) ); assert( n==1 || (flags & SQLITE_SHM_EXCLUSIVE)!=0 ); - assert( pShmNode->h>=0 || pDbFd->pInode->bProcessLock==1 ); - assert( pShmNode->h<0 || pDbFd->pInode->bProcessLock==0 ); + assert( pShmNode->hShm>=0 || pDbFd->pInode->bProcessLock==1 ); + assert( pShmNode->hShm<0 || pDbFd->pInode->bProcessLock==0 ); mask = (1<<(ofst+n)) - (1<1 || mask==(1<nRef>0 ); pShmNode->nRef--; if( pShmNode->nRef==0 ){ - if( deleteFlag && pShmNode->h>=0 ){ + if( deleteFlag && pShmNode->hShm>=0 ){ osUnlink(pShmNode->zFilename); } unixShmPurge(pDbFd); From 9b7e8e10f2049456068868fe4881b26990ffeaf6 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 2 Oct 2018 20:16:41 +0000 Subject: [PATCH 011/109] Add an additional assert() verifying mutex invariants on the unixShmSystemLock() routine in the unix VFS. FossilOrigin-Name: cb1511065d5348c5b3015dc9d690fc5d519a14ffdfa7164bb552a4fa686ad142 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index c0a6b1a606..7bc0eac532 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Additional\sfield\sname\schanges\sand\scommit\sfixes\sassociated\swith\sshared-memory\nlocking\sin\sthe\sunix\sVFS,\sto\simprove\smaintainability.\s\sNo\slogic\schanges. -D 2018-10-02T19:58:08.325 +C Add\san\sadditional\sassert()\sverifying\smutex\sinvariants\son\sthe\nunixShmSystemLock()\sroutine\sin\sthe\sunix\sVFS. +D 2018-10-02T20:16:41.170 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -487,7 +487,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c fd755a51cc621b14c6b5816912e8e103ccc28c46d64f8173f22ba992ddbe9fd3 +F src/os_unix.c d483d738183c822cc96ec5539424eee5b9847c882dee57f93b880aaf46a7af19 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3e9f1635271c92dce5324728b4ee1cc1a1856ec3c60b1b512a652c21e010e63e -R 4c540d033fc87107981e8569f09af526 +P 9280774a4bbc665d70f346d258768cbcca3e0e77791473aecfd7d0e87810ab31 +R fbea89096e881563b5cf5b6d1bddc038 U drh -Z d5d2b74c6598d9bd4b46abde946440e8 +Z 844839c6466e9a3eaf0ac358bf4608fd diff --git a/manifest.uuid b/manifest.uuid index 50977535b7..25b0dcf9ab 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -9280774a4bbc665d70f346d258768cbcca3e0e77791473aecfd7d0e87810ab31 \ No newline at end of file +cb1511065d5348c5b3015dc9d690fc5d519a14ffdfa7164bb552a4fa686ad142 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 1b18e874e8..55f220ea96 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4288,6 +4288,7 @@ static int unixShmSystemLock( /* Access to the unixShmNode object is serialized by the caller */ pShmNode = pFile->pInode->pShmNode; assert( pShmNode->nRef==0 || sqlite3_mutex_held(pShmNode->pShmMutex) ); + assert( pShmNode->nRef>0 || unixMutexHeld() ); /* Shared locks never span more than one byte */ assert( n==1 || lockType!=F_RDLCK ); From 60bdcf5e5641dddea660376b8ea8156aeabf8402 Mon Sep 17 00:00:00 2001 From: dan Date: Wed, 3 Oct 2018 11:13:30 +0000 Subject: [PATCH 012/109] Change a type in shell.c.in from "int" to "sqlite3_int64" in order to avoid a compiler warning and possible integer overflow. FossilOrigin-Name: bf0a6634cd8f9457992b8da522a6775a304156815bf6f4f64f96016356baa870 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 2 +- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 7bc0eac532..0534072120 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sadditional\sassert()\sverifying\smutex\sinvariants\son\sthe\nunixShmSystemLock()\sroutine\sin\sthe\sunix\sVFS. -D 2018-10-02T20:16:41.170 +C Change\sa\stype\sin\sshell.c.in\sfrom\s"int"\sto\s"sqlite3_int64"\sin\sorder\sto\navoid\sa\scompiler\swarning\sand\spossible\sinteger\soverflow. +D 2018-10-03T11:13:30.633 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 -F src/shell.c.in 2162b1dc99b806298207c9c202aa7b49ac8553b8b1e73bb28cd80d5a1861df39 +F src/shell.c.in 6046da2a92998b8fe004ed4eadd4d7f53d6a8e4d99e5e25a0cc7de6de5f6b26b F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 9280774a4bbc665d70f346d258768cbcca3e0e77791473aecfd7d0e87810ab31 -R fbea89096e881563b5cf5b6d1bddc038 -U drh -Z 844839c6466e9a3eaf0ac358bf4608fd +P cb1511065d5348c5b3015dc9d690fc5d519a14ffdfa7164bb552a4fa686ad142 +R 4113007e1d90a93b8509333dc142f43c +U dan +Z 95fcad407c511808d2b753b90ec6a6c6 diff --git a/manifest.uuid b/manifest.uuid index 25b0dcf9ab..6271e5249c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb1511065d5348c5b3015dc9d690fc5d519a14ffdfa7164bb552a4fa686ad142 \ No newline at end of file +bf0a6634cd8f9457992b8da522a6775a304156815bf6f4f64f96016356baa870 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 9bfc3d12cf..cc375e820c 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1273,7 +1273,7 @@ static void editFunc( if( bBin ){ sqlite3_result_blob64(context, p, sz, sqlite3_free); }else{ - int i, j; + sqlite3_int64 i, j; if( hasCRNL ){ /* If the original contains \r\n then do no conversions back to \n */ j = sz; From f470c37a2ba3017f82d12c41b3c813b423c326e2 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 3 Oct 2018 18:05:36 +0000 Subject: [PATCH 013/109] Add an ALWAYS on an unreachable branch in the ALTER TABLE logic. FossilOrigin-Name: ebcd4523171f0988ff08e2bf36fb8a0caa40efe7ac7556b4eb206784969b03e4 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/alter.c | 4 +++- 3 files changed, 11 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 0534072120..c215f49e86 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Change\sa\stype\sin\sshell.c.in\sfrom\s"int"\sto\s"sqlite3_int64"\sin\sorder\sto\navoid\sa\scompiler\swarning\sand\spossible\sinteger\soverflow. -D 2018-10-03T11:13:30.633 +C Add\san\sALWAYS\son\san\sunreachable\sbranch\sin\sthe\sALTER\sTABLE\slogic. +D 2018-10-03T18:05:36.483 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -437,7 +437,7 @@ F spec.template 86a4a43b99ebb3e75e6b9a735d5fd293a24e90ca F sqlite.pc.in 42b7bf0d02e08b9e77734a47798d1a55a9e0716b F sqlite3.1 fc7ad8990fc8409983309bb80de8c811a7506786 F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a -F src/alter.c b929e4daabe215300aa9b4e353977714c1751d91aaa63e52f0a475b840ce245e +F src/alter.c bcb67339d8551408bfc99aa78b597abdc9b880114bc4e42027f9a02615df4f43 F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9 F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cb1511065d5348c5b3015dc9d690fc5d519a14ffdfa7164bb552a4fa686ad142 -R 4113007e1d90a93b8509333dc142f43c -U dan -Z 95fcad407c511808d2b753b90ec6a6c6 +P bf0a6634cd8f9457992b8da522a6775a304156815bf6f4f64f96016356baa870 +R 3bd57e9abfbbe1b0866f4f1caa5677e9 +U drh +Z 12be36416a19f9505215ac2168bb7434 diff --git a/manifest.uuid b/manifest.uuid index 6271e5249c..ba0d4b98a1 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -bf0a6634cd8f9457992b8da522a6775a304156815bf6f4f64f96016356baa870 \ No newline at end of file +ebcd4523171f0988ff08e2bf36fb8a0caa40efe7ac7556b4eb206784969b03e4 \ No newline at end of file diff --git a/src/alter.c b/src/alter.c index 3e2a5f1f08..f0f913b1c5 100644 --- a/src/alter.c +++ b/src/alter.c @@ -1061,7 +1061,9 @@ static int renameResolveTrigger(Parse *pParse, const char *zDb){ db->aDb[sqlite3SchemaToIndex(db, pNew->pTabSchema)].zDbSName ); pParse->eTriggerOp = pNew->op; - if( pParse->pTriggerTab ){ + /* ALWAYS() because if the table of the trigger does not exist, the + ** error would have been hit before this point */ + if( ALWAYS(pParse->pTriggerTab) ){ rc = sqlite3ViewGetColumnNames(pParse, pParse->pTriggerTab); } From bebf54438e5393dcfa0f5c4b04f9c90428274ed8 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 5 Oct 2018 15:10:00 +0000 Subject: [PATCH 014/109] Changes to geopoly to silience false-positive warnings coming out of clang. FossilOrigin-Name: 11d9015f31d1ea2fd27174d4ceea08a145fdbb92a175bec0aae4b90f991694bc --- ext/rtree/geopoly.c | 18 +++++++++++++----- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 20 insertions(+), 12 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 7eea11c48c..5b5dc43a01 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -106,14 +106,24 @@ typedef float GeoCoord; ** ** encoding (1 byte) 0=big-endian, 1=little-endian ** nvertex (3 bytes) Number of vertexes as a big-endian integer +** +** Enough space is allocated for 4 coordinates, to work around over-zealous +** warnings coming from some compiler (notably, clang). In reality, the size +** of each GeoPoly memory allocate is adjusted as necessary so that the +** GeoPoly.a[] array at the end is the appropriate size. */ typedef struct GeoPoly GeoPoly; struct GeoPoly { int nVertex; /* Number of vertexes */ unsigned char hdr[4]; /* Header for on-disk representation */ - GeoCoord a[2]; /* 2*nVertex values. X (longitude) first, then Y */ + GeoCoord a[8]; /* 2*nVertex values. X (longitude) first, then Y */ }; +/* The size of a memory allocation needed for a GeoPoly object sufficient +** to hold N coordinate pairs. +*/ +#define GEOPOLY_SZ(N) (sizeof(GeoPoly) + sizeof(GeoCoord)*2*((N)-4)) + /* ** State of a parse of a GeoJSON input. */ @@ -248,12 +258,10 @@ static GeoPoly *geopolyParseJson(const unsigned char *z, int *pRc){ && s.a[1]==s.a[s.nVertex*2-1] && (s.z++, geopolySkipSpace(&s)==0) ){ - int nByte; GeoPoly *pOut; int x = 1; s.nVertex--; /* Remove the redundant vertex at the end */ - nByte = sizeof(GeoPoly) * s.nVertex*2*sizeof(GeoCoord); - pOut = sqlite3_malloc64( nByte ); + pOut = sqlite3_malloc64( GEOPOLY_SZ(s.nVertex) ); x = 1; if( pOut==0 ) goto parse_json_err; pOut->nVertex = s.nVertex; @@ -588,7 +596,7 @@ static GeoPoly *geopolyBBox( if( pRc ) *pRc = SQLITE_OK; if( aCoord==0 ){ geopolyBboxFill: - pOut = sqlite3_realloc(p, sizeof(GeoPoly)+sizeof(GeoCoord)*6); + pOut = sqlite3_realloc(p, GEOPOLY_SZ(4)); if( pOut==0 ){ sqlite3_free(p); if( context ) sqlite3_result_error_nomem(context); diff --git a/manifest b/manifest index c215f49e86..84b2f73d67 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\san\sALWAYS\son\san\sunreachable\sbranch\sin\sthe\sALTER\sTABLE\slogic. -D 2018-10-03T18:05:36.483 +C Changes\sto\sgeopoly\sto\ssilience\sfalse-positive\swarnings\scoming\sout\sof\sclang. +D 2018-10-05T15:10:00.337 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -361,7 +361,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/geopoly.c cdf7972736f6c60e4309debad504de52ccd2dbe29e02bc8afc7912923ee68059 +F ext/rtree/geopoly.c 04db01e24dca675c5ab75110709aed054325f7474b2f567dd98361c373dcff3c F ext/rtree/rtree.c 6cc2e673cf1e9ea1619f13ab990f12389dfb951b131acbc2fbe164cee8992a20 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -1770,7 +1770,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P bf0a6634cd8f9457992b8da522a6775a304156815bf6f4f64f96016356baa870 -R 3bd57e9abfbbe1b0866f4f1caa5677e9 +P ebcd4523171f0988ff08e2bf36fb8a0caa40efe7ac7556b4eb206784969b03e4 +R 0343e4736757244e342124d3ae0b6945 U drh -Z 12be36416a19f9505215ac2168bb7434 +Z 37c34aea8b9ce101934311a6217c0cb6 diff --git a/manifest.uuid b/manifest.uuid index ba0d4b98a1..988c0f769a 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ebcd4523171f0988ff08e2bf36fb8a0caa40efe7ac7556b4eb206784969b03e4 \ No newline at end of file +11d9015f31d1ea2fd27174d4ceea08a145fdbb92a175bec0aae4b90f991694bc \ No newline at end of file From 07052d553515d9f836c61a98c75011a5ec72e834 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 6 Oct 2018 13:46:22 +0000 Subject: [PATCH 015/109] Add test cases and assert() statements to ensure that the authorizer is being called as expected from within ALTER TABLE. FossilOrigin-Name: ff10d2c7de430c88167b1e6e4f5307eee5d69e22c8d24b2ef4fcb3aea25a92e1 --- manifest | 15 +++---- manifest.uuid | 2 +- src/auth.c | 2 + test/alterauth2.test | 98 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 109 insertions(+), 8 deletions(-) create mode 100644 test/alterauth2.test diff --git a/manifest b/manifest index 84b2f73d67..6f481a7388 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Changes\sto\sgeopoly\sto\ssilience\sfalse-positive\swarnings\scoming\sout\sof\sclang. -D 2018-10-05T15:10:00.337 +C Add\stest\scases\sand\sassert()\sstatements\sto\sensure\sthat\sthe\sauthorizer\sis\sbeing\ncalled\sas\sexpected\sfrom\swithin\sALTER\sTABLE. +D 2018-10-06T13:46:22.771 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -440,7 +440,7 @@ F sqlite3.pc.in 48fed132e7cb71ab676105d2a4dc77127d8c1f3a F src/alter.c bcb67339d8551408bfc99aa78b597abdc9b880114bc4e42027f9a02615df4f43 F src/analyze.c 3dc6b98cf007b005af89df165c966baaa48e8124f38c87b4d2b276fe7f0b9eb9 F src/attach.c 4bd5b92633671d3e8ce431153ebb1893b50335818423b5373f3f27969f79769a -F src/auth.c 32a5bbe3b755169ab6c66311c5225a3cd4f75a46c041f7fb117e0cbb68055114 +F src/auth.c 0fac71038875693a937e506bceb492c5f136dd7b1249fbd4ae70b4e8da14f9df F src/backup.c 78d3cecfbe28230a3a9a1793e2ead609f469be43e8f486ca996006be551857ab F src/bitvec.c 17ea48eff8ba979f1f5b04cc484c7bb2be632f33 F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 @@ -605,6 +605,7 @@ F test/alter2.test 7ea05c7d92ac99349a802ef7ada17294dd647060 F test/alter3.test 4d79934d812eaeacc6f22781a080f8cfe012fdc3 F test/alter4.test 7e93a21fe131e1dfeb317e90056856f96b10381fc7fe3a05e765569a23400433 F test/alterauth.test 63442ba61ceb0c1eeb63aac1f4f5cebfa509d352276059d27106ae256bafc959 +F test/alterauth2.test c0a1ddf5b93d93cb0d15ba7acaf0c5c6fb515bbe861ede75b2d3fabad33b6499 F test/altercol.test 53fb5e218c9296afc160f2c4fcbeaf42bd0604815d9b3896a7d2eec583ad8704 F test/alterlegacy.test e7c07d605c2a85e7d1696c89e6bf64dfc932fc6d9320fe8708c8f5fc0b524d41 F test/altermalloc.test 167a47de41b5c638f5f5c6efb59784002b196fff70f98d9b4ed3cd74a3fb80c9 @@ -1770,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ebcd4523171f0988ff08e2bf36fb8a0caa40efe7ac7556b4eb206784969b03e4 -R 0343e4736757244e342124d3ae0b6945 -U drh -Z 37c34aea8b9ce101934311a6217c0cb6 +P 11d9015f31d1ea2fd27174d4ceea08a145fdbb92a175bec0aae4b90f991694bc +R c3f9b3556958d5e7141476120f8d2533 +U dan +Z 76c0dfa6b1cfccd65370e7083a5b3873 diff --git a/manifest.uuid b/manifest.uuid index 988c0f769a..90f8df9d79 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -11d9015f31d1ea2fd27174d4ceea08a145fdbb92a175bec0aae4b90f991694bc \ No newline at end of file +ff10d2c7de430c88167b1e6e4f5307eee5d69e22c8d24b2ef4fcb3aea25a92e1 \ No newline at end of file diff --git a/src/auth.c b/src/auth.c index 918ff46c3b..6fcdce251d 100644 --- a/src/auth.c +++ b/src/auth.c @@ -151,6 +151,7 @@ void sqlite3AuthRead( int iCol; /* Index of column in table */ assert( pExpr->op==TK_COLUMN || pExpr->op==TK_TRIGGER ); + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->xAuth==0 ) return; iDb = sqlite3SchemaToIndex(pParse->db, pSchema); if( iDb<0 ){ @@ -207,6 +208,7 @@ int sqlite3AuthCheck( /* Don't do any authorization checks if the database is initialising ** or if the parser is being invoked from within sqlite3_declare_vtab. */ + assert( !IN_RENAME_OBJECT || db->xAuth==0 ); if( db->init.busy || IN_SPECIAL_PARSE ){ return SQLITE_OK; } diff --git a/test/alterauth2.test b/test/alterauth2.test new file mode 100644 index 0000000000..bd589cda1d --- /dev/null +++ b/test/alterauth2.test @@ -0,0 +1,98 @@ +# 2018 October 6 +# +# 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. +# +#************************************************************************* +# + +set testdir [file dirname $argv0] + +source $testdir/tester.tcl + +# If SQLITE_OMIT_ALTERTABLE is defined, omit this file. +ifcapable !altertable { + finish_test + return +} +set testprefix alterauth2 + +set ::auth [list] +proc xAuth {type args} { + lappend ::auth [concat $type [lrange $args 0 3]] + if {$type=="SQLITE_READ" && [lindex $args 0] == "t2"} breakpoint + return SQLITE_OK +} +db auth xAuth + +proc do_auth_test {tn sql authcode} { + set script " + set ::auth \[list\] + execsql {$sql} + lsort -unique \[set ::auth\] + " + + set normal [list {*}$authcode] + uplevel [list do_test $tn $script $normal] +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a, b, c); + CREATE VIEW v1 AS SELECT * FROM t1; + CREATE TRIGGER tr1 AFTER INSERT ON t1 BEGIN + DELETE FROM t1 WHERE a Date: Sat, 6 Oct 2018 14:38:17 +0000 Subject: [PATCH 016/109] Fix the ".help -all" option in the command-line shell. FossilOrigin-Name: aac8f1dff0728c629b5cbf30369ee91c5862a707ede694dc2628d1d4f5a6c202 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/shell.c.in | 9 +++++++-- 3 files changed, 15 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 6f481a7388..5f20adeb35 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\stest\scases\sand\sassert()\sstatements\sto\sensure\sthat\sthe\sauthorizer\sis\sbeing\ncalled\sas\sexpected\sfrom\swithin\sALTER\sTABLE. -D 2018-10-06T13:46:22.771 +C Fix\sthe\s".help\s-all"\soption\sin\sthe\scommand-line\sshell. +D 2018-10-06T14:38:17.499 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 -F src/shell.c.in 6046da2a92998b8fe004ed4eadd4d7f53d6a8e4d99e5e25a0cc7de6de5f6b26b +F src/shell.c.in 09342e09c9518e2d927566069272a7a47799e3ad4125562bbfc1240478c4a5a2 F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 11d9015f31d1ea2fd27174d4ceea08a145fdbb92a175bec0aae4b90f991694bc -R c3f9b3556958d5e7141476120f8d2533 -U dan -Z 76c0dfa6b1cfccd65370e7083a5b3873 +P ff10d2c7de430c88167b1e6e4f5307eee5d69e22c8d24b2ef4fcb3aea25a92e1 +R 29cbf681583baf68c349077deec43fe7 +U drh +Z 64cd6344daa5db6811005ab9259da4cc diff --git a/manifest.uuid b/manifest.uuid index 90f8df9d79..d13538dc28 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ff10d2c7de430c88167b1e6e4f5307eee5d69e22c8d24b2ef4fcb3aea25a92e1 \ No newline at end of file +aac8f1dff0728c629b5cbf30369ee91c5862a707ede694dc2628d1d4f5a6c202 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index cc375e820c..fe242af133 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3509,10 +3509,15 @@ static int showHelp(FILE *out, const char *zPattern){ int i, j; int n = 0; char *zPat; - if( zPattern==0 || zPattern[0]=='0' ){ + if( zPattern==0 + || zPattern[0]=='0' + || strcmp(zPattern,"-a")==0 + || strcmp(zPattern,"-all")==0 + ){ /* Show all commands, but only one line per command */ + if( zPattern==0 ) zPattern = ""; for(i=0; i Date: Mon, 8 Oct 2018 12:58:59 +0000 Subject: [PATCH 017/109] Add the geopoly_reverse() function to the GeoPoly extension. FossilOrigin-Name: 690dd18a5768c5a8cdfa92d5b01901c1a7b1fb6ebb90399f56a3112e41609f92 --- ext/rtree/geopoly.c | 31 +++++++++++++++++++++++++++++++ manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 38 insertions(+), 7 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index 5b5dc43a01..c3f3478b5c 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -494,6 +494,36 @@ static void geopolyAreaFunc( } } +/* +** Implementation of the geopoly_reverse(X) function. +** +** Reverse the order of the vertexes in polygon X. This can be used +** to convert an historical polygon that uses a clockwise rotation into +** a well-formed GeoJSON polygon that uses counter-clockwise rotation. +*/ +static void geopolyReverseFunc( + sqlite3_context *context, + int argc, + sqlite3_value **argv +){ + GeoPoly *p = geopolyFuncParam(context, argv[0], 0); + if( p ){ + int ii, jj; + for(ii=2, jj=p->nVertex*2 - 4; iia[ii]; + p->a[ii] = p->a[jj]; + p->a[jj] = t; + t = p->a[ii+1]; + p->a[ii+1] = p->a[jj+1]; + p->a[jj+1] = t; + + } + sqlite3_result_blob(context, p->hdr, + 4+8*p->nVertex, SQLITE_TRANSIENT); + sqlite3_free(p); + } +} + #define GEOPOLY_PI 3.1415926535897932385 /* Fast approximation for cosine(X) for X between -0.5*pi and 2*pi @@ -1721,6 +1751,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, { geopolyXformFunc, 7, 1, "geopoly_xform" }, { geopolyRegularFunc, 4, 1, "geopoly_regular" }, + { geopolyReverseFunc, 1, 1, "geopoly_reverse" }, }; static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); diff --git a/manifest b/manifest index 5f20adeb35..7a838f249e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sthe\s".help\s-all"\soption\sin\sthe\scommand-line\sshell. -D 2018-10-06T14:38:17.499 +C Add\sthe\sgeopoly_reverse()\sfunction\sto\sthe\sGeoPoly\sextension. +D 2018-10-08T12:58:59.969 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -361,7 +361,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/geopoly.c 04db01e24dca675c5ab75110709aed054325f7474b2f567dd98361c373dcff3c +F ext/rtree/geopoly.c 9d8411b2bcaab719f65acc8a84d16200d5139ac634787df546c31bf9972b34e6 F ext/rtree/rtree.c 6cc2e673cf1e9ea1619f13ab990f12389dfb951b131acbc2fbe164cee8992a20 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ff10d2c7de430c88167b1e6e4f5307eee5d69e22c8d24b2ef4fcb3aea25a92e1 -R 29cbf681583baf68c349077deec43fe7 +P aac8f1dff0728c629b5cbf30369ee91c5862a707ede694dc2628d1d4f5a6c202 +R 6c483dda78db6c9ea6a6a082c4feae71 U drh -Z 64cd6344daa5db6811005ab9259da4cc +Z f525bca01c12c5943b4f7c604400e173 diff --git a/manifest.uuid b/manifest.uuid index d13538dc28..b8eda6748b 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -aac8f1dff0728c629b5cbf30369ee91c5862a707ede694dc2628d1d4f5a6c202 \ No newline at end of file +690dd18a5768c5a8cdfa92d5b01901c1a7b1fb6ebb90399f56a3112e41609f92 \ No newline at end of file From 5f8cb730afa1017e1ac1af53886027a6a3d98e4e Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 8 Oct 2018 18:55:56 +0000 Subject: [PATCH 018/109] Replace the new geopoly_reverse() function with geopoly_ccw(). The geopoly_ccw() function only reverses the vertex order if doing so is necessary to get the correct right-hand winding rule on the polygon. FossilOrigin-Name: 075066944b13b18d339ccf87ae16f0b91bf00f40bd70f71c6beba6aa6c43f0b6 --- ext/rtree/geopoly.c | 70 ++++++++++++++++++++++++++++----------------- manifest | 12 ++++---- manifest.uuid | 2 +- 3 files changed, 51 insertions(+), 33 deletions(-) diff --git a/ext/rtree/geopoly.c b/ext/rtree/geopoly.c index c3f3478b5c..be582a3e1b 100644 --- a/ext/rtree/geopoly.c +++ b/ext/rtree/geopoly.c @@ -464,6 +464,27 @@ static void geopolyXformFunc( } } +/* +** Compute the area enclosed by the polygon. +** +** This routine can also be used to detect polygons that rotate in +** the wrong direction. Polygons are suppose to be counter-clockwise (CCW). +** This routine returns a negative value for clockwise (CW) polygons. +*/ +static double geopolyArea(GeoPoly *p){ + double rArea = 0.0; + int ii; + for(ii=0; iinVertex-1; ii++){ + rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ + * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ + * 0.5; + } + rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ + * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ + * 0.5; + return rArea; +} + /* ** Implementation of the geopoly_area(X) function. ** @@ -479,44 +500,41 @@ static void geopolyAreaFunc( ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ - double rArea = 0.0; - int ii; - for(ii=0; iinVertex-1; ii++){ - rArea += (p->a[ii*2] - p->a[ii*2+2]) /* (x0 - x1) */ - * (p->a[ii*2+1] + p->a[ii*2+3]) /* (y0 + y1) */ - * 0.5; - } - rArea += (p->a[ii*2] - p->a[0]) /* (xN - x0) */ - * (p->a[ii*2+1] + p->a[1]) /* (yN + y0) */ - * 0.5; - sqlite3_result_double(context, rArea); + sqlite3_result_double(context, geopolyArea(p)); sqlite3_free(p); } } /* -** Implementation of the geopoly_reverse(X) function. +** Implementation of the geopoly_ccw(X) function. ** -** Reverse the order of the vertexes in polygon X. This can be used -** to convert an historical polygon that uses a clockwise rotation into -** a well-formed GeoJSON polygon that uses counter-clockwise rotation. +** If the rotation of polygon X is clockwise (incorrect) instead of +** counter-clockwise (the correct winding order according to RFC7946) +** then reverse the order of the vertexes in polygon X. +** +** In other words, this routine returns a CCW polygon regardless of the +** winding order of its input. +** +** Use this routine to sanitize historical inputs that that sometimes +** contain polygons that wind in the wrong direction. */ -static void geopolyReverseFunc( +static void geopolyCcwFunc( sqlite3_context *context, int argc, sqlite3_value **argv ){ GeoPoly *p = geopolyFuncParam(context, argv[0], 0); if( p ){ - int ii, jj; - for(ii=2, jj=p->nVertex*2 - 4; iia[ii]; - p->a[ii] = p->a[jj]; - p->a[jj] = t; - t = p->a[ii+1]; - p->a[ii+1] = p->a[jj+1]; - p->a[jj+1] = t; - + if( geopolyArea(p)<0.0 ){ + int ii, jj; + for(ii=2, jj=p->nVertex*2 - 4; iia[ii]; + p->a[ii] = p->a[jj]; + p->a[jj] = t; + t = p->a[ii+1]; + p->a[ii+1] = p->a[jj+1]; + p->a[jj+1] = t; + } } sqlite3_result_blob(context, p->hdr, 4+8*p->nVertex, SQLITE_TRANSIENT); @@ -1751,7 +1769,7 @@ static int sqlite3_geopoly_init(sqlite3 *db){ { geopolyBBoxFunc, 1, 1, "geopoly_bbox" }, { geopolyXformFunc, 7, 1, "geopoly_xform" }, { geopolyRegularFunc, 4, 1, "geopoly_regular" }, - { geopolyReverseFunc, 1, 1, "geopoly_reverse" }, + { geopolyCcwFunc, 1, 1, "geopoly_ccw" }, }; static const struct { void (*xStep)(sqlite3_context*,int,sqlite3_value**); diff --git a/manifest b/manifest index 7a838f249e..bc450e6e5f 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sgeopoly_reverse()\sfunction\sto\sthe\sGeoPoly\sextension. -D 2018-10-08T12:58:59.969 +C Replace\sthe\snew\sgeopoly_reverse()\sfunction\swith\sgeopoly_ccw().\s\sThe\ngeopoly_ccw()\sfunction\sonly\sreverses\sthe\svertex\sorder\sif\sdoing\sso\sis\snecessary\nto\sget\sthe\scorrect\sright-hand\swinding\srule\son\sthe\spolygon. +D 2018-10-08T18:55:56.767 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -361,7 +361,7 @@ F ext/repair/test/checkfreelist01.test 3e8aa6aeb4007680c94a8d07b41c339aa635cc782 F ext/repair/test/checkindex01.test 6945d0ffc0c1dc993b2ce88036b26e0f5d6fcc65da70fc9df27c2647bb358b0f F ext/repair/test/test.tcl 686d76d888dffd021f64260abf29a55c57b2cedfa7fc69150b42b1d6119aac3c F ext/rtree/README 6315c0d73ebf0ec40dedb5aa0e942bc8b54e3761 -F ext/rtree/geopoly.c 9d8411b2bcaab719f65acc8a84d16200d5139ac634787df546c31bf9972b34e6 +F ext/rtree/geopoly.c 2464b3325fcc2878ed08458efeb995f830f4eef28bbf3da9757c4bd95e6f9549 F ext/rtree/rtree.c 6cc2e673cf1e9ea1619f13ab990f12389dfb951b131acbc2fbe164cee8992a20 F ext/rtree/rtree.h 4a690463901cb5e6127cf05eb8e642f127012fd5003830dbc974eca5802d9412 F ext/rtree/rtree1.test 309afc04d4287542b2cd74f933296832cc681c7b014d9405cb329b62053a5349 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P aac8f1dff0728c629b5cbf30369ee91c5862a707ede694dc2628d1d4f5a6c202 -R 6c483dda78db6c9ea6a6a082c4feae71 +P 690dd18a5768c5a8cdfa92d5b01901c1a7b1fb6ebb90399f56a3112e41609f92 +R 35a6105ea46a39f4869622077b954203 U drh -Z f525bca01c12c5943b4f7c604400e173 +Z 59baf7542a91be0562e1f0570ed59fd4 diff --git a/manifest.uuid b/manifest.uuid index b8eda6748b..b661feba37 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -690dd18a5768c5a8cdfa92d5b01901c1a7b1fb6ebb90399f56a3112e41609f92 \ No newline at end of file +075066944b13b18d339ccf87ae16f0b91bf00f40bd70f71c6beba6aa6c43f0b6 \ No newline at end of file From 7dd630a893454538092cce2ac811e85e6fb95190 Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 8 Oct 2018 20:04:16 +0000 Subject: [PATCH 019/109] Fix an issue with the new memstat.c extension. FossilOrigin-Name: ce6e80b1303ed161bec2c63735cd2e2bea7b4e9b4ff780d214d408b1a30d50da --- ext/misc/memstat.c | 2 +- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/ext/misc/memstat.c b/ext/misc/memstat.c index 27cb404df5..3194e752cc 100644 --- a/ext/misc/memstat.c +++ b/ext/misc/memstat.c @@ -235,7 +235,7 @@ static int memstatNext(sqlite3_vtab_cursor *cur){ assert( pCur->iRowid<=MSV_NROW ); while(1){ i = (int)pCur->iRowid - 1; - if( (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){ + if( i<0 || (aMemstatColumn[i].mNull & 2)!=0 || (++pCur->iDb)>=pCur->nDb ){ pCur->iRowid++; if( pCur->iRowid>MSV_NROW ) return SQLITE_OK; /* End of the table */ pCur->iDb = 0; diff --git a/manifest b/manifest index bc450e6e5f..7e0c43b42e 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Replace\sthe\snew\sgeopoly_reverse()\sfunction\swith\sgeopoly_ccw().\s\sThe\ngeopoly_ccw()\sfunction\sonly\sreverses\sthe\svertex\sorder\sif\sdoing\sso\sis\snecessary\nto\sget\sthe\scorrect\sright-hand\swinding\srule\son\sthe\spolygon. -D 2018-10-08T18:55:56.767 +C Fix\san\sissue\swith\sthe\snew\smemstat.c\sextension. +D 2018-10-08T20:04:16.861 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -286,7 +286,7 @@ F ext/misc/fileio.c 7317d825fab6a3c48f6e3822a00a6a22e08e55af31700ac96f16a523f830 F ext/misc/fuzzer.c 7c64b8197bb77b7d64eff7cac7848870235d4c25 F ext/misc/ieee754.c f190d0cc5182529acb15babd177781be1ac1718c F ext/misc/json1.c 276f87dc8365b34b0fffb7ef32481dd07fac6fdb3224e2822396a48377ac8363 -F ext/misc/memstat.c 2780712e90765b810645227578438d972b76a089210901bfe9ec88f6a45b0570 +F ext/misc/memstat.c 7542ff1dd1d926e63dab904070e689cd5b47e4dd19498ad31947c42b207f5363 F ext/misc/memvfs.c ab36f49e02ebcdf85a1e08dc4d8599ea8f343e073ac9e0bca18a98b7e1ec9567 F ext/misc/mmapwarm.c 70b618f2d0bde43fae288ad0b7498a629f2b6f61b50a27e06fae3cd23c83af29 F ext/misc/nextchar.c 35c8b8baacb96d92abbb34a83a997b797075b342 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 690dd18a5768c5a8cdfa92d5b01901c1a7b1fb6ebb90399f56a3112e41609f92 -R 35a6105ea46a39f4869622077b954203 +P 075066944b13b18d339ccf87ae16f0b91bf00f40bd70f71c6beba6aa6c43f0b6 +R 951b54fa62380919f60e6beeacdd92a7 U drh -Z 59baf7542a91be0562e1f0570ed59fd4 +Z c2cad3bd34a2756d8af9a8d60cc5c6a7 diff --git a/manifest.uuid b/manifest.uuid index b661feba37..b2487e39df 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -075066944b13b18d339ccf87ae16f0b91bf00f40bd70f71c6beba6aa6c43f0b6 \ No newline at end of file +ce6e80b1303ed161bec2c63735cd2e2bea7b4e9b4ff780d214d408b1a30d50da \ No newline at end of file From a9e4be3b08123dcb20d506f3c4429e4f25961498 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 10 Oct 2018 18:56:40 +0000 Subject: [PATCH 020/109] In the CLI, allow the SQLITE_HISTORY environment variable, if it exists, to specify an alternative file in which to store the shell edit history. FossilOrigin-Name: 696e82f7c82d1720756078e73f3b15b4cafc202ec290e66f9095a3246c65a3cb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 8 +++++--- 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index 7e0c43b42e..afe756d855 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sissue\swith\sthe\snew\smemstat.c\sextension. -D 2018-10-08T20:04:16.861 +C In\sthe\sCLI,\sallow\sthe\sSQLITE_HISTORY\senvironment\svariable,\sif\sit\sexists,\nto\sspecify\san\salternative\sfile\sin\swhich\sto\sstore\sthe\sshell\sedit\shistory. +D 2018-10-10T18:56:40.387 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 -F src/shell.c.in 09342e09c9518e2d927566069272a7a47799e3ad4125562bbfc1240478c4a5a2 +F src/shell.c.in d574c3be644c80cfcca358ee673615bb2f4da36596fd0744f05ab52f7e38cd0e F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 075066944b13b18d339ccf87ae16f0b91bf00f40bd70f71c6beba6aa6c43f0b6 -R 951b54fa62380919f60e6beeacdd92a7 +P ce6e80b1303ed161bec2c63735cd2e2bea7b4e9b4ff780d214d408b1a30d50da +R 46756433429fb414f7e8a79829036149 U drh -Z c2cad3bd34a2756d8af9a8d60cc5c6a7 +Z 26f7c5a190e4171df3337800973b1cb0 diff --git a/manifest.uuid b/manifest.uuid index b2487e39df..276fe80c8d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ce6e80b1303ed161bec2c63735cd2e2bea7b4e9b4ff780d214d408b1a30d50da \ No newline at end of file +696e82f7c82d1720756078e73f3b15b4cafc202ec290e66f9095a3246c65a3cb \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index fe242af133..a5ab14383c 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -8858,7 +8858,7 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ */ if( stdin_is_interactive ){ char *zHome; - char *zHistory = 0; + char *zHistory; int nHistory; printf( "SQLite version %s %.19s\n" /*extra-version-info*/ @@ -8871,8 +8871,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ printf(".\nUse \".open FILENAME\" to reopen on a " "persistent database.\n"); } - zHome = find_home_dir(0); - if( zHome ){ + zHistory = getenv("SQLITE_HISTORY"); + if( zHistory ){ + zHistory = strdup(zHistory); + }else if( (zHome = find_home_dir(0))!=0 ){ nHistory = strlen30(zHome) + 20; if( (zHistory = malloc(nHistory))!=0 ){ sqlite3_snprintf(nHistory, zHistory,"%s/.sqlite_history", zHome); From b6c4d59e89f667838cf0d4500d36e3542253dc85 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Oct 2018 02:39:11 +0000 Subject: [PATCH 021/109] In the unix VFS, fix the heap shm allocator (used for unix-excl) so that it works even on systems where the page size is larger than 32KB. FossilOrigin-Name: 7fbb083c5cf0948af3624b7538ffa086f77de27a3e84a7039ae7d6574f1a3a54 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/os_unix.c | 4 ++-- test/wal64k.test | 12 ++++++++++++ 4 files changed, 22 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index afe756d855..ff80518453 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\sallow\sthe\sSQLITE_HISTORY\senvironment\svariable,\sif\sit\sexists,\nto\sspecify\san\salternative\sfile\sin\swhich\sto\sstore\sthe\sshell\sedit\shistory. -D 2018-10-10T18:56:40.387 +C In\sthe\sunix\sVFS,\sfix\sthe\sheap\sshm\sallocator\s(used\sfor\sunix-excl)\s\nso\sthat\sit\sworks\seven\son\ssystems\swhere\sthe\spage\ssize\sis\slarger\sthan\s32KB. +D 2018-10-11T02:39:11.173 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -487,7 +487,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c d483d738183c822cc96ec5539424eee5b9847c882dee57f93b880aaf46a7af19 +F src/os_unix.c d4483c1a5462c9f03a4d62655cb208bc6434e549d614b132f652a747bcac9d32 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b @@ -1588,7 +1588,7 @@ F test/wal3.test 2a93004bc0fb2b5c29888964024695bade278ab2 F test/wal4.test 4744e155cd6299c6bd99d3eab1c82f77db9cdb3c F test/wal5.test 9c11da7aeccd83a46d79a556ad11a18d3cb15aa9 F test/wal6.test b602704e4b066199bc89d91ca9000f335dcf4572 -F test/wal64k.test 163655ecd2cb8afef4737cac2a40fdd2eeaf20b8 +F test/wal64k.test 2a525c0f45d709bae3765c71045ccec5df7d100ccbd3a7860fdba46c9addb965 F test/wal7.test 2ae8f427d240099cc4b2dfef63cff44e2a68a1bd F test/wal8.test d9df3fba4caad5854ed69ed673c68482514203c8 F test/wal9.test 378e76a9ad09cd9bee06c172ad3547b0129a6750 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ce6e80b1303ed161bec2c63735cd2e2bea7b4e9b4ff780d214d408b1a30d50da -R 46756433429fb414f7e8a79829036149 +P 696e82f7c82d1720756078e73f3b15b4cafc202ec290e66f9095a3246c65a3cb +R 3dab1e5dfa96bd90e2f41942ffa87100 U drh -Z 26f7c5a190e4171df3337800973b1cb0 +Z eeb432e953b5483573f56669790dd03f diff --git a/manifest.uuid b/manifest.uuid index 276fe80c8d..bc8b8d52ed 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -696e82f7c82d1720756078e73f3b15b4cafc202ec290e66f9095a3246c65a3cb \ No newline at end of file +7fbb083c5cf0948af3624b7538ffa086f77de27a3e84a7039ae7d6574f1a3a54 \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 55f220ea96..4228aaaf05 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4734,12 +4734,12 @@ static int unixShmMap( goto shmpage_out; } }else{ - pMem = sqlite3_malloc64(szRegion); + pMem = sqlite3_malloc64(nMap); if( pMem==0 ){ rc = SQLITE_NOMEM_BKPT; goto shmpage_out; } - memset(pMem, 0, szRegion); + memset(pMem, 0, nMap); } for(i=0; i Date: Thu, 11 Oct 2018 10:37:24 +0000 Subject: [PATCH 022/109] In the CLI, fix a file descriptor leak following OOM and a missing va_end() call. FossilOrigin-Name: ec36d15a9e349f4295a9e2215dea0a18e9276e0e4ce2d05021e6b467ab7763bb --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 3 ++- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index ff80518453..c44252b604 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sunix\sVFS,\sfix\sthe\sheap\sshm\sallocator\s(used\sfor\sunix-excl)\s\nso\sthat\sit\sworks\seven\son\ssystems\swhere\sthe\spage\ssize\sis\slarger\sthan\s32KB. -D 2018-10-11T02:39:11.173 +C In\sthe\sCLI,\sfix\sa\sfile\sdescriptor\sleak\sfollowing\sOOM\sand\sa\smissing\sva_end()\ncall. +D 2018-10-11T10:37:24.495 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 -F src/shell.c.in d574c3be644c80cfcca358ee673615bb2f4da36596fd0744f05ab52f7e38cd0e +F src/shell.c.in fa815984cdb07aad83fa0231ce3de32e7a4d022ab4cbc40f851b1881839b8fed F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 696e82f7c82d1720756078e73f3b15b4cafc202ec290e66f9095a3246c65a3cb -R 3dab1e5dfa96bd90e2f41942ffa87100 +P 7fbb083c5cf0948af3624b7538ffa086f77de27a3e84a7039ae7d6574f1a3a54 +R b6834208f7c836cdc5642ce75ee0475c U drh -Z eeb432e953b5483573f56669790dd03f +Z 331652a34e41515169becdfffb61b371 diff --git a/manifest.uuid b/manifest.uuid index bc8b8d52ed..b0332906bd 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7fbb083c5cf0948af3624b7538ffa086f77de27a3e84a7039ae7d6574f1a3a54 \ No newline at end of file +ec36d15a9e349f4295a9e2215dea0a18e9276e0e4ce2d05021e6b467ab7763bb \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index a5ab14383c..c1db72ce59 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3592,7 +3592,7 @@ static char *readFile(const char *zName, int *pnByte){ nIn = ftell(in); rewind(in); pBuf = sqlite3_malloc64( nIn+1 ); - if( pBuf==0 ) return 0; + if( pBuf==0 ){ fclose(in); return 0; } nRead = fread(pBuf, nIn, 1, in); fclose(in); if( nRead!=1 ){ @@ -4976,6 +4976,7 @@ static void shellPreparePrintf( char *z; va_start(ap, zFmt); z = sqlite3_vmprintf(zFmt, ap); + va_end(ap); if( z==0 ){ *pRc = SQLITE_NOMEM; }else{ From f7f2a82aa0b3e4a166f6d838e216088e047bc9c2 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Oct 2018 13:51:48 +0000 Subject: [PATCH 023/109] On the first connection to a WAL-mode database that was not cleanly shut down and contains a left-over -shm file, truncate the -shm file to 3 bytes instead of to 0 bytes. Avoiding a truncation to 0 means that system monitoring tools can better detect if a process illegitimately tries to truncate a -shm file. Such a rogue process might think it is being helpful by cleaning up old files, but there is a race condition that can cause damage to the database. FossilOrigin-Name: 90cf32cde072a305f30c75a71665d1f9e23e805c0a49f5306f015c056dd70f0c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/os_unix.c | 7 ++++++- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index c44252b604..3584c8263d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\sfix\sa\sfile\sdescriptor\sleak\sfollowing\sOOM\sand\sa\smissing\sva_end()\ncall. -D 2018-10-11T10:37:24.495 +C On\sthe\sfirst\sconnection\sto\sa\sWAL-mode\sdatabase\sthat\swas\snot\scleanly\sshut\sdown\nand\scontains\sa\sleft-over\s-shm\sfile,\struncate\sthe\s-shm\sfile\sto\s3\sbytes\sinstead\nof\sto\s0\sbytes.\sAvoiding\sa\struncation\sto\s0\smeans\sthat\ssystem\smonitoring\stools\ncan\sbetter\sdetect\sif\sa\sprocess\sillegitimately\stries\sto\struncate\sa\s-shm\sfile.\nSuch\sa\srogue\sprocess\smight\sthink\sit\sis\sbeing\shelpful\sby\scleaning\sup\sold\sfiles,\nbut\sthere\sis\sa\srace\scondition\sthat\scan\scause\sdamage\sto\sthe\sdatabase. +D 2018-10-11T13:51:48.266 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -487,7 +487,7 @@ F src/os.c 8aeb0b0f40f8f5b0da03fe49706695adaf42d2f516ab95abc72e86c245e119de F src/os.h 48388821692e87da174ea198bf96b1b2d9d83be5dfc908f673ee21fafbe0d432 F src/os_common.h b2f4707a603e36811d9b1a13278bffd757857b85 F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 -F src/os_unix.c d4483c1a5462c9f03a4d62655cb208bc6434e549d614b132f652a747bcac9d32 +F src/os_unix.c f6e91b8fd82af7afbfd073c4974ad6cdb8e62d9f65ceddb45167835a0567fdc0 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7fbb083c5cf0948af3624b7538ffa086f77de27a3e84a7039ae7d6574f1a3a54 -R b6834208f7c836cdc5642ce75ee0475c +P ec36d15a9e349f4295a9e2215dea0a18e9276e0e4ce2d05021e6b467ab7763bb +R dd28e1032e7501a10c527d67fc7e62ed U drh -Z 331652a34e41515169becdfffb61b371 +Z de92fbcb4550e9f483f9e1ba42f7c62c diff --git a/manifest.uuid b/manifest.uuid index b0332906bd..db516281c9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -ec36d15a9e349f4295a9e2215dea0a18e9276e0e4ce2d05021e6b467ab7763bb \ No newline at end of file +90cf32cde072a305f30c75a71665d1f9e23e805c0a49f5306f015c056dd70f0c \ No newline at end of file diff --git a/src/os_unix.c b/src/os_unix.c index 4228aaaf05..f20763e5b0 100644 --- a/src/os_unix.c +++ b/src/os_unix.c @@ -4435,7 +4435,12 @@ static int unixLockSharedMemory(unixFile *pDbFd, unixShmNode *pShmNode){ rc = SQLITE_READONLY_CANTINIT; }else{ rc = unixShmSystemLock(pDbFd, F_WRLCK, UNIX_SHM_DMS, 1); - if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 0) ){ + /* The first connection to attach must truncate the -shm file. We + ** truncate to 3 bytes (an arbitrary small number, less than the + ** -shm header size) rather than 0 as a system debugging aid, to + ** help detect if a -shm file truncation is legitimate or is the work + ** or a rogue process. */ + if( rc==SQLITE_OK && robust_ftruncate(pShmNode->hShm, 3) ){ rc = unixLogError(SQLITE_IOERR_SHMOPEN,"ftruncate",pShmNode->zFilename); } } From 53f5f0076229d1e3de5257f4eed9a0b89b1de3ab Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Oct 2018 16:38:56 +0000 Subject: [PATCH 024/109] Always reset the pager before changing the codec. FossilOrigin-Name: 0bf0fd242b93c3bd308ab46db1be9edef141b89db07a0f5a4ed8b23c963da0d5 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/pager.c | 1 + 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index 3584c8263d..5fdba93072 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C On\sthe\sfirst\sconnection\sto\sa\sWAL-mode\sdatabase\sthat\swas\snot\scleanly\sshut\sdown\nand\scontains\sa\sleft-over\s-shm\sfile,\struncate\sthe\s-shm\sfile\sto\s3\sbytes\sinstead\nof\sto\s0\sbytes.\sAvoiding\sa\struncation\sto\s0\smeans\sthat\ssystem\smonitoring\stools\ncan\sbetter\sdetect\sif\sa\sprocess\sillegitimately\stries\sto\struncate\sa\s-shm\sfile.\nSuch\sa\srogue\sprocess\smight\sthink\sit\sis\sbeing\shelpful\sby\scleaning\sup\sold\sfiles,\nbut\sthere\sis\sa\srace\scondition\sthat\scan\scause\sdamage\sto\sthe\sdatabase. -D 2018-10-11T13:51:48.266 +C Always\sreset\sthe\spager\sbefore\schanging\sthe\scodec. +D 2018-10-11T16:38:56.549 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -490,7 +490,7 @@ F src/os_setup.h 0dbaea40a7d36bf311613d31342e0b99e2536586 F src/os_unix.c f6e91b8fd82af7afbfd073c4974ad6cdb8e62d9f65ceddb45167835a0567fdc0 F src/os_win.c 070cdbb400097c6cda54aa005356095afdc2f3ee691d17192c54724ef146a971 F src/os_win.h 7b073010f1451abe501be30d12f6bc599824944a -F src/pager.c a0d8f686ef64549ad5b356fd30429bd9ee7a06dd42b4d6faa096352ff26b1c5b +F src/pager.c f803ffcd8440b5249549ea103158a1c659bf060961b2389f9fede66a3a352d0b F src/pager.h ecc554a55bc55d1c4ba5e17137b72e238e00bd81e72ff2662d8b9c8c10ae3963 F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179 F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P ec36d15a9e349f4295a9e2215dea0a18e9276e0e4ce2d05021e6b467ab7763bb -R dd28e1032e7501a10c527d67fc7e62ed +P 90cf32cde072a305f30c75a71665d1f9e23e805c0a49f5306f015c056dd70f0c +R a9a8bd986a1a8ae15295689f4551498f U drh -Z de92fbcb4550e9f483f9e1ba42f7c62c +Z 153df3ec174a478a1e4c4ee9d2527b35 diff --git a/manifest.uuid b/manifest.uuid index db516281c9..6e031d644c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -90cf32cde072a305f30c75a71665d1f9e23e805c0a49f5306f015c056dd70f0c \ No newline at end of file +0bf0fd242b93c3bd308ab46db1be9edef141b89db07a0f5a4ed8b23c963da0d5 \ No newline at end of file diff --git a/src/pager.c b/src/pager.c index 92d32fd275..e59cdfcb62 100644 --- a/src/pager.c +++ b/src/pager.c @@ -7021,6 +7021,7 @@ void sqlite3PagerSetCodec( void (*xCodecFree)(void*), void *pCodec ){ + pager_reset(pPager); if( pPager->xCodecFree ) pPager->xCodecFree(pPager->pCodec); pPager->xCodec = pPager->memDb ? 0 : xCodec; pPager->xCodecSizeChng = xCodecSizeChng; From e93f82658a900b157eedf683bb0281f62923825f Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Oct 2018 16:53:37 +0000 Subject: [PATCH 025/109] Fix harmless compiler warnings in the CLI. FossilOrigin-Name: 1916d2912a4ef5c251853de3c9d66417e20f0c0fc8ddfbc84c131dfd798439f6 --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 5 +++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 5fdba93072..fadcf41d71 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Always\sreset\sthe\spager\sbefore\schanging\sthe\scodec. -D 2018-10-11T16:38:56.549 +C Fix\sharmless\scompiler\swarnings\sin\sthe\sCLI. +D 2018-10-11T16:53:37.019 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 -F src/shell.c.in fa815984cdb07aad83fa0231ce3de32e7a4d022ab4cbc40f851b1881839b8fed +F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1771,7 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 90cf32cde072a305f30c75a71665d1f9e23e805c0a49f5306f015c056dd70f0c -R a9a8bd986a1a8ae15295689f4551498f +P 0bf0fd242b93c3bd308ab46db1be9edef141b89db07a0f5a4ed8b23c963da0d5 +R 39f23ee94b2c360e452a32e265e4dde1 U drh -Z 153df3ec174a478a1e4c4ee9d2527b35 +Z 4b0c86ae06c4aa2155872fd34a461306 diff --git a/manifest.uuid b/manifest.uuid index 6e031d644c..0f1c49939f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -0bf0fd242b93c3bd308ab46db1be9edef141b89db07a0f5a4ed8b23c963da0d5 \ No newline at end of file +1916d2912a4ef5c251853de3c9d66417e20f0c0fc8ddfbc84c131dfd798439f6 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index c1db72ce59..e70e2939bd 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3506,7 +3506,8 @@ static const char *(azHelp[]) = { ** Return the number of matches. */ static int showHelp(FILE *out, const char *zPattern){ - int i, j; + int i = 0; + int j = 0; int n = 0; char *zPat; if( zPattern==0 @@ -6169,7 +6170,7 @@ static int do_meta_command(char *zLine, ShellState *p){ if( c=='h' && strncmp(azArg[0], "help", n)==0 ){ if( nArg>=2 ){ - int n = showHelp(p->out, azArg[1]); + n = showHelp(p->out, azArg[1]); if( n==0 ){ utf8_printf(p->out, "Nothing matches '%s'\n", azArg[1]); } From fa5c62ef2ee00ea32320133da89b278ccf21b143 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 11 Oct 2018 18:41:50 +0000 Subject: [PATCH 026/109] Add the textkey and textrekey pragmas. FossilOrigin-Name: f03164d45450cd7ff2162999aa9e51eec7fb5e7cab1fa83d876b544f8f841097 --- manifest | 17 +++++++++-------- manifest.uuid | 2 +- src/pragma.c | 24 ++++++++++++++++++------ src/pragma.h | 29 ++++++++++++++++++++--------- tool/mkpragmatab.tcl | 17 +++++++++++++++++ 5 files changed, 65 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index fadcf41d71..ac92d94aaf 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sharmless\scompiler\swarnings\sin\sthe\sCLI. -D 2018-10-11T16:53:37.019 +C Add\sthe\stextkey\sand\stextrekey\spragmas. +D 2018-10-11T18:41:50.384 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -496,8 +496,8 @@ F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179 F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 -F src/pragma.c a656ff043a03bd94153e6d731a3fbf1bb420207edc969d8fc04b4d2448387901 -F src/pragma.h 0ea639401ed7b8275c145e3a814119831e296118b545421e76ae2e1516f10ad8 +F src/pragma.c 35efa85894f1ae533c03c64591dfc82f916ad78250591082bbae72a2811bceab +F src/pragma.h e50df79399da8c2efc6bd4b7034e242d0dc6ab2016564f08e94103367098b1e4 F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 @@ -1704,7 +1704,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl fc895d5a40e725b19b866b058b3994bfc45db3e7fef40db9e6c6fd921bf8a337 +F tool/mkpragmatab.tcl 656e64fc4e8b5d91525bac1e81834de3217507657e846b1a08375ca195fa8479 F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1771,7 +1771,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 0bf0fd242b93c3bd308ab46db1be9edef141b89db07a0f5a4ed8b23c963da0d5 -R 39f23ee94b2c360e452a32e265e4dde1 +P 1916d2912a4ef5c251853de3c9d66417e20f0c0fc8ddfbc84c131dfd798439f6 +Q +f829099d2558011d2f19ed3e91778b97e4ce0bdaa4a7cd6b0009f705554398ca +R 63af1cda40897d849945c1a22dbd668a U drh -Z 4b0c86ae06c4aa2155872fd34a461306 +Z 865f15d326c847ade3537f91a0382191 diff --git a/manifest.uuid b/manifest.uuid index 0f1c49939f..54e36d8a4f 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1916d2912a4ef5c251853de3c9d66417e20f0c0fc8ddfbc84c131dfd798439f6 \ No newline at end of file +f03164d45450cd7ff2162999aa9e51eec7fb5e7cab1fa83d876b544f8f841097 \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index fd08cc202c..c3c62a722c 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -2118,12 +2118,24 @@ void sqlite3Pragma( #endif #ifdef SQLITE_HAS_CODEC + /* Pragma iArg + ** ---------- ------ + ** key 0 + ** rekey 1 + ** hexkey 2 + ** hexrekey 3 + ** textkey 4 + ** textrekey 5 + */ case PragTyp_KEY: { - if( zRight ) sqlite3_key_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); - break; - } - case PragTyp_REKEY: { - if( zRight ) sqlite3_rekey_v2(db, zDb, zRight, sqlite3Strlen30(zRight)); + if( zRight ){ + int n = pPragma->iArg<4 ? sqlite3Strlen30(zRight) : -1; + if( (pPragma->iArg & 1)==0 ){ + sqlite3_key_v2(db, zDb, zRight, n); + }else{ + sqlite3_rekey_v2(db, zDb, zRight, n); + } + } break; } case PragTyp_HEXKEY: { @@ -2135,7 +2147,7 @@ void sqlite3Pragma( iByte = (iByte<<4) + sqlite3HexToInt(zRight[i]); if( (i&1)!=0 ) zKey[i/2] = iByte; } - if( (zLeft[3] & 0xf)==0xb ){ + if( (pPragma->iArg & 1)==0 ){ sqlite3_key_v2(db, zDb, zKey, i/2); }else{ sqlite3_rekey_v2(db, zDb, zKey, i/2); diff --git a/src/pragma.h b/src/pragma.h index 3d1ba4f341..93e7116f0e 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -48,10 +48,9 @@ #define PragTyp_ACTIVATE_EXTENSIONS 40 #define PragTyp_HEXKEY 41 #define PragTyp_KEY 42 -#define PragTyp_REKEY 43 -#define PragTyp_LOCK_STATUS 44 -#define PragTyp_PARSER_TRACE 45 -#define PragTyp_STATS 46 +#define PragTyp_LOCK_STATUS 43 +#define PragTyp_PARSER_TRACE 44 +#define PragTyp_STATS 45 /* Property flags associated with various pragma. */ #define PragFlg_NeedSchema 0x01 /* Force schema load before running */ @@ -325,12 +324,12 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_HEXKEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 2 }, {/* zName: */ "hexrekey", /* ePragTyp: */ PragTyp_HEXKEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 3 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) #if !defined(SQLITE_OMIT_CHECK) @@ -504,10 +503,10 @@ static const PragmaName aPragmaName[] = { #endif #if defined(SQLITE_HAS_CODEC) {/* zName: */ "rekey", - /* ePragTyp: */ PragTyp_REKEY, + /* ePragTyp: */ PragTyp_KEY, /* ePragFlg: */ 0, /* ColNames: */ 0, 0, - /* iArg: */ 0 }, + /* iArg: */ 1 }, #endif #if !defined(SQLITE_OMIT_FLAG_PRAGMAS) {/* zName: */ "reverse_unordered_selects", @@ -593,6 +592,18 @@ static const PragmaName aPragmaName[] = { /* ePragFlg: */ PragFlg_NoColumns1, /* ColNames: */ 0, 0, /* iArg: */ 0 }, +#endif +#if defined(SQLITE_HAS_CODEC) + {/* zName: */ "textkey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 4 }, + {/* zName: */ "textrekey", + /* ePragTyp: */ PragTyp_KEY, + /* ePragFlg: */ 0, + /* ColNames: */ 0, 0, + /* iArg: */ 5 }, #endif {/* zName: */ "threads", /* ePragTyp: */ PragTyp_THREADS, @@ -655,4 +666,4 @@ static const PragmaName aPragmaName[] = { /* iArg: */ SQLITE_WriteSchema }, #endif }; -/* Number of pragmas: 62 on by default, 79 total. */ +/* Number of pragmas: 62 on by default, 81 total. */ diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index c40e3f5b77..63fe7ce8e4 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -367,16 +367,33 @@ set pragma_def { IF: defined(SQLITE_DEBUG) || defined(SQLITE_TEST) NAME: key + TYPE: KEY + ARG: 0 IF: defined(SQLITE_HAS_CODEC) NAME: rekey + TYPE: KEY + ARG: 1 IF: defined(SQLITE_HAS_CODEC) NAME: hexkey + TYPE: HEXKEY + ARG: 2 IF: defined(SQLITE_HAS_CODEC) NAME: hexrekey TYPE: HEXKEY + ARG: 3 + IF: defined(SQLITE_HAS_CODEC) + + NAME: textkey + TYPE: KEY + ARG: 4 + IF: defined(SQLITE_HAS_CODEC) + + NAME: textrekey + TYPE: KEY + ARG: 5 IF: defined(SQLITE_HAS_CODEC) NAME: activate_extensions From bafad06139a14a7deefc836af52e22605abc6f25 Mon Sep 17 00:00:00 2001 From: drh Date: Fri, 12 Oct 2018 15:01:56 +0000 Subject: [PATCH 027/109] Test case modifications to support SEE. FossilOrigin-Name: 02b6f8f2778c371130c512e980c3db07c7e76dcf7dd92a878b86e4b6a47ca307 --- manifest | 17 ++++++------- manifest.uuid | 2 +- test/dbstatus.test | 4 +-- test/pragma3.test | 6 ++++- test/shared.test | 62 ++++++++++++++++++++++++---------------------- 5 files changed, 48 insertions(+), 43 deletions(-) diff --git a/manifest b/manifest index ac92d94aaf..2ee3c8fa1d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\stextkey\sand\stextrekey\spragmas. -D 2018-10-11T18:41:50.384 +C Test\scase\smodifications\sto\ssupport\sSEE. +D 2018-10-12T15:01:56.030 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -770,7 +770,7 @@ F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373 F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c -F test/dbstatus.test c15fa97f743dac7ce996814c84b56317e138895ee15ce27f15b608aa6924c90a +F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef F test/default.test 0cb49b1c315a0d81c81d775e407f66906a2a604d F test/delete.test 31832b0c45ecb51a54348c68db173be462985901e6ed7f403d6d7a8f70ab4ef0 @@ -1175,7 +1175,7 @@ F test/permutations.test 8749e292c8f7e98072049543da8c0fe60e1625f0a9f490686230609 F test/pg_common.tcl 301ac19c1a52fd55166d26db929b3b89165c634d52b5f8ad76ea8cb06960db30 F test/pragma.test 7c8cfc328a1717a95663cf8edb06c52ddfeaf97bb0aee69ae7457132e8d39e7d F test/pragma2.test e5d5c176360c321344249354c0c16aec46214c9f -F test/pragma3.test 14c12bc5352b1e100e0b6b44f371053a81ccf8ed +F test/pragma3.test 8300aa9c63cff1027006ca34bf413a148abbd6dcd471fa9a1ded322fe18c0df9 F test/pragma4.test 3046501bee2f652dc2a4f9c87781e2741361d6864439c8381aba6c3b774b335c F test/pragma5.test 824ce6ced5d6b7ec71abe37fc6005ff836fe39d638273dc5192b39864b9ee983 F test/pragmafault.test 275edaf3161771d37de60e5c2b412627ac94cef11739236bec12ed1258b240f8 @@ -1255,7 +1255,7 @@ F test/server1.test c2b00864514a68a0e6fd518659dc95d0050307a357a08969872bef027d78 F test/session.test 78fa2365e93d3663a6e933f86e7afc395adf18be F test/sessionfuzz-data1.db 1f8d5def831f19b1c74571037f0d53a588ea49a6c4ca2a028fc0c27ef896dbcb F test/sessionfuzz.c b0fcdcf757451957e17396a3af5171f1fdf9b2babc81da9fa35675df46c4729a -F test/shared.test 1da9dbad400cee0d93f252ccf76e1ae007a63746 +F test/shared.test 1826673eb5eb745fb91a3bdac99a7737057742ae38dcb0fe076a384d6727578b F test/shared2.test 03eb4a8d372e290107d34b6ce1809919a698e879 F test/shared3.test ab693f9b6e156b8bfb2a0ad94f29fe69602a5d38 F test/shared4.test c75f476804e76e26bf6fa0e7b421fb0ca7d07558 @@ -1771,8 +1771,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1916d2912a4ef5c251853de3c9d66417e20f0c0fc8ddfbc84c131dfd798439f6 -Q +f829099d2558011d2f19ed3e91778b97e4ce0bdaa4a7cd6b0009f705554398ca -R 63af1cda40897d849945c1a22dbd668a +P f03164d45450cd7ff2162999aa9e51eec7fb5e7cab1fa83d876b544f8f841097 +R b06a0e84dfe3f0b011ce56cc2f8b5cd1 U drh -Z 865f15d326c847ade3537f91a0382191 +Z f26fa73bb00e67aa8b5d34053794de3a diff --git a/manifest.uuid b/manifest.uuid index 54e36d8a4f..2ce3280c9c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f03164d45450cd7ff2162999aa9e51eec7fb5e7cab1fa83d876b544f8f841097 \ No newline at end of file +02b6f8f2778c371130c512e980c3db07c7e76dcf7dd92a878b86e4b6a47ca307 \ No newline at end of file diff --git a/test/dbstatus.test b/test/dbstatus.test index 57b91cda1a..564b9c5966 100644 --- a/test/dbstatus.test +++ b/test/dbstatus.test @@ -379,9 +379,9 @@ foreach ::lookaside_buffer_size {0 64 120} { # The following tests focus on DBSTATUS_CACHE_USED_SHARED # ifcapable shared_cache { - if {[permutation]=="memsys3" + if {([permutation]=="memsys3" || [permutation]=="memsys5" - || $::tcl_platform(os)=="Linux"} { + || $::tcl_platform(os)=="Linux") && ![sqlite3 -has-codec]} { proc do_cacheused_test {tn db res} { set cu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED 0] set pcu [sqlite3_db_status $db SQLITE_DBSTATUS_CACHE_USED_SHARED 0] diff --git a/test/pragma3.test b/test/pragma3.test index 8a4f4f9d84..eebbcbb9c6 100644 --- a/test/pragma3.test +++ b/test/pragma3.test @@ -15,7 +15,11 @@ set testdir [file dirname $argv0] source $testdir/tester.tcl -do_not_use_codec + +if {[sqlite3 -has-codec]} { + finish_test + return +} do_execsql_test pragma3-100 { PRAGMA data_version; diff --git a/test/shared.test b/test/shared.test index 4eab476582..589df4d631 100644 --- a/test/shared.test +++ b/test/shared.test @@ -1145,38 +1145,40 @@ do_test shared-$av-16.8 { # Shared cache on named memory databases attached to readonly connections. # -do_test shared-$av-16.8.1 { +if {![sqlite3 -has-codec]} { + do_test shared-$av-16.8.1 { + db1 close + db2 close + + sqlite3 db test1.db + db eval { + CREATE TABLE yy(a, b); + INSERT INTO yy VALUES(77, 88); + } + db close + + sqlite3 db1 test1.db -uri 1 -readonly 1 + sqlite3 db2 test2.db -uri 1 + + db1 eval { + ATTACH 'file:mem?mode=memory&cache=shared' AS shared; + CREATE TABLE shared.xx(a, b); + INSERT INTO xx VALUES(55, 66); + } + db2 eval { + ATTACH 'file:mem?mode=memory&cache=shared' AS shared; + SELECT * FROM xx; + } + } {55 66} + + do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88} + do_test shared-$av-16.8.3 { + list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg + } {1 {attempt to write a readonly database}} + db1 close db2 close - - sqlite3 db test1.db - db eval { - CREATE TABLE yy(a, b); - INSERT INTO yy VALUES(77, 88); - } - db close - - sqlite3 db1 test1.db -uri 1 -readonly 1 - sqlite3 db2 test2.db -uri 1 - - db1 eval { - ATTACH 'file:mem?mode=memory&cache=shared' AS shared; - CREATE TABLE shared.xx(a, b); - INSERT INTO xx VALUES(55, 66); - } - db2 eval { - ATTACH 'file:mem?mode=memory&cache=shared' AS shared; - SELECT * FROM xx; - } -} {55 66} - -do_test shared-$av-16.8.2 { db1 eval { SELECT * FROM yy } } {77 88} -do_test shared-$av-16.8.3 { - list [catch {db1 eval { INSERT INTO yy VALUES(1, 2) }} msg] $msg -} {1 {attempt to write a readonly database}} - -db1 close -db2 close +} } ;# end of autovacuum on/off loop From 44748f27a6c966b7ceef693e1fbc4bd089e73866 Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 18 Oct 2018 14:59:21 +0000 Subject: [PATCH 028/109] Add the SQLITE_CHANGESETAPPLY_INVERT flag to sessions. For inverting and applying a changeset in a single step. FossilOrigin-Name: d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 --- ext/session/session_common.tcl | 17 +++++ ext/session/sessioninvert.test | 120 +++++++++++++++++++++++++++++++++ ext/session/sqlite3session.c | 35 ++++++---- ext/session/sqlite3session.h | 6 ++ ext/session/test_session.c | 28 +++++--- manifest | 21 +++--- manifest.uuid | 2 +- 7 files changed, 198 insertions(+), 31 deletions(-) create mode 100644 ext/session/sessioninvert.test diff --git a/ext/session/session_common.tcl b/ext/session/session_common.tcl index 543b970327..ceffdad4ba 100644 --- a/ext/session/session_common.tcl +++ b/ext/session/session_common.tcl @@ -95,6 +95,23 @@ proc changeset_from_sql {sql {dbname main}} { return $changeset } +proc patchset_from_sql {sql {dbname main}} { + set rc [catch { + sqlite3session S db $dbname + db eval "SELECT name FROM $dbname.sqlite_master WHERE type = 'table'" { + S attach $name + } + db eval $sql + S patchset + } patchset] + catch { S delete } + + if {$rc} { + error $patchset + } + return $patchset +} + proc do_then_apply_sql {sql {dbname main}} { proc xConflict args { return "OMIT" } set rc [catch { diff --git a/ext/session/sessioninvert.test b/ext/session/sessioninvert.test new file mode 100644 index 0000000000..52260af215 --- /dev/null +++ b/ext/session/sessioninvert.test @@ -0,0 +1,120 @@ +# 2018 October 18 +# +# 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 regression tests for SQLite library. +# + +if {![info exists testdir]} { + set testdir [file join [file dirname [info script]] .. .. test] +} +source [file join [file dirname [info script]] session_common.tcl] +source $testdir/tester.tcl +ifcapable !session {finish_test; return} + +set testprefix sessioninvert + +proc do_invert_test {tn sql} { + + forcecopy test.db test.db2 + sqlite3 db2 test.db2 + + set C [changeset_from_sql $sql] + + forcecopy test.db test.db3 + sqlite3 db3 test.db3 + uplevel [list do_test $tn.1 [list compare_db db db3] {}] + + set I [sqlite3changeset_invert $C] + sqlite3changeset_apply db $I {} + uplevel [list do_test $tn.2 [list compare_db db db2] {}] + + sqlite3changeset_apply_v2 -invert db3 $C {} + uplevel [list do_test $tn.3 [list compare_db db db3] {}] + + catch { db2 close } + catch { db3 close } +} + +do_execsql_test 1.0 { + CREATE TABLE t1(a PRIMARY KEY, b, c); + CREATE TABLE t2(d, e, f, PRIMARY KEY(e, f)); + + INSERT INTO t1 VALUES(1, 'one', 'i'); + INSERT INTO t1 VALUES(2, 'two', 'ii'); + INSERT INTO t1 VALUES(3, 'three', 'iii'); + INSERT INTO t1 VALUES(4, 'four', 'iv'); + INSERT INTO t1 VALUES(5, 'five', 'v'); + INSERT INTO t1 VALUES(6, 'six', 'vi'); + + INSERT INTO t2 SELECT * FROM t1; +} + +do_invert_test 1.1 { + INSERT INTO t1 VALUES(7, 'seven', 'vii'); +} + +do_invert_test 1.2 { + DELETE FROM t1 WHERE a<4; +} + +do_invert_test 1.2 { + UPDATE t1 SET c=5; +} + +do_invert_test 1.3 { + UPDATE t1 SET b = a+1 WHERE a%2; + DELETE FROM t2; + INSERT INTO t1 VALUES(10, 'ten', NULL); +} + +do_invert_test 1.4 { + UPDATE t2 SET d = d-1; +} + +do_execsql_test 2.0 { + ANALYZE; + PRAGMA writable_schema = 1; + DROP TABLE IF EXISTS sqlite_stat4; + SELECT * FROM sqlite_stat1; +} { + t2 sqlite_autoindex_t2_1 {6 1 1} + t1 sqlite_autoindex_t1_1 {6 1} +} + +do_invert_test 2.1 { + INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3'); +} + +do_invert_test 2.2 { + DELETE FROM sqlite_stat1; +} + +do_invert_test 2.3 { + UPDATE sqlite_stat1 SET stat = 'hello world'; +} + +do_test 3.0 { + forcecopy test.db test.db2 + sqlite3 db2 test.db2 + set P [patchset_from_sql { + INSERT INTO t2 VALUES(1, 2, 3); + DELETE FROM t2 WHERE d = 3; + }] + + list [catch { sqlite3changeset_apply_v2 -invert db2 $P {} } msg] $msg +} {1 SQLITE_CORRUPT} + +do_test 3.1 { + sqlite3changeset_apply_v2 db2 $P {} + compare_db db db2 +} {} + + +finish_test diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index abbf16dc75..20810ee4f1 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -87,6 +87,7 @@ struct sqlite3_changeset_iter { SessionInput in; /* Input buffer or stream */ SessionBuffer tblhdr; /* Buffer to hold apValue/zTab/abPK/ */ int bPatchset; /* True if this is a patchset */ + int bInvert; /* True to invert changeset */ int rc; /* Iterator error code */ sqlite3_stmt *pConflict; /* Points to conflicting row, if any */ char *zTab; /* Current table */ @@ -2540,7 +2541,8 @@ static int sessionChangesetStart( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn, int nChangeset, /* Size of buffer pChangeset in bytes */ - void *pChangeset /* Pointer to buffer containing changeset */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int bInvert /* True to invert changeset */ ){ sqlite3_changeset_iter *pRet; /* Iterator to return */ int nByte; /* Number of bytes to allocate for iterator */ @@ -2560,6 +2562,7 @@ static int sessionChangesetStart( pRet->in.xInput = xInput; pRet->in.pIn = pIn; pRet->in.bEof = (xInput ? 0 : 1); + pRet->bInvert = bInvert; /* Populate the output variable and return success. */ *pp = pRet; @@ -2574,7 +2577,7 @@ int sqlite3changeset_start( int nChangeset, /* Size of buffer pChangeset in bytes */ void *pChangeset /* Pointer to buffer containing changeset */ ){ - return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0); } /* @@ -2585,7 +2588,7 @@ int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ){ - return sessionChangesetStart(pp, xInput, pIn, 0, 0); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0); } /* @@ -2964,10 +2967,10 @@ static int sessionChangesetNext( op = p->in.aData[p->in.iNext++]; } - if( p->zTab==0 ){ + if( p->zTab==0 || (p->bPatchset && p->bInvert) ){ /* The first record in the changeset is not a table header. Must be a ** corrupt changeset. */ - assert( p->in.iNext==1 ); + assert( p->in.iNext==1 || p->zTab ); return (p->rc = SQLITE_CORRUPT_BKPT); } @@ -2992,33 +2995,39 @@ static int sessionChangesetNext( *paRec = &p->in.aData[p->in.iNext]; p->in.iNext += *pnRec; }else{ + sqlite3_value **apOld = (p->bInvert ? &p->apValue[p->nCol] : p->apValue); + sqlite3_value **apNew = (p->bInvert ? p->apValue : &p->apValue[p->nCol]); /* If this is an UPDATE or DELETE, read the old.* record. */ if( p->op!=SQLITE_INSERT && (p->bPatchset==0 || p->op==SQLITE_DELETE) ){ u8 *abPK = p->bPatchset ? p->abPK : 0; - p->rc = sessionReadRecord(&p->in, p->nCol, abPK, p->apValue); + p->rc = sessionReadRecord(&p->in, p->nCol, abPK, apOld); if( p->rc!=SQLITE_OK ) return p->rc; } /* If this is an INSERT or UPDATE, read the new.* record. */ if( p->op!=SQLITE_DELETE ){ - p->rc = sessionReadRecord(&p->in, p->nCol, 0, &p->apValue[p->nCol]); + p->rc = sessionReadRecord(&p->in, p->nCol, 0, apNew); if( p->rc!=SQLITE_OK ) return p->rc; } - if( p->bPatchset && p->op==SQLITE_UPDATE ){ + if( (p->bPatchset || p->bInvert) && p->op==SQLITE_UPDATE ){ /* If this is an UPDATE that is part of a patchset, then all PK and ** modified fields are present in the new.* record. The old.* record ** is currently completely empty. This block shifts the PK fields from ** new.* to old.*, to accommodate the code that reads these arrays. */ for(i=0; inCol; i++){ - assert( p->apValue[i]==0 ); + assert( p->bPatchset==0 || p->apValue[i]==0 ); if( p->abPK[i] ){ + assert( p->apValue[i]==0 ); p->apValue[i] = p->apValue[i+p->nCol]; if( p->apValue[i]==0 ) return (p->rc = SQLITE_CORRUPT_BKPT); p->apValue[i+p->nCol] = 0; } } + }else if( p->bInvert ){ + if( p->op==SQLITE_INSERT ) p->op = SQLITE_DELETE; + else if( p->op==SQLITE_DELETE ) p->op = SQLITE_INSERT; } } @@ -4182,7 +4191,7 @@ static int sessionRetryConstraints( SessionBuffer cons = pApply->constraints; memset(&pApply->constraints, 0, sizeof(SessionBuffer)); - rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf); + rc = sessionChangesetStart(&pIter2, 0, 0, cons.nBuf, cons.aBuf, 0); if( rc==SQLITE_OK ){ int nByte = 2*pApply->nCol*sizeof(sqlite3_value*); int rc2; @@ -4436,7 +4445,8 @@ int sqlite3changeset_apply_v2( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, 0, 0, nChangeset, pChangeset,bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags @@ -4493,7 +4503,8 @@ int sqlite3changeset_apply_v2_strm( int flags ){ sqlite3_changeset_iter *pIter; /* Iterator to skip through changeset */ - int rc = sqlite3changeset_start_strm(&pIter, xInput, pIn); + int bInverse = !!(flags & SQLITE_CHANGESETAPPLY_INVERT); + int rc = sessionChangesetStart(&pIter, xInput, pIn, 0, 0, bInverse); if( rc==SQLITE_OK ){ rc = sessionChangesetApply( db, pIter, xFilter, xConflict, pCtx, ppRebase, pnRebase, flags diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index a3def5f1df..a9fbed94ef 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -1151,8 +1151,14 @@ int sqlite3changeset_apply_v2( ** causes the sessions module to omit this savepoint. In this case, if the ** caller has an open transaction or savepoint when apply_v2() is called, ** it may revert the partially applied changeset by rolling it back. +** +**
SQLITE_CHANGESETAPPLY_INVERT
+** Invert the changeset before applying it. This is equivalent to inverting +** a changeset using sqlite3changeset_invert() before applying it. It is +** an error to specify this flag with a patchset. */ #define SQLITE_CHANGESETAPPLY_NOSAVEPOINT 0x0001 +#define SQLITE_CHANGESETAPPLY_INVERT 0x0002 /* ** CAPI3REF: Constants Passed To The Conflict Handler diff --git a/ext/session/test_session.c b/ext/session/test_session.c index 3b6c24fd11..6eba2114c7 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -737,20 +737,32 @@ static int SQLITE_TCLAPI testSqlite3changesetApply( sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR); /* Check for the -nosavepoint flag */ - if( bV2 && objc>1 ){ - const char *z1 = Tcl_GetString(objv[1]); - int n = strlen(z1); - if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){ - flags = SQLITE_CHANGESETAPPLY_NOSAVEPOINT; - objc--; - objv++; + if( bV2 ){ + if( objc>1 ){ + const char *z1 = Tcl_GetString(objv[1]); + int n = strlen(z1); + if( n>1 && n<=12 && 0==sqlite3_strnicmp("-nosavepoint", z1, n) ){ + flags |= SQLITE_CHANGESETAPPLY_NOSAVEPOINT; + objc--; + objv++; + } + } + if( objc>1 ){ + const char *z1 = Tcl_GetString(objv[1]); + int n = strlen(z1); + if( n>1 && n<=7 && 0==sqlite3_strnicmp("-invert", z1, n) ){ + flags |= SQLITE_CHANGESETAPPLY_INVERT; + objc--; + objv++; + } } } if( objc!=4 && objc!=5 ){ const char *zMsg; if( bV2 ){ - zMsg = "?-nosavepoint? DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?"; + zMsg = "?-nosavepoint? ?-inverse? " + "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?"; }else{ zMsg = "DB CHANGESET CONFLICT-SCRIPT ?FILTER-SCRIPT?"; } diff --git a/manifest b/manifest index 2ee3c8fa1d..5231fee516 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Test\scase\smodifications\sto\ssupport\sSEE. -D 2018-10-12T15:01:56.030 +C Add\sthe\sSQLITE_CHANGESETAPPLY_INVERT\sflag\sto\ssessions.\sFor\sinverting\sand\sapplying\sa\schangeset\sin\sa\ssingle\sstep. +D 2018-10-18T14:59:21.849 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -407,18 +407,19 @@ F ext/session/sessionE.test 0a616c4ad8fd2c05f23217ebb6212ef80b7fef30f5f086a6633a F ext/session/sessionF.test c2f178d4dfd723a5fd94a730ea2ccb44c669e3ce F ext/session/sessionG.test 3edde849c4071078d92bd682c836186f6e4e5a3fb6bcf3fc1de1a7caa5e4427d F ext/session/sessionH.test 332b60e4c2e0a680105e11936201cabe378216f307e2747803cea56fa7d9ebae -F ext/session/session_common.tcl ee925e0d233677e45e395fb1f559b84068ce7baa8aa1034441739d3e87ee249c +F ext/session/session_common.tcl 29ec9910aca1e996ca1c8531b8cecabf96eb576aa53de65a8ff03d848b9a2a8b F ext/session/session_speed_test.c edc1f96fd5e0e4b16eb03e2a73041013d59e8723 F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28f0c1cc142c3ec F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7 F ext/session/sessionfault2.test 555a8504de03d59b369ef20209585da5aeb2671dedabc4584e9ffe6269689185 +F ext/session/sessioninvert.test d4d8a89990de35e8e56d4d14d14bc7f191aa6f4c2b3731c7ce0fe64b640d29d3 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c ba76c7f01d4c71ab4d134cfda0ba43faae04bff01b8e81d1279a6101c706e3b5 -F ext/session/sqlite3session.h c01820d5b6e73e86d88008f4d1c1c7dfb83422963018292b864028a0400ceccf -F ext/session/test_session.c dba36c6c0153b22501112d3e8882b5c946cf617c955153b6712bd2f8ba1428c0 +F ext/session/sqlite3session.c db0eb1bdadedf9905076fbff66ab7979d92a5d8649f09f39d9268c0d035aeeba +F ext/session/sqlite3session.h 1b0b2bd69ae4cba5fd5fee050ef79707d45a1a3eed41077a92d14556fdcc1f6e +F ext/session/test_session.c 9447482597c7569e49b3db152a300920a4b634d5de86508a94e4338df99b3fda F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e629edbe2648 @@ -1771,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f03164d45450cd7ff2162999aa9e51eec7fb5e7cab1fa83d876b544f8f841097 -R b06a0e84dfe3f0b011ce56cc2f8b5cd1 -U drh -Z f26fa73bb00e67aa8b5d34053794de3a +P 02b6f8f2778c371130c512e980c3db07c7e76dcf7dd92a878b86e4b6a47ca307 +R af6e82cd2e535125553a7eab8caf31bb +U dan +Z 5cdef990913d6faf4879f9cb06bcd872 diff --git a/manifest.uuid b/manifest.uuid index 2ce3280c9c..7f89b9f2dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -02b6f8f2778c371130c512e980c3db07c7e76dcf7dd92a878b86e4b6a47ca307 \ No newline at end of file +d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 \ No newline at end of file From 9c18ef09a57a4c0244cd41942e088c73526f03bb Mon Sep 17 00:00:00 2001 From: dan Date: Thu, 18 Oct 2018 15:17:18 +0000 Subject: [PATCH 029/109] Take steps to avoid a potential integer overflow in sessionBufferGrow(). FossilOrigin-Name: f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 --- ext/session/sqlite3session.c | 6 +++--- manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 20810ee4f1..a1ca9a78b1 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -1794,12 +1794,12 @@ int sqlite3session_attach( static int sessionBufferGrow(SessionBuffer *p, int nByte, int *pRc){ if( *pRc==SQLITE_OK && p->nAlloc-p->nBufnAlloc ? p->nAlloc : 128; + i64 nNew = p->nAlloc ? p->nAlloc : 128; do { nNew = nNew*2; - }while( nNew<(p->nBuf+nByte) ); + }while( (nNew-p->nBuf)aBuf, nNew); + aNew = (u8 *)sqlite3_realloc64(p->aBuf, nNew); if( 0==aNew ){ *pRc = SQLITE_NOMEM; }else{ diff --git a/manifest b/manifest index 5231fee516..748230c555 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sSQLITE_CHANGESETAPPLY_INVERT\sflag\sto\ssessions.\sFor\sinverting\sand\sapplying\sa\schangeset\sin\sa\ssingle\sstep. -D 2018-10-18T14:59:21.849 +C Take\ssteps\sto\savoid\sa\spotential\sinteger\soverflow\sin\ssessionBufferGrow(). +D 2018-10-18T15:17:18.844 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -417,7 +417,7 @@ F ext/session/sessioninvert.test d4d8a89990de35e8e56d4d14d14bc7f191aa6f4c2b3731c F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c db0eb1bdadedf9905076fbff66ab7979d92a5d8649f09f39d9268c0d035aeeba +F ext/session/sqlite3session.c 7c1875f0c124a1bd18beb95ef0fd7ce288e553c883d2f258b921d4612995a258 F ext/session/sqlite3session.h 1b0b2bd69ae4cba5fd5fee050ef79707d45a1a3eed41077a92d14556fdcc1f6e F ext/session/test_session.c 9447482597c7569e49b3db152a300920a4b634d5de86508a94e4338df99b3fda F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 02b6f8f2778c371130c512e980c3db07c7e76dcf7dd92a878b86e4b6a47ca307 -R af6e82cd2e535125553a7eab8caf31bb +P d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 +R e7a7201238f957af096a10fc5c94b75d U dan -Z 5cdef990913d6faf4879f9cb06bcd872 +Z 58cb59871e256ea172e37001653f6319 diff --git a/manifest.uuid b/manifest.uuid index 7f89b9f2dc..f1588fde60 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 \ No newline at end of file +f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 \ No newline at end of file From 46de0728802703082967d4c563d12a2b5d154e57 Mon Sep 17 00:00:00 2001 From: dan Date: Sat, 20 Oct 2018 13:48:09 +0000 Subject: [PATCH 030/109] Add the sqlite3changeset_start_v2() - a new version of _start() that accepts a flags parameter - and a streaming equivalent to the sessions module. Also add the SQLITE_CHANGESETSTART_INVERT flag, used with start_v2() to invert a changeset while iterating through it. FossilOrigin-Name: cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 --- ext/session/sessioninvert.test | 51 ++++++++++++++++++++++++++++++---- ext/session/sqlite3session.c | 18 ++++++++++++ ext/session/sqlite3session.h | 34 ++++++++++++++++++++++- ext/session/test_session.c | 49 ++++++++++++++++++++++++-------- manifest | 18 ++++++------ manifest.uuid | 2 +- 6 files changed, 143 insertions(+), 29 deletions(-) diff --git a/ext/session/sessioninvert.test b/ext/session/sessioninvert.test index 52260af215..49205f6b26 100644 --- a/ext/session/sessioninvert.test +++ b/ext/session/sessioninvert.test @@ -20,7 +20,13 @@ ifcapable !session {finish_test; return} set testprefix sessioninvert -proc do_invert_test {tn sql} { +proc iter_invert {C} { + set x [list] + sqlite3session_foreach -invert c $C { lappend x $c } + set x +} + +proc do_invert_test {tn sql {iter {}}} { forcecopy test.db test.db2 sqlite3 db2 test.db2 @@ -38,6 +44,10 @@ proc do_invert_test {tn sql} { sqlite3changeset_apply_v2 -invert db3 $C {} uplevel [list do_test $tn.3 [list compare_db db db3] {}] + if {$iter!=""} { + uplevel [list do_test $tn.4 [list iter_invert $C] [list {*}$iter]] + } + catch { db2 close } catch { db3 close } } @@ -58,24 +68,44 @@ do_execsql_test 1.0 { do_invert_test 1.1 { INSERT INTO t1 VALUES(7, 'seven', 'vii'); +} { + {DELETE t1 0 X.. {i 7 t seven t vii} {}} } do_invert_test 1.2 { DELETE FROM t1 WHERE a<4; -} - -do_invert_test 1.2 { - UPDATE t1 SET c=5; +} { + {INSERT t1 0 X.. {} {i 1 t one t i}} + {INSERT t1 0 X.. {} {i 2 t two t ii}} + {INSERT t1 0 X.. {} {i 3 t three t iii}} } do_invert_test 1.3 { + UPDATE t1 SET c=5; +} { + {UPDATE t1 0 X.. {i 1 {} {} i 5} {{} {} {} {} t i}} + {UPDATE t1 0 X.. {i 2 {} {} i 5} {{} {} {} {} t ii}} + {UPDATE t1 0 X.. {i 3 {} {} i 5} {{} {} {} {} t iii}} + {UPDATE t1 0 X.. {i 4 {} {} i 5} {{} {} {} {} t iv}} + {UPDATE t1 0 X.. {i 5 {} {} i 5} {{} {} {} {} t v}} + {UPDATE t1 0 X.. {i 6 {} {} i 5} {{} {} {} {} t vi}} +} + +do_invert_test 1.4 { UPDATE t1 SET b = a+1 WHERE a%2; DELETE FROM t2; INSERT INTO t1 VALUES(10, 'ten', NULL); } -do_invert_test 1.4 { +do_invert_test 1.5 { UPDATE t2 SET d = d-1; +} { + {UPDATE t2 0 .XX {i 2 t three t iii} {i 3 {} {} {} {}}} + {UPDATE t2 0 .XX {i 1 t two t ii} {i 2 {} {} {} {}}} + {UPDATE t2 0 .XX {i 5 t six t vi} {i 6 {} {} {} {}}} + {UPDATE t2 0 .XX {i 3 t four t iv} {i 4 {} {} {} {}}} + {UPDATE t2 0 .XX {i 0 t one t i} {i 1 {} {} {} {}}} + {UPDATE t2 0 .XX {i 4 t five t v} {i 5 {} {} {} {}}} } do_execsql_test 2.0 { @@ -90,10 +120,15 @@ do_execsql_test 2.0 { do_invert_test 2.1 { INSERT INTO sqlite_stat1 VALUES('t3', 'idx2', '1 2 3'); +} { + {DELETE sqlite_stat1 0 XX. {t t3 t idx2 t {1 2 3}} {}} } do_invert_test 2.2 { DELETE FROM sqlite_stat1; +} { + {INSERT sqlite_stat1 0 XX. {} {t t1 t sqlite_autoindex_t1_1 t {6 1}}} + {INSERT sqlite_stat1 0 XX. {} {t t2 t sqlite_autoindex_t2_1 t {6 1 1}}} } do_invert_test 2.3 { @@ -112,6 +147,10 @@ do_test 3.0 { } {1 SQLITE_CORRUPT} do_test 3.1 { + list [catch { sqlite3session_foreach -invert db2 $P {} } msg] $msg +} {1 SQLITE_CORRUPT} + +do_test 3.2 { sqlite3changeset_apply_v2 db2 $P {} compare_db db db2 } {} diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index a1ca9a78b1..1a7f003eb6 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -2579,6 +2579,15 @@ int sqlite3changeset_start( ){ return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, 0); } +int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int nChangeset, /* Size of buffer pChangeset in bytes */ + void *pChangeset, /* Pointer to buffer containing changeset */ + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, 0, 0, nChangeset, pChangeset, bInvert); +} /* ** Streaming version of sqlite3changeset_start(). @@ -2590,6 +2599,15 @@ int sqlite3changeset_start_strm( ){ return sessionChangesetStart(pp, xInput, pIn, 0, 0, 0); } +int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, /* OUT: Changeset iterator handle */ + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +){ + int bInvert = !!(flags & SQLITE_CHANGESETSTART_INVERT); + return sessionChangesetStart(pp, xInput, pIn, 0, 0, bInvert); +} /* ** If the SessionInput object passed as the only argument is a streaming diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index a9fbed94ef..b9303635e7 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -473,12 +473,38 @@ int sqlite3session_isempty(sqlite3_session *pSession); ** consecutively. There is no chance that the iterator will visit a change ** the applies to table X, then one for table Y, and then later on visit ** another change for table X. +** +** The behavior of sqlite3changeset_start_v2() and its streaming equivalent +** may be modified by passing a combination of +** [SQLITE_CHANGESETSTART_INVERT | supported flags] as the 4th parameter. +** +** Note that the sqlite3changeset_start_v2() API is still experimental +** and therefore subject to change. */ int sqlite3changeset_start( sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ int nChangeset, /* Size of changeset blob in bytes */ void *pChangeset /* Pointer to blob containing changeset */ ); +int sqlite3changeset_start_v2( + sqlite3_changeset_iter **pp, /* OUT: New changeset iterator handle */ + int nChangeset, /* Size of changeset blob in bytes */ + void *pChangeset, /* Pointer to blob containing changeset */ + int flags /* SESSION_CHANGESETSTART_* flags */ +); + +/* +** CAPI3REF: Flags for sqlite3changeset_start_v2 +** +** The following flags may passed via the 4th parameter to +** [sqlite3changeset_start_v2] and [sqlite3changeset_start_v2_strm]: +** +**
SQLITE_CHANGESETAPPLY_INVERT
+** Invert the changeset while iterating through it. This is equivalent to +** inverting a changeset using sqlite3changeset_invert() before applying it. +** It is an error to specify this flag with a patchset. +*/ +#define SQLITE_CHANGESETSTART_INVERT 0x0002 /* @@ -1133,7 +1159,7 @@ int sqlite3changeset_apply_v2( ), void *pCtx, /* First argument passed to xConflict */ void **ppRebase, int *pnRebase, /* OUT: Rebase data */ - int flags /* Combination of SESSION_APPLY_* flags */ + int flags /* SESSION_CHANGESETAPPLY_* flags */ ); /* @@ -1552,6 +1578,12 @@ int sqlite3changeset_start_strm( int (*xInput)(void *pIn, void *pData, int *pnData), void *pIn ); +int sqlite3changeset_start_v2_strm( + sqlite3_changeset_iter **pp, + int (*xInput)(void *pIn, void *pData, int *pnData), + void *pIn, + int flags +); int sqlite3session_changeset_strm( sqlite3_session *pSession, int (*xOutput)(void *pOut, const void *pData, int nData), diff --git a/ext/session/test_session.c b/ext/session/test_session.c index 6eba2114c7..016050fdba 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -981,31 +981,56 @@ static int SQLITE_TCLAPI test_sqlite3session_foreach( Tcl_Obj *pCS; Tcl_Obj *pScript; int isCheckNext = 0; + int isInvert = 0; TestStreamInput sStr; memset(&sStr, 0, sizeof(sStr)); - if( objc>1 ){ + while( objc>1 ){ char *zOpt = Tcl_GetString(objv[1]); - isCheckNext = (strcmp(zOpt, "-next")==0); + int nOpt = strlen(zOpt); + if( zOpt[0]!='-' ) break; + if( nOpt<=7 && 0==sqlite3_strnicmp(zOpt, "-invert", nOpt) ){ + isInvert = 1; + }else + if( nOpt<=5 && 0==sqlite3_strnicmp(zOpt, "-next", nOpt) ){ + isCheckNext = 1; + }else{ + break; + } + objv++; + objc--; } - if( objc!=4+isCheckNext ){ - Tcl_WrongNumArgs(interp, 1, objv, "?-next? VARNAME CHANGESET SCRIPT"); + if( objc!=4 ){ + Tcl_WrongNumArgs( + interp, 1, objv, "?-next? ?-invert? VARNAME CHANGESET SCRIPT"); return TCL_ERROR; } - pVarname = objv[1+isCheckNext]; - pCS = objv[2+isCheckNext]; - pScript = objv[3+isCheckNext]; + pVarname = objv[1]; + pCS = objv[2]; + pScript = objv[3]; pChangeset = (void *)Tcl_GetByteArrayFromObj(pCS, &nChangeset); sStr.nStream = test_tcl_integer(interp, SESSION_STREAM_TCL_VAR); - if( sStr.nStream==0 ){ - rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + if( isInvert ){ + int f = SQLITE_CHANGESETSTART_INVERT; + if( sStr.nStream==0 ){ + rc = sqlite3changeset_start_v2(&pIter, nChangeset, pChangeset, f); + }else{ + void *pCtx = (void*)&sStr; + sStr.aData = (unsigned char*)pChangeset; + sStr.nData = nChangeset; + rc = sqlite3changeset_start_v2_strm(&pIter, testStreamInput, pCtx, f); + } }else{ - sStr.aData = (unsigned char*)pChangeset; - sStr.nData = nChangeset; - rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr); + if( sStr.nStream==0 ){ + rc = sqlite3changeset_start(&pIter, nChangeset, pChangeset); + }else{ + sStr.aData = (unsigned char*)pChangeset; + sStr.nData = nChangeset; + rc = sqlite3changeset_start_strm(&pIter, testStreamInput, (void*)&sStr); + } } if( rc!=SQLITE_OK ){ return test_session_error(interp, rc, 0); diff --git a/manifest b/manifest index 748230c555..2cea732c3d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Take\ssteps\sto\savoid\sa\spotential\sinteger\soverflow\sin\ssessionBufferGrow(). -D 2018-10-18T15:17:18.844 +C Add\sthe\ssqlite3changeset_start_v2()\s-\sa\snew\sversion\sof\s_start()\sthat\saccepts\sa\sflags\sparameter\s-\sand\sa\sstreaming\sequivalent\sto\sthe\ssessions\smodule.\sAlso\sadd\sthe\sSQLITE_CHANGESETSTART_INVERT\sflag,\sused\swith\sstart_v2()\sto\sinvert\sa\schangeset\swhile\siterating\sthrough\sit. +D 2018-10-20T13:48:09.884 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -413,13 +413,13 @@ F ext/session/sessionat.test efe88965e74ff1bc2af9c310b28358c02d420c1fb2705cc7a28 F ext/session/sessiondiff.test ad13dd65664bae26744e1f18eb3cbd5588349b7e9118851d8f9364248d67bcec F ext/session/sessionfault.test da273f2712b6411e85e71465a1733b8501dbf6f7 F ext/session/sessionfault2.test 555a8504de03d59b369ef20209585da5aeb2671dedabc4584e9ffe6269689185 -F ext/session/sessioninvert.test d4d8a89990de35e8e56d4d14d14bc7f191aa6f4c2b3731c7ce0fe64b640d29d3 +F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b2953cf48683fb2724169 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c 7c1875f0c124a1bd18beb95ef0fd7ce288e553c883d2f258b921d4612995a258 -F ext/session/sqlite3session.h 1b0b2bd69ae4cba5fd5fee050ef79707d45a1a3eed41077a92d14556fdcc1f6e -F ext/session/test_session.c 9447482597c7569e49b3db152a300920a4b634d5de86508a94e4338df99b3fda +F ext/session/sqlite3session.c 7b9ae0d7f3f89551c893ad5beafe831df1c097623f6abc983dad7b6dbca726cb +F ext/session/sqlite3session.h 11f229ec3f123da40c31500b01a2f6807185293d9173a5e0aa5be42ad70ab85d +F ext/session/test_session.c 4699405b2afcf6833c11358cdb9da50f8f5d2b7123f44b3e2cef1cfb88c9fa39 F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e629edbe2648 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d4b6406e7f5ba06ac73ab9fdef57232b2459e0af12420ed946ebed6aef46f0b1 -R e7a7201238f957af096a10fc5c94b75d +P f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 +R 3605ff60956926e38b591288ff5e2c64 U dan -Z 58cb59871e256ea172e37001653f6319 +Z 32299de6da54da0b9ad3507fdc1f1f73 diff --git a/manifest.uuid b/manifest.uuid index f1588fde60..a6502f7411 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 \ No newline at end of file +cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 \ No newline at end of file From 0f5f54062cf943b0506018761b3ee5c6d0e842da Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 23 Oct 2018 13:48:19 +0000 Subject: [PATCH 031/109] Fix a problem with using window functions in compound (UNION, INTERSECT etc.) queries. FossilOrigin-Name: 059ff53a46c7f1e4bf3e7dc558312beef67826c2753e2ab7e4e7df498b37b617 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/window.c | 2 +- test/window1.test | 45 +++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 54 insertions(+), 9 deletions(-) diff --git a/manifest b/manifest index 2cea732c3d..fb76c66c2b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3changeset_start_v2()\s-\sa\snew\sversion\sof\s_start()\sthat\saccepts\sa\sflags\sparameter\s-\sand\sa\sstreaming\sequivalent\sto\sthe\ssessions\smodule.\sAlso\sadd\sthe\sSQLITE_CHANGESETSTART_INVERT\sflag,\sused\swith\sstart_v2()\sto\sinvert\sa\schangeset\swhile\siterating\sthrough\sit. -D 2018-10-20T13:48:09.884 +C Fix\sa\sproblem\swith\susing\swindow\sfunctions\sin\scompound\s(UNION,\sINTERSECT\setc.)\nqueries. +D 2018-10-23T13:48:19.879 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -593,7 +593,7 @@ F src/where.c a54a3d639bcd751d1474deff58e239b2e475a96e1b8f9178aa7864df8782a4e3 F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f F src/wherecode.c 3df0a541373d5f999684d761e4bd700d57adb46c7d39da4e77b767b5adcd5893 F src/whereexpr.c 1b5a5a7876997f65232bbf19c5c1eeb47eb328b8fa5b28c865543052904cde00 -F src/window.c a28d8d42c51c7e31136a42f3e245282049d4a9466b36d7bd765772991472df41 +F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd F test/affinity3.test 6a101af2fc945ce2912f6fe54dd646018551710d @@ -1646,7 +1646,7 @@ F test/win32heap.test 10fd891266bd00af68671e702317726375e5407561d859be1aa04696f2 F test/win32lock.test fbf107c91d8f5512be5a5b87c4c42ab9fdd54972 F test/win32longpath.test 169c75a3b2e43481f4a62122510210c67b08f26d F test/win32nolock.test ac4f08811a562e45a5755e661f45ca85892bdbbc -F test/window1.test 474bef1a6ac291755e51d1f9458dc11117c1870ac5e08b4d3938649b215f8334 +F test/window1.test 02e481ac48c445b43bab7b3cf1e4115165b5127a1aa29e14f5372922c836f1a4 F test/window2.tcl 9bfa842d8a62b0d36dc8c1b5972206393c43847433c6d75940b87fec93ce3143 F test/window2.test 8e6d2a1b9f54dfebee1cde961c8590cd87b4db45c50f44947a211e1b63c2a05e F test/window3.tcl 577a3b1ff913208e5248c04dab9df17fd760ce159a752789e26d0cb4a5f91823 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P f7affa2e708d1b4c7c47157bcb18e9f79611ca45a93ebc88de6dc96f84a677e7 -R 3605ff60956926e38b591288ff5e2c64 +P cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 +R d52bd090bd9fd502659683e6d6b4324b U dan -Z 32299de6da54da0b9ad3507fdc1f1f73 +Z 24c25ee2516ea8b59659cd5b9047d478 diff --git a/manifest.uuid b/manifest.uuid index a6502f7411..0f238787cf 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 \ No newline at end of file +059ff53a46c7f1e4bf3e7dc558312beef67826c2753e2ab7e4e7df498b37b617 \ No newline at end of file diff --git a/src/window.c b/src/window.c index 36cfc1c280..f5deae9a6e 100644 --- a/src/window.c +++ b/src/window.c @@ -746,7 +746,7 @@ static ExprList *exprListAppendList( */ int sqlite3WindowRewrite(Parse *pParse, Select *p){ int rc = SQLITE_OK; - if( p->pWin ){ + if( p->pWin && p->pPrior==0 ){ Vdbe *v = sqlite3GetVdbe(pParse); sqlite3 *db = pParse->db; Select *pSub = 0; /* The subquery */ diff --git a/test/window1.test b/test/window1.test index 4980305449..a8399a8606 100644 --- a/test/window1.test +++ b/test/window1.test @@ -549,4 +549,49 @@ do_execsql_test 12.110 { ORDER BY b LIMIT 2; } {2 B two 3 C three} +#------------------------------------------------------------------------- + +do_execsql_test 13.1 { + DROP TABLE IF EXISTS t1; + CREATE TABLE t1(a int, b int); + INSERT INTO t1 VALUES(1,11); + INSERT INTO t1 VALUES(2,12); +} + +do_execsql_test 13.2.1 { + SELECT a, rank() OVER(ORDER BY b) FROM t1; + SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; +} { + 1 1 2 2 2 1 1 2 +} +do_execsql_test 13.2.2 { + SELECT a, rank() OVER(ORDER BY b) FROM t1 + UNION ALL + SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; +} { + 1 1 2 2 2 1 1 2 +} +do_execsql_test 13.3 { + SELECT a, rank() OVER(ORDER BY b) FROM t1 + UNION + SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; +} { + 1 1 1 2 2 1 2 2 +} + +do_execsql_test 13.4 { + SELECT a, rank() OVER(ORDER BY b) FROM t1 + EXCEPT + SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; +} { + 1 1 2 2 +} + +do_execsql_test 13.5 { + SELECT a, rank() OVER(ORDER BY b) FROM t1 + INTERSECT + SELECT a, rank() OVER(ORDER BY b DESC) FROM t1; +} { +} + finish_test From e23d05e807ccc3a9ef7605eb6aed1089e31208c5 Mon Sep 17 00:00:00 2001 From: drh Date: Wed, 24 Oct 2018 23:55:41 +0000 Subject: [PATCH 032/109] Add the ENABLE_GEOPOLY case to the compile_options pragma. FossilOrigin-Name: de940296d227c96db4d0cf913fc5c0e5138729eda7cda0a0ac6b704cce1e1e1e --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/ctime.c | 3 +++ 3 files changed, 11 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index fb76c66c2b..7cbd3c5a2b 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sa\sproblem\swith\susing\swindow\sfunctions\sin\scompound\s(UNION,\sINTERSECT\setc.)\nqueries. -D 2018-10-23T13:48:19.879 +C Add\sthe\sENABLE_GEOPOLY\scase\sto\sthe\scompile_options\spragma. +D 2018-10-24T23:55:41.740 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -451,7 +451,7 @@ F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd9 F src/build.c 0b3d422770877d74ee6d54f4c122d82c48f7d04ee3bfb91702e402de7f5c45ac F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c b157b01081f92442f8b0218ddb93ddce8ebddad36dbddeecfdd771561dd4f387 +F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3 F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cbedcb9aaefdfe00453efbdf0eac6c15e1f53bbe8fff2e7d534a5adf23be04f5 -R d52bd090bd9fd502659683e6d6b4324b -U dan -Z 24c25ee2516ea8b59659cd5b9047d478 +P 059ff53a46c7f1e4bf3e7dc558312beef67826c2753e2ab7e4e7df498b37b617 +R 88b06779070fae47149f041be44e3466 +U drh +Z d7bdc9586bb70ec6171514ee74a2ea6d diff --git a/manifest.uuid b/manifest.uuid index 0f238787cf..cf0b4d4ba2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -059ff53a46c7f1e4bf3e7dc558312beef67826c2753e2ab7e4e7df498b37b617 \ No newline at end of file +de940296d227c96db4d0cf913fc5c0e5138729eda7cda0a0ac6b704cce1e1e1e \ No newline at end of file diff --git a/src/ctime.c b/src/ctime.c index f408a3b5f0..5bc1e5c74f 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -235,6 +235,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_FTS5 "ENABLE_FTS5", #endif +#if SQLITE_ENABLE_GEOPOLY + "ENABLE_GEOPOLY", +#endif #if SQLITE_ENABLE_HIDDEN_COLUMNS "ENABLE_HIDDEN_COLUMNS", #endif From 8e5bfedd22019b0fc14d75a9b3bff2c23cd7f2b1 Mon Sep 17 00:00:00 2001 From: drh Date: Thu, 25 Oct 2018 14:15:37 +0000 Subject: [PATCH 033/109] In the WHERE-constraint propagation optimization, if there are duplicate constraint, make sure only one of them propagates. Proposed fix for ticket [cf5ed20fc8621b165]. FossilOrigin-Name: 5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/select.c | 25 ++++++++++++++++++++----- test/whereL.test | 11 +++++++++++ 4 files changed, 39 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index 7cbd3c5a2b..8332621247 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\sENABLE_GEOPOLY\scase\sto\sthe\scompile_options\spragma. -D 2018-10-24T23:55:41.740 +C In\sthe\sWHERE-constraint\spropagation\soptimization,\sif\sthere\sare\sduplicate\nconstraint,\smake\ssure\sonly\sone\sof\sthem\spropagates.\s\sProposed\sfix\sfor\nticket\s[cf5ed20fc8621b165]. +D 2018-10-25T14:15:37.103 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -504,7 +504,7 @@ F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 -F src/select.c 33aacf1c17c64a00788c779b23d0875dd0d90eb4c08f867ebc31139ef3a67c95 +F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 @@ -1636,7 +1636,7 @@ F test/whereH.test e4b07f7a3c2f5d31195cd33710054c78667573b2 F test/whereI.test b7769ee8dbefd987fb266715fee887f05f9ff180016b06fca7fa402df739193b F test/whereJ.test 88287550f6ee604422403b053455b1ad894eeaa5c35d348532dfa1439286cb9a F test/whereK.test f8e3cf26a8513ecc7f514f54df9f0572c046c42b -F test/whereL.test 84de61afe4b8e5a3ff7d741c990d85cb44b3ce798cd8412d5603930f3f75014f +F test/whereL.test 0a19fc44cd1122040f56c934f1b14d0ca85bde28f270268a428dd9796ea0634c F test/wherefault.test 1374c3aa198388925246475f84ad4cd5f9528864 F test/wherelfault.test 9012e4ef5259058b771606616bd007af5d154e64cc25fa9fd4170f6411db44e3 F test/wherelimit.test 592081800806d297dd7449b1030c863d2883d6d42901837ccd2e5a9bd962edb0 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 059ff53a46c7f1e4bf3e7dc558312beef67826c2753e2ab7e4e7df498b37b617 -R 88b06779070fae47149f041be44e3466 +P de940296d227c96db4d0cf913fc5c0e5138729eda7cda0a0ac6b704cce1e1e1e +R d5acc9d026bd9c265f6de052be0f92d3 U drh -Z d7bdc9586bb70ec6171514ee74a2ea6d +Z 4bc6cbb9e4f3ab72bb6d01ca2996d24a diff --git a/manifest.uuid b/manifest.uuid index cf0b4d4ba2..802efe5c70 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -de940296d227c96db4d0cf913fc5c0e5138729eda7cda0a0ac6b704cce1e1e1e \ No newline at end of file +5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07 \ No newline at end of file diff --git a/src/select.c b/src/select.c index 1d2cd1a969..c60ff27001 100644 --- a/src/select.c +++ b/src/select.c @@ -4074,7 +4074,7 @@ static int flattenSubquery( #endif /* !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) */ /* -** A structure to keep track of all of the column values that fixed to +** A structure to keep track of all of the column values that are fixed to ** a known value due to WHERE clause constraints of the form COLUMN=VALUE. */ typedef struct WhereConst WhereConst; @@ -4086,13 +4086,28 @@ struct WhereConst { }; /* -** Add a new entry to the pConst object +** Add a new entry to the pConst object. Except, do not add duplicate +** pColumn entires. */ static void constInsert( - WhereConst *pConst, - Expr *pColumn, - Expr *pValue + WhereConst *pConst, /* The WhereConst into which we are inserting */ + Expr *pColumn, /* The COLUMN part of the constraint */ + Expr *pValue /* The VALUE part of the constraint */ ){ + int i; + assert( pColumn->op==TK_COLUMN ); + + /* 2018-10-25 ticket [cf5ed20f] + ** Make sure the same pColumn is not inserted more than once */ + for(i=0; inConst; i++){ + const Expr *pExpr = pConst->apExpr[i*2]; + assert( pExpr->op==TK_COLUMN ); + if( pExpr->iTable==pColumn->iTable + && pExpr->iColumn==pColumn->iColumn + ){ + return; /* Already present. Return without doing anything. */ + } + } pConst->nConst++; pConst->apExpr = sqlite3DbReallocOrFree(pConst->pParse->db, pConst->apExpr, diff --git a/test/whereL.test b/test/whereL.test index 3fe725b877..d0e5f0b604 100644 --- a/test/whereL.test +++ b/test/whereL.test @@ -111,4 +111,15 @@ do_execsql_test 302 { AND B.id=subq.zz; } {1} +# 2018-10-25: Ticket [cf5ed20f] +# Incorrect join result with duplicate WHERE clause constraint. +# +do_execsql_test 400 { + CREATE TABLE x(a, b, c); + CREATE TABLE y(a, b); + INSERT INTO x VALUES (1, 0, 1); + INSERT INTO y VALUES (1, 2); + SELECT x.a FROM x JOIN y ON x.c = y.a WHERE x.b = 1 AND x.b = 1; +} {} + finish_test From f689400dc7ca5ec26725b47355650210d20a9ae8 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Oct 2018 15:36:53 +0000 Subject: [PATCH 034/109] Prevent an == constraint specified using the table-valued-function argument syntax from being used to optimize any scan not related to the virtual table for which it was specified as an argument. FossilOrigin-Name: 4d46685f282409f7154be288719cbea4b743d7ea5315a55a91462003497469f7 --- manifest | 16 ++++++------- manifest.uuid | 2 +- src/whereexpr.c | 6 +++-- test/bestindex4.test | 53 ++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 66 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 8332621247..a7604adb25 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sWHERE-constraint\spropagation\soptimization,\sif\sthere\sare\sduplicate\nconstraint,\smake\ssure\sonly\sone\sof\sthem\spropagates.\s\sProposed\sfix\sfor\nticket\s[cf5ed20fc8621b165]. -D 2018-10-25T14:15:37.103 +C Prevent\san\s==\sconstraint\sspecified\susing\sthe\stable-valued-function\sargument\nsyntax\sfrom\sbeing\sused\sto\soptimize\sany\sscan\snot\srelated\sto\sthe\svirtual\stable\nfor\swhich\sit\swas\sspecified\sas\san\sargument. +D 2018-10-26T15:36:53.982 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -592,7 +592,7 @@ F src/walker.c fb94aadc9099ff9c6506d0a8b88d51266005bcaa265403f3d7caf732a562eb66 F src/where.c a54a3d639bcd751d1474deff58e239b2e475a96e1b8f9178aa7864df8782a4e3 F src/whereInt.h f125f29fca80890768e0b2caa14f95db74b2dacd3a122a168f97aa7b64d6968f F src/wherecode.c 3df0a541373d5f999684d761e4bd700d57adb46c7d39da4e77b767b5adcd5893 -F src/whereexpr.c 1b5a5a7876997f65232bbf19c5c1eeb47eb328b8fa5b28c865543052904cde00 +F src/whereexpr.c 7660a5845113f05f60fa615aed40047a058587a36b70a7b0c28b74253a19ffa1 F src/window.c 6550e2850ebced51100ef83d49b00a1cf03f81a482dafedafb0320df647ed8fc F test/8_3_names.test ebbb5cd36741350040fd28b432ceadf495be25b2 F test/affinity2.test a6d901b436328bd67a79b41bb0ac2663918fe3bd @@ -669,7 +669,7 @@ F test/bc_common.tcl b5e42d80305be95697e6370e015af571e5333a1c F test/bestindex1.test 852170bddbb21daa121fabcc274640ff83d7d8705912e8b5fe7ed2c5a9a9224a F test/bestindex2.test 9a0ccd320b6525eec3a706aae6cdab7e1b7b5abca75027e39f39f755e76e5928 F test/bestindex3.test 001788a114ad96d81d5154fe77c7f1e26e84b3a2b5635ca29e4f96f6decc534e -F test/bestindex4.test 4cb5ff7dbaebadb87d366f51969271778423b455 +F test/bestindex4.test 210eac9323ef88881212d6ae90c84dad86ec14d82c6f4fc9a9ee24c76a8f2014 F test/bestindex5.test 412b42f8036b28d8b2f3534d89389ad946a4b1a65a12263f51936f7424296f1b F test/bestindex6.test d856a9bb63d927493575823eed44053bc36251e241aa364e54d0f2a2d302e1d4 F test/between.test 34d375fb5ce1ae283ffe82b6b233e9f38e84fc6c @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P de940296d227c96db4d0cf913fc5c0e5138729eda7cda0a0ac6b704cce1e1e1e -R d5acc9d026bd9c265f6de052be0f92d3 -U drh -Z 4bc6cbb9e4f3ab72bb6d01ca2996d24a +P 5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07 +R 8af441be159a5306c3bcc729f277a8dc +U dan +Z 7280881af13a5758968cff92a52a3f86 diff --git a/manifest.uuid b/manifest.uuid index 802efe5c70..59f3e0c5b9 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07 \ No newline at end of file +4d46685f282409f7154be288719cbea4b743d7ea5315a55a91462003497469f7 \ No newline at end of file diff --git a/src/whereexpr.c b/src/whereexpr.c index 8f3791e798..c69d7fe581 100644 --- a/src/whereexpr.c +++ b/src/whereexpr.c @@ -1573,6 +1573,7 @@ void sqlite3WhereTabFuncArgs( pArgs = pItem->u1.pFuncArg; if( pArgs==0 ) return; for(j=k=0; jnExpr; j++){ + Expr *pRhs; while( knCol && (pTab->aCol[k].colFlags & COLFLAG_HIDDEN)==0 ){k++;} if( k>=pTab->nCol ){ sqlite3ErrorMsg(pParse, "too many arguments on %s() - max %d", @@ -1584,8 +1585,9 @@ void sqlite3WhereTabFuncArgs( pColRef->iTable = pItem->iCursor; pColRef->iColumn = k++; pColRef->y.pTab = pTab; - pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, - sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0)); + pRhs = sqlite3PExpr(pParse, TK_UPLUS, + sqlite3ExprDup(pParse->db, pArgs->a[j].pExpr, 0), 0); + pTerm = sqlite3PExpr(pParse, TK_EQ, pColRef, pRhs); whereClauseInsert(pWC, pTerm, TERM_DYNAMIC); } } diff --git a/test/bestindex4.test b/test/bestindex4.test index 64727bd0d7..9a92625c4a 100644 --- a/test/bestindex4.test +++ b/test/bestindex4.test @@ -117,4 +117,57 @@ for {set param1 0} {$param1<16} {incr param1} { } } +#------------------------------------------------------------------------- +# Test that a parameter passed to a table-valued function cannot be +# used to drive an index. i.e. that in the following: +# +# SELECT * FROM tbl, vtab(tbl.x); +# +# The implicit constraint "tbl.x = vtab.hidden" is not optimized using +# an index on tbl.x. +# +reset_db +register_tcl_module db +proc vtab_command {method args} { + switch -- $method { + xConnect { + return "CREATE TABLE t1(a, b, c, d HIDDEN)" + } + + xBestIndex { + set clist [lindex $args 0] + if {[llength $clist]!=1} { error "unexpected constraint list" } + catch { array unset C } + array set C [lindex $clist 0] + if {$C(usable)} { + return [list omit 0 idxnum 555 rows 10 cost 100] + } + return [list cost 100000000] + } + + } + + return {} +} + +do_execsql_test 2.0 { + CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); + CREATE TABLE t1 (x INT PRIMARY KEY); +} {} + +do_execsql_test 2.1 { + EXPLAIN QUERY PLAN SELECT * FROM t1, x1 WHERE x1.d=t1.x; +} { + 3 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 0:} + 7 0 0 {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (x=?)} +} + +do_execsql_test 2.2 { + EXPLAIN QUERY PLAN SELECT * FROM t1, x1(t1.x) +} { + 3 0 0 {SCAN TABLE t1} + 5 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:} +} + + finish_test From 1f48e67db125ad20716ff617c75a49859bb2bf16 Mon Sep 17 00:00:00 2001 From: dan Date: Fri, 26 Oct 2018 17:05:00 +0000 Subject: [PATCH 035/109] Add the sqlite3session_config() interface. For configuring global parameters belonging to the sessions module. FossilOrigin-Name: 1e69f3ff057b0be27a9e79842de2485f8299799f309e89bfa7597dd688e0975b --- ext/session/session1.test | 7 +++++++ ext/session/sqlite3session.c | 37 ++++++++++++++++++++++++++------- ext/session/sqlite3session.h | 39 +++++++++++++++++++++++++++++++++++ ext/session/test_session.c | 40 ++++++++++++++++++++++++++++++++++++ manifest | 18 ++++++++-------- manifest.uuid | 2 +- 6 files changed, 126 insertions(+), 17 deletions(-) diff --git a/ext/session/session1.test b/ext/session/session1.test index f423a0cf4b..0eb850a795 100644 --- a/ext/session/session1.test +++ b/ext/session/session1.test @@ -655,6 +655,13 @@ do_test $tn.13.3 { } {1 one 2 two 3 iii} execsql ROLLBACK +do_test $tn.14.1 { sqlite3session_config strm_size -1 } 64 +do_test $tn.14.2 { sqlite3session_config strm_size 65536 } 65536 +do_test $tn.14.3 { sqlite3session_config strm_size 64 } 64 +do_test $tn.14.4 { + list [catch {sqlite3session_config invalid 123} msg] $msg +} {1 SQLITE_MISUSE} + }] } diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 1a7f003eb6..108b74ca2a 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -25,6 +25,8 @@ typedef struct SessionInput SessionInput; # endif #endif +static int sessions_strm_chunk_size = SESSIONS_STRM_CHUNK_SIZE; + typedef struct SessionHook SessionHook; struct SessionHook { void *pCtx; @@ -2397,12 +2399,12 @@ static int sessionGenerateChangeset( rc = sqlite3_reset(pSel); } - /* If the buffer is now larger than SESSIONS_STRM_CHUNK_SIZE, pass + /* If the buffer is now larger than sessions_strm_chunk_size, pass ** its contents to the xOutput() callback. */ if( xOutput && rc==SQLITE_OK && buf.nBuf>nNoop - && buf.nBuf>SESSIONS_STRM_CHUNK_SIZE + && buf.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, (void*)buf.aBuf, buf.nBuf); nNoop = -1; @@ -2614,7 +2616,7 @@ int sqlite3changeset_start_v2_strm( ** object and the buffer is full, discard some data to free up space. */ static void sessionDiscardData(SessionInput *pIn){ - if( pIn->xInput && pIn->iNext>=SESSIONS_STRM_CHUNK_SIZE ){ + if( pIn->xInput && pIn->iNext>=sessions_strm_chunk_size ){ int nMove = pIn->buf.nBuf - pIn->iNext; assert( nMove>=0 ); if( nMove>0 ){ @@ -2637,7 +2639,7 @@ static int sessionInputBuffer(SessionInput *pIn, int nByte){ int rc = SQLITE_OK; if( pIn->xInput ){ while( !pIn->bEof && (pIn->iNext+nByte)>=pIn->nData && rc==SQLITE_OK ){ - int nNew = SESSIONS_STRM_CHUNK_SIZE; + int nNew = sessions_strm_chunk_size; if( pIn->bNoDiscard==0 ) sessionDiscardData(pIn); if( SQLITE_OK==sessionBufferGrow(&pIn->buf, nNew, &rc) ){ @@ -3362,7 +3364,7 @@ static int sessionChangesetInvert( } assert( rc==SQLITE_OK ); - if( xOutput && sOut.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ + if( xOutput && sOut.nBuf>=sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; if( rc!=SQLITE_OK ) goto finished_invert; @@ -4895,7 +4897,7 @@ static int sessionChangegroupOutput( sessionAppendByte(&buf, p->op, &rc); sessionAppendByte(&buf, p->bIndirect, &rc); sessionAppendBlob(&buf, p->aRecord, p->nRecord, &rc); - if( rc==SQLITE_OK && xOutput && buf.nBuf>=SESSIONS_STRM_CHUNK_SIZE ){ + if( rc==SQLITE_OK && xOutput && buf.nBuf>=sessions_strm_chunk_size ){ rc = xOutput(pOut, buf.aBuf, buf.nBuf); buf.nBuf = 0; } @@ -5291,7 +5293,7 @@ static int sessionRebase( sessionAppendByte(&sOut, pIter->bIndirect, &rc); sessionAppendBlob(&sOut, aRec, nRec, &rc); } - if( rc==SQLITE_OK && xOutput && sOut.nBuf>SESSIONS_STRM_CHUNK_SIZE ){ + if( rc==SQLITE_OK && xOutput && sOut.nBuf>sessions_strm_chunk_size ){ rc = xOutput(pOut, sOut.aBuf, sOut.nBuf); sOut.nBuf = 0; } @@ -5402,4 +5404,25 @@ void sqlite3rebaser_delete(sqlite3_rebaser *p){ } } +/* +** Global configuration +*/ +int sqlite3session_config(int op, void *pArg){ + int rc = SQLITE_OK; + switch( op ){ + case SQLITE_SESSION_CONFIG_STRMSIZE: { + int *pInt = (int*)pArg; + if( *pInt>0 ){ + sessions_strm_chunk_size = *pInt; + } + *pInt = sessions_strm_chunk_size; + break; + } + default: + rc = SQLITE_MISUSE; + break; + } + return rc; +} + #endif /* SQLITE_ENABLE_SESSION && SQLITE_ENABLE_PREUPDATE_HOOK */ diff --git a/ext/session/sqlite3session.h b/ext/session/sqlite3session.h index b9303635e7..3d1df429e3 100644 --- a/ext/session/sqlite3session.h +++ b/ext/session/sqlite3session.h @@ -1610,6 +1610,45 @@ int sqlite3rebaser_rebase_strm( void *pOut ); +/* +** CAPI3REF: Configure global parameters +** +** The sqlite3session_config() interface is used to make global configuration +** changes to the sessions module in order to tune it to the specific needs +** of the application. +** +** The sqlite3session_config() interface is not threadsafe. If it is invoked +** while any other thread is inside any other sessions method then the +** results are undefined. Furthermore, if it is invoked after any sessions +** related objects have been created, the results are also undefined. +** +** The first argument to the sqlite3session_config() function must be one +** of the SQLITE_SESSION_CONFIG_XXX constants defined below. The +** interpretation of the (void*) value passed as the second parameter and +** the effect of calling this function depends on the value of the first +** parameter. +** +**
+**
SQLITE_SESSION_CONFIG_STRMSIZE
+** By default, the sessions module streaming interfaces attempt to input +** and output data in approximately 1 KiB chunks. This operand may be used +** to set and query the value of this configuration setting. The pointer +** passed as the second argument must point to a value of type (int). +** If this value is greater than 0, it is used as the new streaming data +** chunk size for both input and output. Before returning, the (int) value +** pointed to by pArg is set to the final value of the streaming interface +** chunk size. +**
+** +** This function returns SQLITE_OK if successful, or an SQLite error code +** otherwise. +*/ +int sqlite3session_config(int op, void *pArg); + +/* +** CAPI3REF: Values for sqlite3session_config(). +*/ +#define SQLITE_SESSION_CONFIG_STRMSIZE 1 /* ** Make sure we can call this stuff from C++. diff --git a/ext/session/test_session.c b/ext/session/test_session.c index 016050fdba..1e76616cbb 100644 --- a/ext/session/test_session.c +++ b/ext/session/test_session.c @@ -1239,6 +1239,45 @@ static int SQLITE_TCLAPI test_sqlite3rebaser_create( return TCL_OK; } +/* +** tclcmd: sqlite3rebaser_configure OP VALUE +*/ +static int SQLITE_TCLAPI test_sqlite3session_config( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + struct ConfigOpt { + const char *zSub; + int op; + } aSub[] = { + { "strm_size", SQLITE_SESSION_CONFIG_STRMSIZE }, + { "invalid", 0 }, + { 0 } + }; + int rc; + int iSub; + int iVal; + + if( objc!=3 ){ + Tcl_WrongNumArgs(interp, 1, objv, "OP VALUE"); + return SQLITE_ERROR; + } + rc = Tcl_GetIndexFromObjStruct(interp, + objv[1], aSub, sizeof(aSub[0]), "sub-command", 0, &iSub + ); + if( rc!=TCL_OK ) return rc; + if( Tcl_GetIntFromObj(interp, objv[2], &iVal) ) return TCL_ERROR; + + rc = sqlite3session_config(aSub[iSub].op, (void*)&iVal); + if( rc!=SQLITE_OK ){ + return test_session_error(interp, rc, 0); + } + Tcl_SetObjResult(interp, Tcl_NewIntObj(iVal)); + return TCL_OK; +} + int TestSession_Init(Tcl_Interp *interp){ struct Cmd { const char *zCmd; @@ -1254,6 +1293,7 @@ int TestSession_Init(Tcl_Interp *interp){ test_sqlite3changeset_apply_replace_all }, { "sql_exec_changeset", test_sql_exec_changeset }, { "sqlite3rebaser_create", test_sqlite3rebaser_create }, + { "sqlite3session_config", test_sqlite3session_config }, }; int i; diff --git a/manifest b/manifest index a7604adb25..5268fa17f5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Prevent\san\s==\sconstraint\sspecified\susing\sthe\stable-valued-function\sargument\nsyntax\sfrom\sbeing\sused\sto\soptimize\sany\sscan\snot\srelated\sto\sthe\svirtual\stable\nfor\swhich\sit\swas\sspecified\sas\san\sargument. -D 2018-10-26T15:36:53.982 +C Add\sthe\ssqlite3session_config()\sinterface.\sFor\sconfiguring\sglobal\sparameters\nbelonging\sto\sthe\ssessions\smodule. +D 2018-10-26T17:05:00.030 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -391,7 +391,7 @@ F ext/rtree/util/randomshape.tcl 54ee03d0d4a1c621806f7f44d5b78d2db8fac26e0e8687c F ext/rtree/viewrtree.tcl eea6224b3553599ae665b239bd827e182b466024 F ext/rtree/visual01.txt e9c2564083bcd30ec51b07f881bffbf0e12b50a3f6fced0c222c5c1d2f94ac66 F ext/session/changeset.c 4ccbaa4531944c24584bf6a61ba3a39c62b6267a -F ext/session/session1.test 4532116484f525110eb4cfff7030c59354c0cde9def4d109466b0df2b35ad5cc +F ext/session/session1.test 0b2f88995832ea040ae8e83a1ad4afa99c00b85c779d213da73a95ea4113233e F ext/session/session2.test 284de45abae4cc1082bc52012ee81521d5ac58e0 F ext/session/session3.test ce9ce3dfa489473987f899e9f6a0f2db9bde3479 F ext/session/session4.test 6778997065b44d99c51ff9cece047ff9244a32856b328735ae27ddef68979c40 @@ -417,9 +417,9 @@ F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b295 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c 7b9ae0d7f3f89551c893ad5beafe831df1c097623f6abc983dad7b6dbca726cb -F ext/session/sqlite3session.h 11f229ec3f123da40c31500b01a2f6807185293d9173a5e0aa5be42ad70ab85d -F ext/session/test_session.c 4699405b2afcf6833c11358cdb9da50f8f5d2b7123f44b3e2cef1cfb88c9fa39 +F ext/session/sqlite3session.c 0119dac126fb2b4ca6bed53509071d87a7977f3e97a2f8b8fa13c6e57beb6f76 +F ext/session/sqlite3session.h 05351d2f50a1203fdffbeb590fdbbc796c9a6bfcd0c9b26cf6db3854e3eb4294 +F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 F ext/userauth/user-auth.txt e6641021a9210364665fe625d067617d03f27b04 F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e629edbe2648 @@ -1772,7 +1772,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 5d5b596f152bb2781011a05f75f9e200774d4f69d648ef68de577b4ace973e07 -R 8af441be159a5306c3bcc729f277a8dc +P 4d46685f282409f7154be288719cbea4b743d7ea5315a55a91462003497469f7 +R c10d7255298165478f73aa6752c71429 U dan -Z 7280881af13a5758968cff92a52a3f86 +Z 0397ec87e4a63dd314f7afa18223a9dc diff --git a/manifest.uuid b/manifest.uuid index 59f3e0c5b9..9c1c574c1c 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4d46685f282409f7154be288719cbea4b743d7ea5315a55a91462003497469f7 \ No newline at end of file +1e69f3ff057b0be27a9e79842de2485f8299799f309e89bfa7597dd688e0975b \ No newline at end of file From 65da285e6aabbea5073a02e7ba1aa29712ec55fa Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 27 Oct 2018 00:47:33 +0000 Subject: [PATCH 036/109] Initial code for a fuzzing tool on database file that works with the -fsanitize=fuzzer option of clang. FossilOrigin-Name: 90d12094d36957fbded71545add8a5dc206798fdacc17d4d161d715569a7f991 --- manifest | 14 ++++--- manifest.uuid | 2 +- test/dbfuzz2-seed1.db | Bin 0 -> 3584 bytes test/dbfuzz2.c | 83 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 92 insertions(+), 7 deletions(-) create mode 100644 test/dbfuzz2-seed1.db create mode 100644 test/dbfuzz2.c diff --git a/manifest b/manifest index 5268fa17f5..58e0c599f7 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Add\sthe\ssqlite3session_config()\sinterface.\sFor\sconfiguring\sglobal\sparameters\nbelonging\sto\sthe\ssessions\smodule. -D 2018-10-26T17:05:00.030 +C Initial\scode\sfor\sa\sfuzzing\stool\son\sdatabase\sfile\sthat\sworks\swith\sthe\n-fsanitize=fuzzer\soption\sof\sclang. +D 2018-10-27T00:47:33.850 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 @@ -770,6 +770,8 @@ F test/dataversion1.test 6e5e86ac681f0782e766ebcb56c019ae001522d114e0e111e5ebf68 F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373 F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e +F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee +F test/dbfuzz2.c 726596ade432252e5a71d63ac1d14ebe499187091f3f32ad6302f7f1283229ff F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef @@ -1772,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 4d46685f282409f7154be288719cbea4b743d7ea5315a55a91462003497469f7 -R c10d7255298165478f73aa6752c71429 -U dan -Z 0397ec87e4a63dd314f7afa18223a9dc +P 1e69f3ff057b0be27a9e79842de2485f8299799f309e89bfa7597dd688e0975b +R de82b9ab66221c495821cf10212a8a14 +U drh +Z f0456761bef72ec9a03e18592dbe2afd diff --git a/manifest.uuid b/manifest.uuid index 9c1c574c1c..9af6513d41 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -1e69f3ff057b0be27a9e79842de2485f8299799f309e89bfa7597dd688e0975b \ No newline at end of file +90d12094d36957fbded71545add8a5dc206798fdacc17d4d161d715569a7f991 \ No newline at end of file diff --git a/test/dbfuzz2-seed1.db b/test/dbfuzz2-seed1.db new file mode 100644 index 0000000000000000000000000000000000000000..17f0550d61626eef82b17461866eb43d5500980a GIT binary patch literal 3584 zcmeHJO>5Lp6n*D?_9uP?%&~ic>WUq13NI+)g{G4%8O(A@d9T3EjJK z;mRN2s_06=jVlrH2e?r|K{wvKB$H0TO*b9sTqf_{yquhucMtE*y>n}QXtH2?@6p4) z2@=K`z`8-e7@MO@(^Z*Efvj%G<52vsaE`4;H|Oc81Bc-wUg9pEVufy|%Fb)YZ#L03 z{mq@sbWBHIy`8T0(xA6?Wjzf{Cmgj_9LHa1;_`5Jkc~`2Kc@s;-?*0E3ur31u|bZo ztJ3ion@9_6yfrYfngr9FMaSV*G-!p&u79amKQW1%Tt6YyD9WPkR>%({V-t%>q~){7 z3$VzG1!vo|`6RL(_M^>Ku8qWdhTr&s&lJq;f6lL&@L}p4Xw+d;qY;X T(NJ|vhaS{X +#include +#include +#include +#include +#include +#include +#include "sqlite3.h" + +/* +** This is the is the SQL that is run against the database. +*/ +static const char *azSql[] = { + "PRAGMA integrity_check;", + "SELECT * FROM sqlite_master;", + "SELECT sum(length(name)) FROM dbstat;", + "UPDATE t1 SET b=a, a=b WHERE a Date: Sat, 27 Oct 2018 16:02:16 +0000 Subject: [PATCH 037/109] Add an entry in Makefile.in to build dbfuzz2 using clang-6.0 with -fsanitize=fuzzer,undefined. FossilOrigin-Name: a4a083ed8cdb106af661d2ee0203e21c576f5c2304419ce603826e4f2851c2e0 --- Makefile.in | 16 ++++++++++++++++ manifest | 12 ++++++------ manifest.uuid | 2 +- 3 files changed, 23 insertions(+), 7 deletions(-) diff --git a/Makefile.in b/Makefile.in index 96e2eb11f8..4e0e8dda3c 100644 --- a/Makefile.in +++ b/Makefile.in @@ -664,6 +664,22 @@ sessionfuzz$(TEXE): $(TOP)/test/sessionfuzz.c sqlite3.c sqlite3.h dbfuzz$(TEXE): $(TOP)/test/dbfuzz.c sqlite3.c sqlite3.h $(LTLINK) -o $@ $(DBFUZZ_OPT) $(TOP)/test/dbfuzz.c sqlite3.c $(TLIBS) +DBFUZZ2_OPTS = \ + -DSQLITE_THREADSAFE=0 \ + -DSQLITE_OMIT_LOAD_EXTENSION \ + -DSQLITE_ENABLE_DESERIALIZE \ + -DSQLITE_DEBUG \ + -DSQLITE_ENABLE_DBSTAT_VTAB \ + -DSQLITE_ENABLE_RTREE \ + -DSQLITE_ENABLE_FTS4 \ + -DSQLITE_EANBLE_FTS5 + +dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h + clang-6.0 -I. -g -Os -fsanitize=fuzzer,undefined -o dbfuzz2 \ + $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c + mkdir -p dbfuzz2-dir + cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir + mptester$(TEXE): sqlite3.lo $(TOP)/mptest/mptest.c $(LTLINK) -o $@ -I. $(TOP)/mptest/mptest.c sqlite3.lo \ $(TLIBS) -rpath "$(libdir)" diff --git a/manifest b/manifest index 58e0c599f7..e0f55bd758 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -C Initial\scode\sfor\sa\sfuzzing\stool\son\sdatabase\sfile\sthat\sworks\swith\sthe\n-fsanitize=fuzzer\soption\sof\sclang. -D 2018-10-27T00:47:33.850 +C Add\san\sentry\sin\sMakefile.in\sto\sbuild\sdbfuzz2\susing\sclang-6.0\swith\n-fsanitize=fuzzer,undefined. +D 2018-10-27T16:02:16.717 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea -F Makefile.in 01e95208a78b57d056131382c493c963518f36da4c42b12a97eb324401b3a334 +F Makefile.in dfd61c71a68d90ad1d0db96e94999610c44ddad6b131f8032bcac6cb9e0a45a7 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc b946f8806a5d401a299453f61de80dfd1a9df14fa4902b299e6465e3c3134872 F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 1e69f3ff057b0be27a9e79842de2485f8299799f309e89bfa7597dd688e0975b -R de82b9ab66221c495821cf10212a8a14 +P 90d12094d36957fbded71545add8a5dc206798fdacc17d4d161d715569a7f991 +R 6ad21b1e34719504a3a3472b9a8be5cf U drh -Z f0456761bef72ec9a03e18592dbe2afd +Z 0cf82952939867f49c62e617cf35a655 diff --git a/manifest.uuid b/manifest.uuid index 9af6513d41..4f9dc2f6dc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -90d12094d36957fbded71545add8a5dc206798fdacc17d4d161d715569a7f991 \ No newline at end of file +a4a083ed8cdb106af661d2ee0203e21c576f5c2304419ce603826e4f2851c2e0 \ No newline at end of file From d811d844cdc91cbe858cd95d5ceb9eac4f2748db Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 27 Oct 2018 21:06:44 +0000 Subject: [PATCH 038/109] Improvements to the dbfuzz2.c test module. FossilOrigin-Name: d60eff493b875366981c5a25000bb65cde9f6e628192914910790acc562c17b9 --- Makefile.in | 2 +- manifest | 14 +++++++------- manifest.uuid | 2 +- test/dbfuzz2.c | 52 ++++++++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 59 insertions(+), 11 deletions(-) diff --git a/Makefile.in b/Makefile.in index 4e0e8dda3c..3d44a96b31 100644 --- a/Makefile.in +++ b/Makefile.in @@ -675,7 +675,7 @@ DBFUZZ2_OPTS = \ -DSQLITE_EANBLE_FTS5 dbfuzz2: $(TOP)/test/dbfuzz2.c sqlite3.c sqlite3.h - clang-6.0 -I. -g -Os -fsanitize=fuzzer,undefined -o dbfuzz2 \ + clang-6.0 -I. -g -O0 -fsanitize=fuzzer,undefined -o dbfuzz2 \ $(DBFUZZ2_OPTS) $(TOP)/test/dbfuzz2.c sqlite3.c mkdir -p dbfuzz2-dir cp $(TOP)/test/dbfuzz2-seed* dbfuzz2-dir diff --git a/manifest b/manifest index e0f55bd758..ca47a75175 100644 --- a/manifest +++ b/manifest @@ -1,8 +1,8 @@ -C Add\san\sentry\sin\sMakefile.in\sto\sbuild\sdbfuzz2\susing\sclang-6.0\swith\n-fsanitize=fuzzer,undefined. -D 2018-10-27T16:02:16.717 +C Improvements\sto\sthe\sdbfuzz2.c\stest\smodule. +D 2018-10-27T21:06:44.652 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea -F Makefile.in dfd61c71a68d90ad1d0db96e94999610c44ddad6b131f8032bcac6cb9e0a45a7 +F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 F Makefile.msc b946f8806a5d401a299453f61de80dfd1a9df14fa4902b299e6465e3c3134872 F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee @@ -771,7 +771,7 @@ F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373 F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee -F test/dbfuzz2.c 726596ade432252e5a71d63ac1d14ebe499187091f3f32ad6302f7f1283229ff +F test/dbfuzz2.c fae8599108dbf6460f8862677a22ee517c9030cdd931df0ed3c66c09ab14e46a F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 90d12094d36957fbded71545add8a5dc206798fdacc17d4d161d715569a7f991 -R 6ad21b1e34719504a3a3472b9a8be5cf +P a4a083ed8cdb106af661d2ee0203e21c576f5c2304419ce603826e4f2851c2e0 +R e5a9cd9771ffc88fd093fdbd062e0c2a U drh -Z 0cf82952939867f49c62e617cf35a655 +Z 7b11fae1033935d453c9b6c66817005d diff --git a/manifest.uuid b/manifest.uuid index 4f9dc2f6dc..4ba4dbd6ae 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a4a083ed8cdb106af661d2ee0203e21c576f5c2304419ce603826e4f2851c2e0 \ No newline at end of file +d60eff493b875366981c5a25000bb65cde9f6e628192914910790acc562c17b9 \ No newline at end of file diff --git a/test/dbfuzz2.c b/test/dbfuzz2.c index d676c70ef7..27be2b5259 100644 --- a/test/dbfuzz2.c +++ b/test/dbfuzz2.c @@ -53,20 +53,31 @@ static const char *azSql[] = { "SELECT * FROM sqlite_master;", "SELECT sum(length(name)) FROM dbstat;", "UPDATE t1 SET b=a, a=b WHERE a=1 ){ + printf("************** nByte=%d ***************\n", (int)nByte); + fflush(stdout); + } rc = sqlite3_open(":memory:", &db); if( rc ) return 1; a = sqlite3_malloc64(nByte); @@ -76,8 +87,45 @@ int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ SQLITE_DESERIALIZE_RESIZEABLE | SQLITE_DESERIALIZE_FREEONCLOSE); for(i=0; i=1 ){ + printf("%s\n", azSql[i]); + fflush(stdout); + } sqlite3_exec(db, azSql[i], 0, 0, 0); } sqlite3_close(db); + if( sqlite3_memory_used()!=0 ){ + fprintf(stderr,"Memory leak: %lld bytes\n", sqlite3_memory_used()); + exit(1); + } + return 0; +} + +/* libFuzzer invokes this routine once when the executable starts, to +** process the command-line arguments. +*/ +int LLVMFuzzerInitialize(int *pArgc, char ***pArgv){ + int i, j; + int argc = *pArgc; + char **newArgv; + char **argv = *pArgv; + newArgv = malloc( sizeof(char*)*(argc+1) ); + if( newArgv==0 ) return 0; + newArgv[0] = argv[0]; + for(i=j=1; i Date: Mon, 29 Oct 2018 16:07:10 +0000 Subject: [PATCH 039/109] Harden the dbstat extension against corrupt database files. FossilOrigin-Name: a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/dbstat.c | 29 +++++++++++++++++++++++------ 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/manifest b/manifest index ca47a75175..aaed9b62d8 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sthe\sdbfuzz2.c\stest\smodule. -D 2018-10-27T21:06:44.652 +C Harden\sthe\sdbstat\sextension\sagainst\scorrupt\sdatabase\sfiles. +D 2018-10-29T16:07:10.322 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b @@ -454,7 +454,7 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3 -F src/dbstat.c edabb82611143727511a45ca0859b8cd037851ebe756ae3db289859dd18b6f91 +F src/dbstat.c 5f96184b8a751b7c92b959b55679f56e409c3b3bbe98eaf5e43189c16d4df082 F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2 F src/expr.c 5cee8fb79b1952689af80ed71ed16ad295f29d85de30c7592993b05cf1ec1e06 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a4a083ed8cdb106af661d2ee0203e21c576f5c2304419ce603826e4f2851c2e0 -R e5a9cd9771ffc88fd093fdbd062e0c2a +P d60eff493b875366981c5a25000bb65cde9f6e628192914910790acc562c17b9 +R 668f948a6c21a9c15cb9b96a8664b9e2 U drh -Z 7b11fae1033935d453c9b6c66817005d +Z 0ebd96da0851d12eb56b4ff281cd01aa diff --git a/manifest.uuid b/manifest.uuid index 4ba4dbd6ae..27cd6745a3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -d60eff493b875366981c5a25000bb65cde9f6e628192914910790acc562c17b9 \ No newline at end of file +a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f \ No newline at end of file diff --git a/src/dbstat.c b/src/dbstat.c index 0f1fd0a70c..0eb70d6ce8 100644 --- a/src/dbstat.c +++ b/src/dbstat.c @@ -324,22 +324,33 @@ static int statDecodePage(Btree *pBt, StatPage *p){ u8 *aHdr = &aData[p->iPgno==1 ? 100 : 0]; p->flags = aHdr[0]; + if( p->flags==0x0A || p->flags==0x0D ){ + isLeaf = 1; + nHdr = 8; + }else if( p->flags==0x05 || p->flags==0x02 ){ + isLeaf = 0; + nHdr = 12; + }else{ + goto statPageIsCorrupt; + } + if( p->iPgno==1 ) nHdr += 100; p->nCell = get2byte(&aHdr[3]); p->nMxPayload = 0; - - isLeaf = (p->flags==0x0A || p->flags==0x0D); - nHdr = 12 - isLeaf*4 + (p->iPgno==1)*100; + szPage = sqlite3BtreeGetPageSize(pBt); nUnused = get2byte(&aHdr[5]) - nHdr - 2*p->nCell; nUnused += (int)aHdr[7]; iOff = get2byte(&aHdr[1]); while( iOff ){ + int iNext; + if( iOff>=szPage ) goto statPageIsCorrupt; nUnused += get2byte(&aData[iOff+2]); - iOff = get2byte(&aData[iOff]); + iNext = get2byte(&aData[iOff]); + if( iNext0 ) goto statPageIsCorrupt; + iOff = iNext; } p->nUnused = nUnused; p->iRightChildPg = isLeaf ? 0 : sqlite3Get4byte(&aHdr[8]); - szPage = sqlite3BtreeGetPageSize(pBt); if( p->nCell ){ int i; /* Used to iterate through cells */ @@ -356,6 +367,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ StatCell *pCell = &p->aCell[i]; iOff = get2byte(&aData[nHdr+i*2]); + if( iOff=szPage ) goto statPageIsCorrupt; if( !isLeaf ){ pCell->iChildPg = sqlite3Get4byte(&aData[iOff]); iOff += 4; @@ -372,8 +384,8 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } if( nPayload>(u32)p->nMxPayload ) p->nMxPayload = nPayload; getLocalPayload(nUsable, p->flags, nPayload, &nLocal); + if( nLocal<0 ) goto statPageIsCorrupt; pCell->nLocal = nLocal; - assert( nLocal>=0 ); assert( nPayload>=(u32)nLocal ); assert( nLocal<=(nUsable-35) ); if( nPayload>(u32)nLocal ){ @@ -402,6 +414,11 @@ static int statDecodePage(Btree *pBt, StatPage *p){ } return SQLITE_OK; + +statPageIsCorrupt: + p->flags = 0; + p->nCell = 0; + return SQLITE_OK; } /* From dbe7d37ae8e69a1e5252dca2c83badb471ff1310 Mon Sep 17 00:00:00 2001 From: dan Date: Mon, 29 Oct 2018 17:08:27 +0000 Subject: [PATCH 040/109] In the sessions module, avoid collecting rebase data if the user has not requested it. FossilOrigin-Name: de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f --- ext/session/sqlite3session.c | 62 +++++++++++++++++++----------------- manifest | 14 ++++---- manifest.uuid | 2 +- 3 files changed, 41 insertions(+), 37 deletions(-) diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 108b74ca2a..465af8d6e1 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -3443,7 +3443,8 @@ struct SessionApplyCtx { int bDeferConstraints; /* True to defer constraints */ SessionBuffer constraints; /* Deferred constraints are stored here */ SessionBuffer rebase; /* Rebase information (if any) here */ - int bRebaseStarted; /* If table header is already in rebase */ + u8 bRebaseStarted; /* If table header is already in rebase */ + u8 bRebase; /* True to collect rebase information */ }; /* @@ -3840,35 +3841,36 @@ static int sessionRebaseAdd( sqlite3_changeset_iter *pIter /* Iterator pointing at current change */ ){ int rc = SQLITE_OK; - int i; - int eOp = pIter->op; - if( p->bRebaseStarted==0 ){ - /* Append a table-header to the rebase buffer */ - const char *zTab = pIter->zTab; - sessionAppendByte(&p->rebase, 'T', &rc); - sessionAppendVarint(&p->rebase, p->nCol, &rc); - sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); - sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); - p->bRebaseStarted = 1; - } - - assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); - assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); - - sessionAppendByte(&p->rebase, - (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc - ); - sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); - for(i=0; inCol; i++){ - sqlite3_value *pVal = 0; - if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ - sqlite3changeset_old(pIter, i, &pVal); - }else{ - sqlite3changeset_new(pIter, i, &pVal); + if( p->bRebase ){ + int i; + int eOp = pIter->op; + if( p->bRebaseStarted==0 ){ + /* Append a table-header to the rebase buffer */ + const char *zTab = pIter->zTab; + sessionAppendByte(&p->rebase, 'T', &rc); + sessionAppendVarint(&p->rebase, p->nCol, &rc); + sessionAppendBlob(&p->rebase, p->abPK, p->nCol, &rc); + sessionAppendBlob(&p->rebase, (u8*)zTab, (int)strlen(zTab)+1, &rc); + p->bRebaseStarted = 1; } - sessionAppendValue(&p->rebase, pVal, &rc); - } + assert( eType==SQLITE_CHANGESET_REPLACE||eType==SQLITE_CHANGESET_OMIT ); + assert( eOp==SQLITE_DELETE || eOp==SQLITE_INSERT || eOp==SQLITE_UPDATE ); + + sessionAppendByte(&p->rebase, + (eOp==SQLITE_DELETE ? SQLITE_DELETE : SQLITE_INSERT), &rc + ); + sessionAppendByte(&p->rebase, (eType==SQLITE_CHANGESET_REPLACE), &rc); + for(i=0; inCol; i++){ + sqlite3_value *pVal = 0; + if( eOp==SQLITE_DELETE || (eOp==SQLITE_UPDATE && p->abPK[i]) ){ + sqlite3changeset_old(pIter, i, &pVal); + }else{ + sqlite3changeset_new(pIter, i, &pVal); + } + sessionAppendValue(&p->rebase, pVal, &rc); + } + } return rc; } @@ -4277,6 +4279,7 @@ static int sessionChangesetApply( pIter->in.bNoDiscard = 1; memset(&sApply, 0, sizeof(sApply)); + sApply.bRebase = (ppRebase && pnRebase); sqlite3_mutex_enter(sqlite3_db_mutex(db)); if( (flags & SQLITE_CHANGESETAPPLY_NOSAVEPOINT)==0 ){ rc = sqlite3_exec(db, "SAVEPOINT changeset_apply", 0, 0, 0); @@ -4427,7 +4430,8 @@ static int sessionChangesetApply( } } - if( rc==SQLITE_OK && bPatchset==0 && ppRebase && pnRebase ){ + assert( sApply.bRebase || sApply.rebase.nBuf==0 ); + if( rc==SQLITE_OK && bPatchset==0 && sApply.bRebase ){ *ppRebase = (void*)sApply.rebase.aBuf; *pnRebase = sApply.rebase.nBuf; sApply.rebase.aBuf = 0; diff --git a/manifest b/manifest index aaed9b62d8..e51359b125 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Harden\sthe\sdbstat\sextension\sagainst\scorrupt\sdatabase\sfiles. -D 2018-10-29T16:07:10.322 +C In\sthe\ssessions\smodule,\savoid\scollecting\srebase\sdata\sif\sthe\suser\shas\snot\nrequested\sit. +D 2018-10-29T17:08:27.831 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b @@ -417,7 +417,7 @@ F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b295 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c 0119dac126fb2b4ca6bed53509071d87a7977f3e97a2f8b8fa13c6e57beb6f76 +F ext/session/sqlite3session.c 8772d3cb9124a14f85c7c9ca2bc4931f1180ee99acf5386bdfdd6892455b2443 F ext/session/sqlite3session.h 05351d2f50a1203fdffbeb590fdbbc796c9a6bfcd0c9b26cf6db3854e3eb4294 F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P d60eff493b875366981c5a25000bb65cde9f6e628192914910790acc562c17b9 -R 668f948a6c21a9c15cb9b96a8664b9e2 -U drh -Z 0ebd96da0851d12eb56b4ff281cd01aa +P a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f +R e9d59384eb4e31957429edb55e9fdfcd +U dan +Z e1a47567ef9afc1d6422d6b424bf5b3a diff --git a/manifest.uuid b/manifest.uuid index 27cd6745a3..171c1f3dc2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f \ No newline at end of file +de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f \ No newline at end of file From 8bee11a41ef9a90f8c9046db725dcf962700127c Mon Sep 17 00:00:00 2001 From: mistachkin Date: Mon, 29 Oct 2018 17:53:23 +0000 Subject: [PATCH 041/109] Add the sqlite3_normalized_sql() API. FossilOrigin-Name: 592b66e8058dd03a056a036e2606247c9efdb06d15eebe9bcc455f7f55e30ae6 --- Makefile.in | 40 +++--- Makefile.msc | 4 + main.mk | 34 +++--- manifest | 55 +++++---- manifest.uuid | 2 +- src/build.c | 6 + src/callback.c | 19 ++- src/ctime.c | 3 + src/expr.c | 8 ++ src/hash.c | 56 +++++++++ src/loadext.c | 8 +- src/prepare.c | 288 +++++++++++++++++++++++++++++++++++++++++++ src/sqlite.h.in | 21 +++- src/sqlite3ext.h | 5 + src/sqliteInt.h | 23 ++++ src/test1.c | 100 ++++++++++++++- src/test_config.c | 6 + src/tokenize.c | 67 ++++++++++ src/vdbeInt.h | 3 + src/vdbeapi.c | 10 ++ src/vdbeaux.c | 15 +++ test/normalize.test | 289 ++++++++++++++++++++++++++++++++++++++++++++ 22 files changed, 996 insertions(+), 66 deletions(-) diff --git a/Makefile.in b/Makefile.in index 3d44a96b31..2cd8471bb5 100644 --- a/Makefile.in +++ b/Makefile.in @@ -22,7 +22,7 @@ TOP = @abs_srcdir@ # BCC = @BUILD_CC@ @BUILD_CFLAGS@ -# TCC is the C Compile and options for use in building executables that +# TCC is the C Compile and options for use in building executables that # will run on the target platform. (BCC and TCC are usually the # same unless your are cross-compiling.) Separate CC and CFLAGS macros # are provide so that these aspects of the build process can be changed @@ -35,7 +35,7 @@ TCC += -I${TOP}/ext/fts3 -I${TOP}/ext/async -I${TOP}/ext/session # Define this for the autoconf-based build, so that the code knows it can # include the generated config.h -# +# TCC += -D_HAVE_SQLITE_CONFIG_H -DBUILD_sqlite # Define -DNDEBUG to compile without debugging (i.e., for production usage) @@ -66,7 +66,7 @@ LIBREADLINE = @TARGET_READLINE_LIBS@ TCC += -DSQLITE_THREADSAFE=@SQLITE_THREADSAFE@ # Any target libraries which libsqlite must be linked against -# +# TLIBS = @LIBS@ $(LIBS) # Flags controlling use of the in memory btree implementation @@ -78,8 +78,8 @@ TLIBS = @LIBS@ $(LIBS) TEMP_STORE = -DSQLITE_TEMP_STORE=@TEMP_STORE@ # Enable/disable loadable extensions, and other optional features -# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). -# The same set of OMIT and ENABLE flags should be passed to the +# based on configuration. (-DSQLITE_OMIT*, -DSQLITE_ENABLE*). +# The same set of OMIT and ENABLE flags should be passed to the # LEMON parser generator and the mkkeywordhash tool as well. OPT_FEATURE_FLAGS = @OPT_FEATURE_FLAGS@ @@ -126,8 +126,8 @@ SHLIB_SUFFIX = @TCL_SHLIB_SUFFIX@ # If gcov support was enabled by the configure script, add the appropriate # flags here. It's not always as easy as just having the user add the right # CFLAGS / LDFLAGS, because libtool wants to use CFLAGS when linking, which -# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs. -# Supposedly GCC does the right thing if you use --coverage, but in +# causes build errors with -fprofile-arcs -ftest-coverage with some GCCs. +# Supposedly GCC does the right thing if you use --coverage, but in # practice it still fails. See: # # http://www.mail-archive.com/debian-gcc@lists.debian.org/msg26197.html @@ -425,7 +425,7 @@ TESTSRC = \ $(TOP)/ext/fts3/fts3_term.c \ $(TOP)/ext/fts3/fts3_test.c \ $(TOP)/ext/session/test_session.c \ - $(TOP)/ext/rbu/test_rbu.c + $(TOP)/ext/rbu/test_rbu.c # Statically linked extensions # @@ -507,7 +507,7 @@ TESTSRC2 = \ $(TOP)/ext/fts3/fts3_write.c \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/session/sqlite3session.c \ - $(TOP)/ext/misc/stmt.c + $(TOP)/ext/misc/stmt.c # Header files used by all library source files. # @@ -602,7 +602,7 @@ FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ FUZZCHECK_OPT += -DSQLITE_MAX_MEMORY=50000000 FUZZCHECK_OPT += -DSQLITE_PRINTF_PRECISION_LIMIT=1000 FUZZCHECK_SRC = $(TOP)/test/fuzzcheck.c $(TOP)/test/ossfuzz.c -DBFUZZ_OPT = +DBFUZZ_OPT = # This is the default Makefile target. The objects listed here # are what get build when you type just "make" with no arguments. @@ -1143,7 +1143,7 @@ FTS5_SRC = \ $(TOP)/ext/fts5/fts5_varint.c \ $(TOP)/ext/fts5/fts5_vocab.c \ -fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon +fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon$(BEXE) $(OPTS) fts5parse.y @@ -1170,7 +1170,7 @@ sqlite3rbu.lo: $(TOP)/ext/rbu/sqlite3rbu.c $(HDR) $(EXTHDR) # TESTFIXTURE_FLAGS = -DSQLITE_TEST=1 -DSQLITE_CRASH_TEST=1 TESTFIXTURE_FLAGS += -DTCLSH_INIT_PROC=sqlite3TestInit -TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE +TESTFIXTURE_FLAGS += -DSQLITE_SERVER=1 -DSQLITE_PRIVATE="" -DSQLITE_CORE TESTFIXTURE_FLAGS += -DBUILD_sqlite TESTFIXTURE_FLAGS += -DSQLITE_SERIES_CONSTRAINT_VERIFY=1 TESTFIXTURE_FLAGS += -DSQLITE_DEFAULT_PAGE_SIZE=1024 @@ -1186,6 +1186,10 @@ testfixture$(TEXE): $(TESTFIXTURE_SRC) $(LTLINK) -DSQLITE_NO_SYNC=1 $(TEMP_STORE) $(TESTFIXTURE_FLAGS) \ -o $@ $(TESTFIXTURE_SRC) $(LIBTCL) $(TLIBS) +coretestprogs: $(TESTPROGS) + +testprogs: coretestprogs srcck1$(BEXE) fuzzcheck$(TEXE) sessionfuzz$(TEXE) + # A very detailed test running most or all test cases fulltest: $(TESTPROGS) fuzztest ./testfixture$(TEXE) $(TOP)/test/all.test $(TESTOPTS) @@ -1245,7 +1249,7 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $ sqlite3_analyzer$(TEXE): sqlite3_analyzer.c $(LTLINK) sqlite3_analyzer.c -o $@ $(LIBTCL) $(TLIBS) -sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in +sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in $(TCLSH_CMD) $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c sqltclsh$(TEXE): sqltclsh.c @@ -1312,7 +1316,7 @@ KV_OPT += -DSQLITE_DIRECT_OVERFLOW_READ kvtest$(TEXE): $(TOP)/test/kvtest.c sqlite3.c $(LTLINK) $(KV_OPT) -o $@ $(TOP)/test/kvtest.c sqlite3.c $(TLIBS) -rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo +rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.lo $(LTLINK) -I. -o $@ $(TOP)/ext/rbu/rbu.c sqlite3.lo $(TLIBS) loadfts$(EXE): $(TOP)/tool/loadfts.c libsqlite3.la @@ -1340,7 +1344,7 @@ snapshot-tarball: sqlite3.c # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. -# +# THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ $(TOP)/test/tt3_checkpoint.c \ $(TOP)/test/tt3_index.c \ @@ -1354,7 +1358,7 @@ threadtest3$(TEXE): sqlite3.lo $(THREADTEST3_SRC) threadtest: threadtest3$(TEXE) ./threadtest3$(TEXE) -releasetest: +releasetest: $(TCLSH_CMD) $(TOP)/test/releasetest.tcl # Standard install and cleanup targets @@ -1362,7 +1366,7 @@ releasetest: lib_install: libsqlite3.la $(INSTALL) -d $(DESTDIR)$(libdir) $(LTINSTALL) libsqlite3.la $(DESTDIR)$(libdir) - + install: sqlite3$(TEXE) lib_install sqlite3.h sqlite3.pc ${HAVE_TCL:1=tcl_install} $(INSTALL) -d $(DESTDIR)$(bindir) $(LTINSTALL) sqlite3$(TEXE) $(DESTDIR)$(bindir) @@ -1380,7 +1384,7 @@ tcl_install: lib_install libtclsqlite3.la pkgIndex.tcl rm -f $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.la $(DESTDIR)$(TCLLIBDIR)/libtclsqlite3.a $(INSTALL) -m 0644 pkgIndex.tcl $(DESTDIR)$(TCLLIBDIR) -clean: +clean: rm -f *.lo *.la *.o sqlite3$(TEXE) libsqlite3.la rm -f sqlite3.h opcodes.* rm -rf .libs .deps diff --git a/Makefile.msc b/Makefile.msc index b9fab7c408..2f09f0008d 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -2335,6 +2335,10 @@ extensiontest: testfixture.exe testloadext.dll @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\loadext.test $(TESTOPTS) +coretestprogs: $(TESTPROGS) + +testprogs: coretestprogs srcck1.exe fuzzcheck.exe sessionfuzz.exe + fulltest: $(TESTPROGS) fuzztest @set PATH=$(LIBTCLPATH);$(PATH) .\testfixture.exe $(TOP)\test\all.test $(TESTOPTS) diff --git a/main.mk b/main.mk index 1df68076c1..e799896ebc 100644 --- a/main.mk +++ b/main.mk @@ -19,7 +19,7 @@ # EXE The suffix to add to executable files. ".exe" for windows # and "" for Unix. # -# TCC C Compiler and options for use in building executables that +# TCC C Compiler and options for use in building executables that # will run on the target platform. This is usually the same # as BCC, unless you are cross-compiling. # @@ -43,7 +43,7 @@ # This is how we compile # -TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) +TCCX = $(TCC) $(OPTS) -I. -I$(TOP)/src -I$(TOP) TCCX += -I$(TOP)/ext/rtree -I$(TOP)/ext/icu -I$(TOP)/ext/fts3 TCCX += -I$(TOP)/ext/async -I$(TOP)/ext/userauth TCCX += -I$(TOP)/ext/session @@ -236,7 +236,7 @@ SRC += \ $(TOP)/ext/session/sqlite3session.h SRC += \ $(TOP)/ext/userauth/userauth.c \ - $(TOP)/ext/userauth/sqlite3userauth.h + $(TOP)/ext/userauth/sqlite3userauth.h SRC += \ $(TOP)/ext/rbu/sqlite3rbu.c \ $(TOP)/ext/rbu/sqlite3rbu.h @@ -251,7 +251,7 @@ FTS5_HDR = \ $(TOP)/ext/fts5/fts5.h \ $(TOP)/ext/fts5/fts5Int.h \ fts5parse.h - + FTS5_SRC = \ $(TOP)/ext/fts5/fts5_aux.c \ $(TOP)/ext/fts5/fts5_buffer.c \ @@ -431,7 +431,7 @@ TESTSRC2 = \ $(TOP)/ext/async/sqlite3async.c \ $(TOP)/ext/misc/stmt.c \ $(TOP)/ext/session/sqlite3session.c \ - $(TOP)/ext/session/test_session.c + $(TOP)/ext/session/test_session.c # Header files used by all library source files. # @@ -484,7 +484,7 @@ EXTHDR += \ EXTHDR += \ $(TOP)/ext/fts5/fts5Int.h \ fts5parse.h \ - $(TOP)/ext/fts5/fts5.h + $(TOP)/ext/fts5/fts5.h EXTHDR += \ $(TOP)/ext/userauth/sqlite3userauth.h @@ -800,7 +800,7 @@ rtree.o: $(TOP)/ext/rtree/rtree.c $(HDR) $(EXTHDR) -fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon +fts5parse.c: $(TOP)/ext/fts5/fts5parse.y lemon cp $(TOP)/ext/fts5/fts5parse.y . rm -f fts5parse.h ./lemon $(OPTS) fts5parse.y @@ -834,13 +834,13 @@ sqlite3_analyzer.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/spaceanal.tcl $ tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqlite3_analyzer.c.in >sqlite3_analyzer.c sqlite3_analyzer$(EXE): sqlite3_analyzer.c - $(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB) + $(TCCX) $(TCL_FLAGS) sqlite3_analyzer.c -o $@ $(LIBTCL) $(THREADLIB) sqltclsh.c: sqlite3.c $(TOP)/src/tclsqlite.c $(TOP)/tool/sqltclsh.tcl $(TOP)/ext/misc/appendvfs.c $(TOP)/tool/mkccode.tcl tclsh $(TOP)/tool/mkccode.tcl $(TOP)/tool/sqltclsh.c.in >sqltclsh.c sqltclsh$(EXE): sqltclsh.c - $(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB) + $(TCCX) $(TCL_FLAGS) sqltclsh.c -o $@ $(LIBTCL) $(THREADLIB) sqlite3_expert$(EXE): $(TOP)/ext/expert/sqlite3expert.h $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c $(TCCX) -DSQLITE_THREADSAFE=0 -DSQLITE_OMIT_LOAD_EXTENSION $(TOP)/ext/expert/sqlite3expert.c $(TOP)/ext/expert/expert.c sqlite3.c -o sqlite3_expert$(EXE) $(THREADLIB) @@ -893,6 +893,10 @@ fts3-testfixture$(EXE): sqlite3.c fts3amal.c $(TESTSRC) $(TOP)/src/tclsqlite.c $(TESTSRC) $(TOP)/src/tclsqlite.c sqlite3.c fts3amal.c \ -o testfixture$(EXE) $(LIBTCL) $(THREADLIB) +coretestprogs: $(TESTPROGS) + +testprogs: coretestprogs srcck1$(EXE) fuzzcheck$(EXE) sessionfuzz$(EXE) + fulltest: $(TESTPROGS) fuzztest ./testfixture$(EXE) $(TOP)/test/all.test $(TESTOPTS) @@ -949,7 +953,7 @@ smoketest: $(TESTPROGS) fuzzcheck$(EXE) # The next two rules are used to support the "threadtest" target. Building # threadtest runs a few thread-safety tests that are implemented in C. This # target is invoked by the releasetest.tcl script. -# +# THREADTEST3_SRC = $(TOP)/test/threadtest3.c \ $(TOP)/test/tt3_checkpoint.c \ $(TOP)/test/tt3_index.c \ @@ -1013,12 +1017,12 @@ wordcount$(EXE): $(TOP)/test/wordcount.c sqlite3.c $(TOP)/test/wordcount.c sqlite3.c speedtest1$(EXE): $(TOP)/test/speedtest1.c sqlite3.c - $(TCCX) -I. $(ST_OPT) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.c $(THREADLIB) + $(TCCX) -I. $(ST_OPT) -o speedtest1$(EXE) $(TOP)/test/speedtest1.c sqlite3.c $(THREADLIB) kvtest$(EXE): $(TOP)/test/kvtest.c sqlite3.c - $(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB) + $(TCCX) -I. $(KV_OPT) -o kvtest$(EXE) $(TOP)/test/kvtest.c sqlite3.c $(THREADLIB) -rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o +rbu$(EXE): $(TOP)/ext/rbu/rbu.c $(TOP)/ext/rbu/sqlite3rbu.c sqlite3.o $(TCC) -I. -o rbu$(EXE) $(TOP)/ext/rbu/rbu.c sqlite3.o \ $(THREADLIB) @@ -1050,7 +1054,7 @@ install: sqlite3 libsqlite3.a sqlite3.h mv libsqlite3.a /usr/lib mv sqlite3.h /usr/include -clean: +clean: rm -f *.o sqlite3 sqlite3.exe libsqlite3.a sqlite3.h opcodes.* rm -f lemon lemon.exe lempar.c parse.* sqlite*.tar.gz rm -f mkkeywordhash mkkeywordhash.exe keywordhash.h @@ -1078,7 +1082,7 @@ clean: rm -f sqlite3rc.h rm -f shell.c sqlite3ext.h rm -f sqlite3_analyzer sqlite3_analyzer.exe sqlite3_analyzer.c - rm -f sqlite3_expert sqlite3_expert.exe + rm -f sqlite3_expert sqlite3_expert.exe rm -f sqlite-*-output.vsix rm -f mptester mptester.exe rm -f fuzzershell fuzzershell.exe diff --git a/manifest b/manifest index e51359b125..4cd0556450 100644 --- a/manifest +++ b/manifest @@ -1,10 +1,10 @@ -C In\sthe\ssessions\smodule,\savoid\scollecting\srebase\sdata\sif\sthe\suser\shas\snot\nrequested\sit. -D 2018-10-29T17:08:27.831 +C Add\sthe\ssqlite3_normalized_sql()\sAPI. +D 2018-10-29T17:53:23.938 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea -F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b +F Makefile.in 783093f97550d2fd61618ca76ada6fbbfc6ec26c242a66e8c25a4d9d54cde899 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 -F Makefile.msc b946f8806a5d401a299453f61de80dfd1a9df14fa4902b299e6465e3c3134872 +F Makefile.msc fd51f9eba2cc0da0c26344b7f08addc16a2094640bb60e481dcd6408b901a293 F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee F VERSION 654da1d4053fb09ffc33a3910e6d427182a7dcdc67e934fa83de2849ac83fccb F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -426,7 +426,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk ff82d38126f8f0668b7990e0f1f3dcd74fa2d477c19b2e3feaaba586051e9b48 +F main.mk ab2257d67e9db1fa9ef6159fadc32ef59ab24b9734cd567622d795392c3b2d83 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -448,26 +448,26 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173 F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2 F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96 -F src/build.c 0b3d422770877d74ee6d54f4c122d82c48f7d04ee3bfb91702e402de7f5c45ac -F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288 +F src/build.c 675799caa8bdd73bea8f8c268a735cb208133ce875bf5c4cbcf7280bebfb2227 +F src/callback.c 789bd33d188146f66c0dd8306472a72d1c05f71924b24a91caf6bd45cf9aba73 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e -F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950 +F src/ctime.c 109e58d00f62e8e71ee1eb5944ac18b90171c928ab2e082e058056e1137cc20b F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3 F src/dbstat.c 5f96184b8a751b7c92b959b55679f56e409c3b3bbe98eaf5e43189c16d4df082 F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2 -F src/expr.c 5cee8fb79b1952689af80ed71ed16ad295f29d85de30c7592993b05cf1ec1e06 +F src/expr.c 16dee9504d0c6a09de8aa188fb0989ec3fd48b9704abd4fc80539065f2b52adc F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 F src/fkey.c 972a4ba14296bef2303a0abbad1e3d82bc3c61f9e6ce4e8e9528bdee68748812 F src/func.c 7c288b4ce309b5a8b8473514b88e1f8e69a80134509a8c0db8e39c858e367e7f F src/global.c 9bf034fd560bdd514715170ed8460bb7f823cec113f0569ef3f18a20c7ccd128 -F src/hash.c a12580e143f10301ed5166ea4964ae2853d3905a511d4e0c44497245c7ce1f7a +F src/hash.c 931ec82d7e070654a8facb42549bbb3a25720171d73ba94c3d3160580d01ef1f F src/hash.h ab34c5c54a9e9de2e790b24349ba5aab3dbb4fd4 F src/hwtime.h 747c1bbe9df21a92e9c50f3bbec1de841dc5e5da F src/in-operator.md 10cd8f4bcd225a32518407c2fb2484089112fd71 F src/insert.c 0a214201afec77880a31a59c33d86b473a160fc5cc31981eab2041ae03d8bf2f F src/legacy.c 134ab3e3fae00a0f67a5187981d6935b24b337bcf0f4b3e5c9fa5763da95bf4e -F src/loadext.c 30b140d0e5031924c56f802760506c0a235ced0dff9f3d95119aa86df12856e2 +F src/loadext.c 448eab53ecdb566a1259ee2d45ebff9c0bc4a2cf393774488775c33e4fbe89bf F src/main.c 6275ece0699a957c4709a7ebe29476f132adbe459d18a6b497e234e4669abf91 F src/malloc.c 07295435093ce354c6d9063ac05a2eeae28bd251d2e63c48b3d67c12c76f7e18 F src/mem0.c 6a55ebe57c46ca1a7d98da93aaa07f99f1059645 @@ -499,22 +499,22 @@ F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 F src/pragma.c 35efa85894f1ae533c03c64591dfc82f916ad78250591082bbae72a2811bceab F src/pragma.h e50df79399da8c2efc6bd4b7034e242d0dc6ab2016564f08e94103367098b1e4 -F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 +F src/prepare.c bf148a889ed92589dd2e6b99b54107e8c7668ad2f69a41bb55b4bbc701fc6474 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d -F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec +F src/sqlite.h.in 4f95d6f484ce247fa7cbb7382641d40919cfe9c3bf8091bc462638c7bac4efea F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 -F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 -F src/sqliteInt.h 75d8266b27c287aeada717a541cf7b7543383fccdb1d7d45a5620f666e864c55 +F src/sqlite3ext.h 960f1b86c3610fa23cb6a267572a97dcf286e77aa0dd3b9b23292ffaa1ea8683 +F src/sqliteInt.h be74ca8df8831848718a9ddcd71af265807ca77ef25f1d3416a7b4378c4372fb F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 F src/tclsqlite.c e72862a271348d779672b45a730c33fd0c535e630ff927e8ce4a0c908d1d28c6 -F src/test1.c 9bb042e4afedc570f78638993fc9cc1760d897d3b27dd72c20618044b2a8fa5e +F src/test1.c e89148fdb0b3aa92af609669078c219d7b26bf442418b547f0db79d82a7d82f9 F src/test2.c 3efb99ab7f1fc8d154933e02ae1378bac9637da5 F src/test3.c 61798bb0d38b915067a8c8e03f5a534b431181f802659a6616f9b4ff7d872644 F src/test4.c 18ec393bb4d0ad1de729f0b94da7267270f3d8e6 @@ -529,7 +529,7 @@ F src/test_backup.c bf5da90c9926df0a4b941f2d92825a01bbe090a0 F src/test_bestindex.c 78809f11026f18a93fcfd798d9479cba37e1201c830260bf1edc674b2fa9b857 F src/test_blob.c ae4a0620b478548afb67963095a7417cd06a4ec0a56adb453542203bfdcb31ce F src/test_btree.c 8b2dc8b8848cf3a4db93f11578f075e82252a274 -F src/test_config.c 3bbc5e593f308cbff426bb88c9dbf75deab551e5ddcece1251b8d9a40e55aef5 +F src/test_config.c 5ebafbcd5c75ac1c16bb0c8fe926dc325cc03e780943a88ca50e0d9a4fc4d2f5 F src/test_delete.c e2fe07646dff6300b48d49b2fee2fe192ed389e834dd635e3b3bac0ce0bf9f8f F src/test_demovfs.c a0c3bdd45ed044115c2c9f7779e56eafff18741e F src/test_devsym.c 1960abbb234b97e9b920f07e99503fc04b443f62bbc3c6ff2c2cea2133e3b8a2 @@ -567,7 +567,7 @@ F src/test_windirent.h 90dfbe95442c9762357fe128dc7ae3dc199d006de93eb33ba3972e0a9 F src/test_window.c cdae419fdcea5bad6dcd9368c685abdad6deb59e9fc8b84b153de513d394ba3f F src/test_wsd.c 41cadfd9d97fe8e3e4e44f61a4a8ccd6f7ca8fe9 F src/threads.c 4ae07fa022a3dc7c5beb373cf744a85d3c5c6c3c -F src/tokenize.c 9f55961518f77793edd56eee860ecf035d4370ebbb0726ad2f6cada6637fd16b +F src/tokenize.c 9e781e1ca80eefe7b5d6a9e2cd5c678c847da55fd6f093781fad7950934d4c83 F src/treeview.c 0ef7dc77d6fe03172ba65dddfd3b3c557b7b7e217ca1963b7665beb266a0e2c0 F src/trigger.c d3d78568f37fb2e6cdcc2d1e7b60156f15b0b600adec55b83c5d42f6cad250bd F src/update.c 1816d56c1bca1ba4e0ef98cac2f49be62858e9df1dc08844c7067eb41cc44274 @@ -577,9 +577,9 @@ F src/util.c d9eb0a6c4aae1b00a7369eadd7ca0bbe946cb4c953b6751aa20d357c2f482157 F src/vacuum.c 36e7d21a20c0bf6ef4ef7c399d192b5239410b7c4d3c1070fba4e30810d0b855 F src/vdbe.c 005e691ea4c7d51e6c1a69d9389aeb34700884c85f51681817ddea3fdc2fc39b F src/vdbe.h 5081dcc497777efe5e9ebe7330d283a044a005e4bdda2e2e984f03bf89a0d907 -F src/vdbeInt.h f1f35f70460698d8f5a2bdef1001114babf318e2983a067804e2ae077d8e9827 -F src/vdbeapi.c 2ba821c5929a2769e4b217dd85843479c718b8989d414723ec8af0616a83d611 -F src/vdbeaux.c 9fe7760a6b9739f21f3e19ad5364330b0f681998fc52c32358243b0060423474 +F src/vdbeInt.h 8a52b8db3d20f9755a965d864b8653052c7ef1ccadceb2e057047cd421f6336e +F src/vdbeapi.c ecccfce6f614c33a95952efeec969d163e8349eac314ee2b7b163eda921b5eb0 +F src/vdbeaux.c f547901b1aa9e2d81c63f06893f633648e434180666a827aacb547d7d6c8a601 F src/vdbeblob.c f5c70f973ea3a9e915d1693278a5f890dc78594300cf4d54e64f2b0917c94191 F src/vdbemem.c 81329ab760e4ec0162119d9cd10193e0303c45c5935bb20c7ae9139d44dd6641 F src/vdbesort.c 90aad5a92608f2dd771c96749beabdb562c9d881131a860a7a5bccf66dc3be7f @@ -1135,7 +1135,7 @@ F test/mutex2.test bfeaeac2e73095b2ac32285d2756e3a65e681660 F test/nan.test 437d40e6d0778b050d7750726c0cbd2c9936b81962926e8f8c48ca698f00f4d1 F test/nockpt.test 8c43b25af63b0bd620cf1b003529e37b6f1dc53bd22690e96a1bd73f78dde53a F test/nolock.test f196cf8b8fbea4e2ca345140a2b3f3b0da45c76e -F test/normalize.test 1dedf653ca33b0b55fd0c7967d2861a51f1801a7aa899a02d4c0d7adfcd5acdc +F test/normalize.test 6a80564d2000702b5919ed2c1069fef0f95762142bc96a71b4c124a845165713 F test/notify1.test 669b2b743618efdc18ca4b02f45423d5d2304abf F test/notify2.test 2ecabaa1305083856b7c39cf32816b612740c161 F test/notify3.test 10ff25cde502e72a92053a2f215d64bece4ef934 @@ -1774,7 +1774,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f -R e9d59384eb4e31957429edb55e9fdfcd -U dan -Z e1a47567ef9afc1d6422d6b424bf5b3a +P de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f +R 3a0379f1d958d505b0867531ec02f91e +T *branch * normalized_sql +T *sym-normalized_sql * +T -sym-trunk * +U mistachkin +Z aed093f5ed17f4e7a3a3d3f732fe7b71 diff --git a/manifest.uuid b/manifest.uuid index 171c1f3dc2..df07ff9960 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f \ No newline at end of file +592b66e8058dd03a056a036e2606247c9efdb06d15eebe9bcc455f7f55e30ae6 \ No newline at end of file diff --git a/src/build.c b/src/build.c index b4041389ba..5a5bea50fc 100644 --- a/src/build.c +++ b/src/build.c @@ -633,6 +633,12 @@ static void SQLITE_NOINLINE deleteTable(sqlite3 *db, Table *pTable){ /* Delete the Table structure itself. */ +#ifdef SQLITE_ENABLE_NORMALIZE + if( pTable->pColHash ){ + sqlite3HashClear(pTable->pColHash); + sqlite3_free(pTable->pColHash); + } +#endif sqlite3DeleteColumnNames(db, pTable); sqlite3DbFree(db, pTable->zName); sqlite3DbFree(db, pTable->zColAff); diff --git a/src/callback.c b/src/callback.c index a629b6825e..faf6d520c4 100644 --- a/src/callback.c +++ b/src/callback.c @@ -295,6 +295,21 @@ static FuncDef *functionSearch( } return 0; } +#ifdef SQLITE_ENABLE_NORMALIZE +FuncDef *sqlite3FunctionSearchN( + int h, /* Hash of the name */ + const char *zFunc, /* Name of function */ + int nFunc /* Length of the name */ +){ + FuncDef *p; + for(p=sqlite3BuiltinFunctions.a[h]; p; p=p->u.pHash){ + if( sqlite3StrNICmp(p->zName, zFunc, nFunc)==0 ){ + return p; + } + } + return 0; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* ** Insert a new FuncDef into a FuncDefHash hash table. @@ -308,7 +323,7 @@ void sqlite3InsertBuiltinFuncs( FuncDef *pOther; const char *zName = aDef[i].zName; int nName = sqlite3Strlen30(zName); - int h = (zName[0] + nName) % SQLITE_FUNC_HASH_SZ; + int h = SQLITE_FUNC_HASH(zName[0], nName); assert( zName[0]>='a' && zName[0]<='z' ); pOther = functionSearch(h, zName); if( pOther ){ @@ -387,7 +402,7 @@ FuncDef *sqlite3FindFunction( */ if( !createFlag && (pBest==0 || (db->mDbFlags & DBFLAG_PreferBuiltin)!=0) ){ bestScore = 0; - h = (sqlite3UpperToLower[(u8)zName[0]] + nName) % SQLITE_FUNC_HASH_SZ; + h = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zName[0]], nName); p = functionSearch(h, zName); while( p ){ int score = matchQuality(p, nArg, enc); diff --git a/src/ctime.c b/src/ctime.c index 5bc1e5c74f..27fc4fe6c2 100644 --- a/src/ctime.c +++ b/src/ctime.c @@ -268,6 +268,9 @@ static const char * const sqlite3azCompileOpt[] = { #if SQLITE_ENABLE_MULTIPLEX "ENABLE_MULTIPLEX", #endif +#if SQLITE_ENABLE_NORMALIZE + "ENABLE_NORMALIZE", +#endif #if SQLITE_ENABLE_NULL_TRIM "ENABLE_NULL_TRIM", #endif diff --git a/src/expr.c b/src/expr.c index b2854f9a5d..9c0ce1f87d 100644 --- a/src/expr.c +++ b/src/expr.c @@ -2149,6 +2149,14 @@ int sqlite3IsRowid(const char *z){ if( sqlite3StrICmp(z, "OID")==0 ) return 1; return 0; } +#ifdef SQLITE_ENABLE_NORMALIZE +int sqlite3IsRowidN(const char *z, int n){ + if( sqlite3StrNICmp(z, "_ROWID_", n)==0 ) return 1; + if( sqlite3StrNICmp(z, "ROWID", n)==0 ) return 1; + if( sqlite3StrNICmp(z, "OID", n)==0 ) return 1; + return 0; +} +#endif /* ** pX is the RHS of an IN operator. If pX is a SELECT statement diff --git a/src/hash.c b/src/hash.c index 79bb85ac01..fba9dc9f80 100644 --- a/src/hash.c +++ b/src/hash.c @@ -64,6 +64,20 @@ static unsigned int strHash(const char *z){ } return h; } +#ifdef SQLITE_ENABLE_NORMALIZE +static unsigned int strHashN(const char *z, int n){ + unsigned int h = 0; + int i; + for(i=0; iht ){ /*OPTIMIZATION-IF-TRUE*/ + struct _ht *pEntry; + h = strHashN(pKey, nKey) % pH->htsize; + pEntry = &pH->ht[h]; + elem = pEntry->chain; + count = pEntry->count; + }else{ + h = 0; + elem = pH->first; + count = pH->count; + } + if( pHash ) *pHash = h; + while( count-- ){ + assert( elem!=0 ); + if( sqlite3StrNICmp(elem->pKey,pKey,nKey)==0 ){ + return elem; + } + elem = elem->next; + } + return &nullElement; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* Remove a single entry from the hash table given a pointer to that ** element and a hash on the element's key. @@ -219,6 +267,14 @@ void *sqlite3HashFind(const Hash *pH, const char *pKey){ assert( pKey!=0 ); return findElementWithHash(pH, pKey, 0)->data; } +#ifdef SQLITE_ENABLE_NORMALIZE +void *sqlite3HashFindN(const Hash *pH, const char *pKey, int nKey){ + assert( pH!=0 ); + assert( pKey!=0 ); + assert( nKey>=0 ); + return findElementWithHashN(pH, pKey, nKey, 0)->data; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* Insert an element into the hash table pH. The key is pKey ** and the data is "data". diff --git a/src/loadext.c b/src/loadext.c index 72bfd5c51e..710227d7c4 100644 --- a/src/loadext.c +++ b/src/loadext.c @@ -451,7 +451,13 @@ static const sqlite3_api_routines sqlite3Apis = { sqlite3_str_length, sqlite3_str_value, /* Version 3.25.0 and later */ - sqlite3_create_window_function + sqlite3_create_window_function, + /* Version 3.26.0 and later */ +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3_normalized_sql +#else + 0 +#endif }; /* diff --git a/src/prepare.c b/src/prepare.c index 602e4dc49d..6d2b804136 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -709,6 +709,294 @@ static int sqlite3LockAndPrepare( return rc; } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Checks if the specified token is a table, column, or function name, +** based on the databases associated with the statement being prepared. +** If the function fails, zero is returned and pRc is filled with the +** error code. +*/ +static int shouldTreatAsIdentifier( + sqlite3 *db, /* Database handle. */ + const char *zToken, /* Pointer to start of token to be checked */ + int nToken, /* Length of token to be checked */ + int *pRc /* Pointer to error code upon failure */ +){ + int bFound = 0; /* Non-zero if token is an identifier name. */ + int i, j; /* Database and column loop indexes. */ + Schema *pSchema; /* Schema for current database. */ + Hash *pHash; /* Hash table of tables for current database. */ + HashElem *e; /* Hash element for hash table iteration. */ + Table *pTab; /* Database table for columns being checked. */ + + if( sqlite3IsRowidN(zToken, nToken) ){ + return 1; + } + if( nToken>0 ){ + int hash = SQLITE_FUNC_HASH(sqlite3UpperToLower[(u8)zToken[0]], nToken); + if( sqlite3FunctionSearchN(hash, zToken, nToken) ) return 1; + } + assert( db!=0 ); + sqlite3_mutex_enter(db->mutex); + sqlite3BtreeEnterAll(db); + for(i=0; inDb; i++){ + pHash = &db->aFunc; + if( sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + break; + } + pSchema = db->aDb[i].pSchema; + if( pSchema==0 ) continue; + pHash = &pSchema->tblHash; + if( sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + break; + } + for(e=sqliteHashFirst(pHash); e; e=sqliteHashNext(e)){ + pTab = sqliteHashData(e); + if( pTab==0 ) continue; + pHash = pTab->pColHash; + if( pHash==0 ){ + pTab->pColHash = pHash = sqlite3_malloc(sizeof(Hash)); + if( pHash ){ + sqlite3HashInit(pHash); + for(j=0; jnCol; j++){ + Column *pCol = &pTab->aCol[j]; + sqlite3HashInsert(pHash, pCol->zName, pCol); + } + }else{ + *pRc = SQLITE_NOMEM_BKPT; + bFound = 0; + goto done; + } + } + if( pHash && sqlite3HashFindN(pHash, zToken, nToken) ){ + bFound = 1; + goto done; + } + } + } +done: + sqlite3BtreeLeaveAll(db); + sqlite3_mutex_leave(db->mutex); + return bFound; +} + +/* +** Attempt to estimate the final output buffer size needed for the fully +** normalized version of the specified SQL string. This should take into +** account any potential expansion that could occur (e.g. via IN clauses +** being expanded, etc). This size returned is the total number of bytes +** including the NUL terminator. +*/ +static int estimateNormalizedSize( + const char *zSql, /* The original SQL string */ + int nSql, /* Length of original SQL string */ + u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */ +){ + int nOut = nSql + 4; + const char *z = zSql; + while( nOut0 ){ + zOut[j++] = '"'; + continue; + }else if( k==nToken-1 ){ + zOut[j++] = '"'; + continue; + } + } + if( bKeyword ){ + zOut[j++] = sqlite3Toupper(zSql[iIn+k]); + }else{ + zOut[j++] = sqlite3Tolower(zSql[iIn+k]); + } + } + *piOut = j; +} + +/* +** Perform normalization of the SQL contained in the prepared statement and +** store the result in the zNormSql field. The schema for the associated +** databases are consulted while performing the normalization in order to +** determine if a token appears to be an identifier. All identifiers are +** left intact in the normalized SQL and all literals are replaced with a +** single '?'. +*/ +void sqlite3Normalize( + Vdbe *pVdbe, /* VM being reprepared */ + const char *zSql, /* The original SQL string */ + int nSql, /* Size of the input string in bytes */ + u8 prepFlags /* The flags passed to sqlite3_prepare_v3() */ +){ + sqlite3 *db; /* Database handle. */ + char *z; /* The output string */ + int nZ; /* Size of the output string in bytes */ + int i; /* Next character to read from zSql[] */ + int j; /* Next character to fill in on z[] */ + int tokenType = 0; /* Type of the next token */ + int prevTokenType = 0; /* Type of the previous token, except spaces */ + int n; /* Size of the next token */ + int nParen = 0; /* Nesting level of parenthesis */ + Hash inHash; /* Table of parenthesis levels to output index. */ + + db = sqlite3VdbeDb(pVdbe); + assert( db!=0 ); + assert( pVdbe->zNormSql==0 ); + if( zSql==0 ) return; + nZ = estimateNormalizedSize(zSql, nSql, prepFlags); + z = sqlite3DbMallocRawNN(db, nZ); + if( z==0 ) return; + sqlite3HashInit(&inHash); + for(i=j=0; i0 ){ + sqlite3HashInsert(&inHash, zSql+nParen, 0); + assert( jj+6=0 ); + assert( nZ-1-j=0 ); + /* Fall through */ + } + case TK_MINUS: + case TK_SEMI: + case TK_PLUS: + case TK_STAR: + case TK_SLASH: + case TK_REM: + case TK_EQ: + case TK_LE: + case TK_NE: + case TK_LSHIFT: + case TK_LT: + case TK_RSHIFT: + case TK_GT: + case TK_GE: + case TK_BITOR: + case TK_CONCAT: + case TK_COMMA: + case TK_BITAND: + case TK_BITNOT: + case TK_DOT: + case TK_IN: + case TK_IS: + case TK_NOT: + case TK_NULL: + case TK_ID: { + if( tokenType==TK_NULL ){ + if( prevTokenType==TK_IS || prevTokenType==TK_NOT ){ + /* NULL is a keyword in this case, not a literal value */ + }else{ + /* Here the NULL is a literal value */ + z[j++] = '?'; + break; + } + } + if( j>0 && sqlite3IsIdChar(z[j-1]) && sqlite3IsIdChar(zSql[i]) ){ + z[j++] = ' '; + } + if( tokenType==TK_ID ){ + int i2 = i, n2 = n, rc = SQLITE_OK; + if( nParen>0 ){ + assert( nParen0 && z[j-1]==' ' ){ j--; } + if( j>0 && z[j-1]!=';' ){ z[j++] = ';'; } + z[j] = 0; + assert( jzNormSql = z; + sqlite3HashClear(&inHash); +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + /* ** Rerun the compilation of a statement after a schema change. ** diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 2d090e3ec7..9ead2b7aa6 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -3609,9 +3609,19 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** on this hint by avoiding the use of [lookaside memory] so as not to ** deplete the limited store of lookaside memory. Future versions of ** SQLite may act on this hint differently. +** +** [[SQLITE_PREPARE_NORMALIZE]] ^(
SQLITE_PREPARE_NORMALIZE
+**
The SQLITE_PREPARE_NORMALIZE flag indicates that a normalized +** representation of the SQL statement should be calculated and then +** associated with the prepared statement, which can be obtained via +** the [sqlite3_normalized_sql()] interface. The semantics used to +** normalize a SQL statement are unspecified and subject to change. +** At a minimum, literal values will be replaced with suitable +** placeholders. ** */ #define SQLITE_PREPARE_PERSISTENT 0x01 +#define SQLITE_PREPARE_NORMALIZE 0x02 /* ** CAPI3REF: Compiling An SQL Statement @@ -3769,6 +3779,11 @@ int sqlite3_prepare16_v3( ** ^The sqlite3_expanded_sql(P) interface returns a pointer to a UTF-8 ** string containing the SQL text of prepared statement P with ** [bound parameters] expanded. +** ^The sqlite3_normalized_sql(P) interface returns a pointer to a UTF-8 +** string containing the normalized SQL text of prepared statement P. The +** semantics used to normalize a SQL statement are unspecified and subject +** to change. At a minimum, literal values will be replaced with suitable +** placeholders. ** ** ^(For example, if a prepared statement is created using the SQL ** text "SELECT $abc,:xyz" and if parameter $abc is bound to integer 2345 @@ -3784,14 +3799,16 @@ int sqlite3_prepare16_v3( ** bound parameter expansions. ^The [SQLITE_OMIT_TRACE] compile-time ** option causes sqlite3_expanded_sql() to always return NULL. ** -** ^The string returned by sqlite3_sql(P) is managed by SQLite and is -** automatically freed when the prepared statement is finalized. +** ^The strings returned by sqlite3_sql(P) and sqlite3_normalized_sql(P) +** are managed by SQLite and are automatically freed when the prepared +** statement is finalized. ** ^The string returned by sqlite3_expanded_sql(P), on the other hand, ** is obtained from [sqlite3_malloc()] and must be free by the application ** by passing it to [sqlite3_free()]. */ const char *sqlite3_sql(sqlite3_stmt *pStmt); char *sqlite3_expanded_sql(sqlite3_stmt *pStmt); +const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt); /* ** CAPI3REF: Determine If An SQL Statement Writes The Database diff --git a/src/sqlite3ext.h b/src/sqlite3ext.h index 35d9950cf6..34c41fd5a9 100644 --- a/src/sqlite3ext.h +++ b/src/sqlite3ext.h @@ -310,12 +310,15 @@ struct sqlite3_api_routines { int (*str_errcode)(sqlite3_str*); int (*str_length)(sqlite3_str*); char *(*str_value)(sqlite3_str*); + /* Version 3.25.0 and later */ int (*create_window_function)(sqlite3*,const char*,int,int,void*, void (*xStep)(sqlite3_context*,int,sqlite3_value**), void (*xFinal)(sqlite3_context*), void (*xValue)(sqlite3_context*), void (*xInv)(sqlite3_context*,int,sqlite3_value**), void(*xDestroy)(void*)); + /* Version 3.26.0 and later */ + const char *(*normalized_sql)(sqlite3_stmt*); }; /* @@ -603,6 +606,8 @@ typedef int (*sqlite3_loadext_entry)( #define sqlite3_str_value sqlite3_api->str_value /* Version 3.25.0 and later */ #define sqlite3_create_window_function sqlite3_api->create_window_function +/* Version 3.26.0 and later */ +#define sqlite3_normalized_sql sqlite3_api->normalized_sql #endif /* !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) */ #if !defined(SQLITE_CORE) && !defined(SQLITE_OMIT_LOAD_EXTENSION) diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f0ed023c6d..5a6042b2b5 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1312,6 +1312,8 @@ struct FuncDefHash { FuncDef *a[SQLITE_FUNC_HASH_SZ]; /* Hash table for functions */ }; +#define SQLITE_FUNC_HASH(C,L) (((C)+(L))%SQLITE_FUNC_HASH_SZ) + #ifdef SQLITE_USER_AUTHENTICATION /* ** Information held in the "sqlite3" database connection object and used @@ -1943,6 +1945,9 @@ struct VTable { struct Table { char *zName; /* Name of the table or view */ Column *aCol; /* Information about each column */ +#ifdef SQLITE_ENABLE_NORMALIZE + Hash *pColHash; /* All columns indexed by name */ +#endif Index *pIndex; /* List of SQL indexes on this table. */ Select *pSelect; /* NULL for tables. Points to definition if a view. */ FKey *pFKey; /* Linked list of all foreign keys in this table */ @@ -2279,6 +2284,12 @@ struct IndexSample { tRowcnt *anDLt; /* Est. number of distinct keys less than this sample */ }; +/* +** Possible values to use within the flags argument to sqlite3GetToken(). +*/ +#define SQLITE_TOKEN_QUOTED 0x1 /* Token is a quoted identifier. */ +#define SQLITE_TOKEN_KEYWORD 0x2 /* Token is a keyword. */ + /* ** Each token coming out of the lexer is an instance of ** this structure. Tokens are also used as part of an expression. @@ -4000,6 +4011,9 @@ int sqlite3ExprIsInteger(Expr*, int*); int sqlite3ExprCanBeNull(const Expr*); int sqlite3ExprNeedsNoAffinityChange(const Expr*, char); int sqlite3IsRowid(const char*); +#ifdef SQLITE_ENABLE_NORMALIZE +int sqlite3IsRowidN(const char*, int); +#endif void sqlite3GenerateRowDelete( Parse*,Table*,Trigger*,int,int,int,i16,u8,u8,u8,int); void sqlite3GenerateRowIndexDelete(Parse*, Table*, int, int, int*, int); @@ -4026,6 +4040,9 @@ ExprList *sqlite3ExprListDup(sqlite3*,ExprList*,int); SrcList *sqlite3SrcListDup(sqlite3*,SrcList*,int); IdList *sqlite3IdListDup(sqlite3*,IdList*); Select *sqlite3SelectDup(sqlite3*,Select*,int); +#ifdef SQLITE_ENABLE_NORMALIZE +FuncDef *sqlite3FunctionSearchN(int,const char*,int); +#endif void sqlite3InsertBuiltinFuncs(FuncDef*,int); FuncDef *sqlite3FindFunction(sqlite3*,const char*,int,u8,u8); void sqlite3RegisterBuiltinFunctions(void); @@ -4229,6 +4246,9 @@ void sqlite3AlterFunctions(void); void sqlite3AlterRenameTable(Parse*, SrcList*, Token*); void sqlite3AlterRenameColumn(Parse*, SrcList*, Token*, Token*); int sqlite3GetToken(const unsigned char *, int *); +#ifdef SQLITE_ENABLE_NORMALIZE +int sqlite3GetTokenNormalized(const unsigned char *, int *, int *); +#endif void sqlite3NestedParse(Parse*, const char*, ...); void sqlite3ExpirePreparedStatements(sqlite3*, int); int sqlite3CodeSubselect(Parse*, Expr *, int, int); @@ -4386,6 +4406,9 @@ sqlite3_int64 sqlite3StmtCurrentTime(sqlite3_context*); int sqlite3VdbeParameterIndex(Vdbe*, const char*, int); int sqlite3TransferBindings(sqlite3_stmt *, sqlite3_stmt *); void sqlite3ParserReset(Parse*); +#ifdef SQLITE_ENABLE_NORMALIZE +void sqlite3Normalize(Vdbe*, const char*, int, u8); +#endif int sqlite3Reprepare(Vdbe*); void sqlite3ExprListCheckLength(Parse*, ExprList*, const char*); CollSeq *sqlite3BinaryCompareCollSeq(Parse *, Expr *, Expr *); diff --git a/src/test1.c b/src/test1.c index d2c997bdfe..7fee969243 100644 --- a/src/test1.c +++ b/src/test1.c @@ -4218,6 +4218,7 @@ static int SQLITE_TCLAPI test_prepare_v2( char *zCopy = 0; /* malloc() copy of zSql */ int bytes; const char *zTail = 0; + const char **pzTail; sqlite3_stmt *pStmt = 0; char zBuf[50]; int rc; @@ -4242,7 +4243,8 @@ static int SQLITE_TCLAPI test_prepare_v2( zCopy = malloc(n); memcpy(zCopy, zSql, n); } - rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, objc>=5 ? &zTail : 0); + pzTail = objc>=5 ? &zTail : 0; + rc = sqlite3_prepare_v2(db, zCopy, bytes, &pStmt, pzTail); free(zCopy); zTail = &zSql[(zTail - zCopy)]; @@ -4269,6 +4271,79 @@ static int SQLITE_TCLAPI test_prepare_v2( return TCL_OK; } +/* +** Usage: sqlite3_prepare_v3 DB sql bytes flags ?tailvar? +** +** Compile up to bytes of the supplied SQL string using +** database handle and flags . The parameter is +** the name of a global variable that is set to the unused portion of +** (if any). A STMT handle is returned. +*/ +static int SQLITE_TCLAPI test_prepare_v3( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3 *db; + const char *zSql; + char *zCopy = 0; /* malloc() copy of zSql */ + int bytes, flags; + const char *zTail = 0; + const char **pzTail; + sqlite3_stmt *pStmt = 0; + char zBuf[50]; + int rc; + + if( objc!=6 && objc!=5 ){ + Tcl_AppendResult(interp, "wrong # args: should be \"", + Tcl_GetString(objv[0]), " DB sql bytes flags tailvar", 0); + return TCL_ERROR; + } + if( getDbPointer(interp, Tcl_GetString(objv[1]), &db) ) return TCL_ERROR; + zSql = Tcl_GetString(objv[2]); + if( Tcl_GetIntFromObj(interp, objv[3], &bytes) ) return TCL_ERROR; + if( Tcl_GetIntFromObj(interp, objv[4], &flags) ) return TCL_ERROR; + + /* Instead of using zSql directly, make a copy into a buffer obtained + ** directly from malloc(). The idea is to make it easier for valgrind + ** to spot buffer overreads. */ + if( bytes>=0 ){ + zCopy = malloc(bytes); + memcpy(zCopy, zSql, bytes); + }else{ + int n = (int)strlen(zSql) + 1; + zCopy = malloc(n); + memcpy(zCopy, zSql, n); + } + pzTail = objc>=6 ? &zTail : 0; + rc = sqlite3_prepare_v3(db, zCopy, bytes, (unsigned int)flags,&pStmt,pzTail); + free(zCopy); + zTail = &zSql[(zTail - zCopy)]; + + assert(rc==SQLITE_OK || pStmt==0); + Tcl_ResetResult(interp); + if( sqlite3TestErrCode(interp, db, rc) ) return TCL_ERROR; + if( rc==SQLITE_OK && zTail && objc>=6 ){ + if( bytes>=0 ){ + bytes = bytes - (int)(zTail-zSql); + } + Tcl_ObjSetVar2(interp, objv[5], 0, Tcl_NewStringObj(zTail, bytes), 0); + } + if( rc!=SQLITE_OK ){ + assert( pStmt==0 ); + sqlite3_snprintf(sizeof(zBuf), zBuf, "(%d) ", rc); + Tcl_AppendResult(interp, zBuf, sqlite3_errmsg(db), 0); + return TCL_ERROR; + } + + if( pStmt ){ + if( sqlite3TestMakePointerStr(interp, zBuf, pStmt) ) return TCL_ERROR; + Tcl_AppendResult(interp, zBuf, 0); + } + return TCL_OK; +} + /* ** Usage: sqlite3_prepare_tkt3134 DB ** @@ -4676,6 +4751,25 @@ static int SQLITE_TCLAPI test_ex_sql( sqlite3_free(z); return TCL_OK; } +#ifdef SQLITE_ENABLE_NORMALIZE +static int SQLITE_TCLAPI test_norm_sql( + void * clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *CONST objv[] +){ + sqlite3_stmt *pStmt; + + if( objc!=2 ){ + Tcl_WrongNumArgs(interp, 1, objv, "STMT"); + return TCL_ERROR; + } + + if( getStmtPointer(interp, Tcl_GetString(objv[1]), &pStmt) ) return TCL_ERROR; + Tcl_SetResult(interp, (char *)sqlite3_normalized_sql(pStmt), TCL_VOLATILE); + return TCL_OK; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ /* ** Usage: sqlite3_column_count STMT @@ -7646,6 +7740,7 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_prepare", test_prepare ,0 }, { "sqlite3_prepare16", test_prepare16 ,0 }, { "sqlite3_prepare_v2", test_prepare_v2 ,0 }, + { "sqlite3_prepare_v3", test_prepare_v3 ,0 }, { "sqlite3_prepare_tkt3134", test_prepare_tkt3134, 0}, { "sqlite3_prepare16_v2", test_prepare16_v2 ,0 }, { "sqlite3_finalize", test_finalize ,0 }, @@ -7657,6 +7752,9 @@ int Sqlitetest1_Init(Tcl_Interp *interp){ { "sqlite3_step", test_step ,0 }, { "sqlite3_sql", test_sql ,0 }, { "sqlite3_expanded_sql", test_ex_sql ,0 }, +#ifdef SQLITE_ENABLE_NORMALIZE + { "sqlite3_normalized_sql", test_norm_sql ,0 }, +#endif { "sqlite3_next_stmt", test_next_stmt ,0 }, { "sqlite3_stmt_readonly", test_stmt_readonly ,0 }, { "sqlite3_stmt_busy", test_stmt_busy ,0 }, diff --git a/src/test_config.c b/src/test_config.c index f017abc307..05002349bd 100644 --- a/src/test_config.c +++ b/src/test_config.c @@ -762,6 +762,12 @@ Tcl_SetVar2(interp, "sqlite_options", "mergesort", "1", TCL_GLOBAL_ONLY); Tcl_SetVar2(interp, "sqlite_options", "uri_00_error", "0", TCL_GLOBAL_ONLY); #endif +#if defined(SQLITE_ENABLE_NORMALIZE) + Tcl_SetVar2(interp, "sqlite_options", "normalize", "1", TCL_GLOBAL_ONLY); +#else + Tcl_SetVar2(interp, "sqlite_options", "normalize", "0", TCL_GLOBAL_ONLY); +#endif + #ifdef SQLITE_OMIT_WINDOWFUNC Tcl_SetVar2(interp, "sqlite_options", "windowfunc", "0", TCL_GLOBAL_ONLY); #else diff --git a/src/tokenize.c b/src/tokenize.c index 262144ff7d..05ca86e74f 100644 --- a/src/tokenize.c +++ b/src/tokenize.c @@ -545,6 +545,73 @@ int sqlite3GetToken(const unsigned char *z, int *tokenType){ return i; } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the length (in bytes) of the token that begins at z[0]. +** Store the token type in *tokenType before returning. If flags has +** SQLITE_TOKEN_NORMALIZE flag enabled, use the identifier token type +** for keywords. Add SQLITE_TOKEN_QUOTED to flags if the token was +** actually a quoted identifier. Add SQLITE_TOKEN_KEYWORD to flags +** if the token was recognized as a keyword; this is useful when the +** SQLITE_TOKEN_NORMALIZE flag is used, because it enables the caller +** to differentiate between a keyword being treated as an identifier +** (for normalization purposes) and an actual identifier. +*/ +int sqlite3GetTokenNormalized( + const unsigned char *z, + int *tokenType, + int *flags +){ + int n; + unsigned char iClass = aiClass[*z]; + if( iClass==CC_KYWD ){ + int i; + for(i=1; aiClass[z[i]]<=CC_KYWD; i++){} + if( IdChar(z[i]) ){ + /* This token started out using characters that can appear in keywords, + ** but z[i] is a character not allowed within keywords, so this must + ** be an identifier instead */ + i++; + while( IdChar(z[i]) ){ i++; } + *tokenType = TK_ID; + return i; + } + *tokenType = TK_ID; + n = keywordCode((char*)z, i, tokenType); + /* If the token is no longer considered to be an identifier, then it is a + ** keyword of some kind. Make the token back into an identifier and then + ** set the SQLITE_TOKEN_KEYWORD flag. Several non-identifier tokens are + ** used verbatim, including IN, IS, NOT, and NULL. */ + switch( *tokenType ){ + case TK_ID: { + /* do nothing, handled by caller */ + break; + } + case TK_IN: + case TK_IS: + case TK_NOT: + case TK_NULL: { + *flags |= SQLITE_TOKEN_KEYWORD; + break; + } + default: { + *tokenType = TK_ID; + *flags |= SQLITE_TOKEN_KEYWORD; + break; + } + } + }else{ + n = sqlite3GetToken(z, tokenType); + /* If the token is considered to be an identifier and the character class + ** of the first character is a quote, set the SQLITE_TOKEN_QUOTED flag. */ + if( *tokenType==TK_ID && (iClass==CC_QUOTE || iClass==CC_QUOTE2) ){ + *flags |= SQLITE_TOKEN_QUOTED; + } + } + return n; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + /* ** Run the parser on the given SQL string. The parser structure is ** passed in. An SQLITE_ status code is returned. If an error occurs diff --git a/src/vdbeInt.h b/src/vdbeInt.h index 107e5cab44..1cb7219611 100644 --- a/src/vdbeInt.h +++ b/src/vdbeInt.h @@ -406,6 +406,9 @@ struct Vdbe { yDbMask lockMask; /* Subset of btreeMask that requires a lock */ u32 aCounter[7]; /* Counters used by sqlite3_stmt_status() */ char *zSql; /* Text of the SQL statement that generated this */ +#ifdef SQLITE_ENABLE_NORMALIZE + char *zNormSql; /* Normalization of the associated SQL statement */ +#endif void *pFree; /* Free this when deleting the vdbe */ VdbeFrame *pFrame; /* Parent frame */ VdbeFrame *pDelFrame; /* List of frame objects to free on VM reset */ diff --git a/src/vdbeapi.c b/src/vdbeapi.c index b21f70e7e0..59327bed38 100644 --- a/src/vdbeapi.c +++ b/src/vdbeapi.c @@ -1702,6 +1702,16 @@ char *sqlite3_expanded_sql(sqlite3_stmt *pStmt){ #endif } +#ifdef SQLITE_ENABLE_NORMALIZE +/* +** Return the normalized SQL associated with a prepared statement. +*/ +const char *sqlite3_normalized_sql(sqlite3_stmt *pStmt){ + Vdbe *p = (Vdbe *)pStmt; + return p ? p->zNormSql : 0; +} +#endif /* SQLITE_ENABLE_NORMALIZE */ + #ifdef SQLITE_ENABLE_PREUPDATE_HOOK /* ** Allocate and populate an UnpackedRecord structure based on the serialized diff --git a/src/vdbeaux.c b/src/vdbeaux.c index 99df435966..f1496a3abf 100644 --- a/src/vdbeaux.c +++ b/src/vdbeaux.c @@ -64,6 +64,13 @@ void sqlite3VdbeSetSql(Vdbe *p, const char *z, int n, u8 prepFlags){ } assert( p->zSql==0 ); p->zSql = sqlite3DbStrNDup(p->db, z, n); +#ifdef SQLITE_ENABLE_NORMALIZE + assert( p->zNormSql==0 ); + if( p->zSql && (prepFlags & SQLITE_PREPARE_NORMALIZE)!=0 ){ + sqlite3Normalize(p, p->zSql, n, prepFlags); + assert( p->zNormSql!=0 || p->db->mallocFailed ); + } +#endif } /* @@ -85,6 +92,11 @@ void sqlite3VdbeSwap(Vdbe *pA, Vdbe *pB){ zTmp = pA->zSql; pA->zSql = pB->zSql; pB->zSql = zTmp; +#ifdef SQLITE_ENABLE_NORMALIZE + zTmp = pA->zNormSql; + pA->zNormSql = pB->zNormSql; + pB->zNormSql = zTmp; +#endif pB->expmask = pA->expmask; pB->prepFlags = pA->prepFlags; memcpy(pB->aCounter, pA->aCounter, sizeof(pB->aCounter)); @@ -3156,6 +3168,9 @@ void sqlite3VdbeClearObject(sqlite3 *db, Vdbe *p){ vdbeFreeOpArray(db, p->aOp, p->nOp); sqlite3DbFree(db, p->aColName); sqlite3DbFree(db, p->zSql); +#ifdef SQLITE_ENABLE_NORMALIZE + sqlite3DbFree(db, p->zNormSql); +#endif #ifdef SQLITE_ENABLE_STMT_SCANSTATUS { int i; diff --git a/test/normalize.test b/test/normalize.test index 9e3ec9c967..e85bd00332 100644 --- a/test/normalize.test +++ b/test/normalize.test @@ -72,4 +72,293 @@ foreach {tnum sql norm} { do_test $tnum [list sqlite3_normalize $sql] $norm } +ifcapable normalize { +do_test 200 { + execsql { + CREATE TABLE t1(a,b); + } +} {} +do_test 201 { + set STMT [sqlite3_prepare_v3 $DB \ + "SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 0 TAIL] + + sqlite3_bind_null $STMT 1 +} {} +do_test 202 { + sqlite3_normalized_sql $STMT +} {} +do_test 203 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +do_test 210 { + set STMT [sqlite3_prepare_v3 $DB \ + "SELECT a, b FROM t1 WHERE b = ? ORDER BY a;" -1 2 TAIL] + + sqlite3_bind_null $STMT 1 +} {} +do_test 211 { + sqlite3_normalized_sql $STMT +} {SELECT a,b FROM t1 WHERE b=?ORDER BY a;} +do_test 212 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +do_test 220 { + set STMT [sqlite3_prepare_v3 $DB \ + "SELECT a, b FROM t1 WHERE b = 'a' ORDER BY a;" -1 2 TAIL] +} {/^[0-9A-Fa-f]+$/} +do_test 221 { + sqlite3_normalized_sql $STMT +} {SELECT a,b FROM t1 WHERE b=?ORDER BY a;} +do_test 222 { + sqlite3_finalize $STMT +} {SQLITE_OK} + +do_test 297 { + execsql { + DROP TABLE t1; + } +} {} +do_test 298 { + execsql { + CREATE TABLE t1(a,b,c,d,e,"col f",w,x,y,z); + CREATE TABLE t2(x,"col y"); + } +} {} +do_test 299 { + sqlite3_create_function db +} {SQLITE_OK} + +foreach {tnum sql flags norm} { + 300 + {SELECT * FROM t1 WHERE a IN (1) AND b=51.42} + 0x2 + {0 {SELECT*FROM t1 WHERE a IN(?,?,?)AND b=?;}} + + 310 + {SELECT a, b+15, c FROM t1 WHERE d NOT IN (SELECT x FROM t2);} + 0x2 + {0 {SELECT a,b+?,c FROM t1 WHERE d NOT IN(SELECT x FROM t2);}} + + 320 + { SELECT NULL, b FROM t1 -- comment text + WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */ + SELECT a FROM t) + OR e='hello'; + } + 0x2 + {0 {SELECT?,b FROM t1 WHERE d IN(WITH t(a)AS(VALUES(?))SELECT a FROM t)OR e=?;}} + + 321 + {/*Initial comment*/ + -- another comment line + SELECT NULL /* comment */ , b FROM t1 -- comment text + WHERE d IN (WITH t(a) AS (VALUES(5)) /* CTE */ + SELECT a FROM t) + OR e='hello'; + } + 0x2 + {0 {SELECT?,b FROM t1 WHERE d IN(WITH t(a)AS(VALUES(?))SELECT a FROM t)OR e=?;}} + + 330 + {/* Query containing parameters */ + SELECT x,$::abc(15),y,@abc,z,?99,w FROM t1 /* Trailing comment */} + 0x2 + {0 {SELECT x,?,y,?,z,?,w FROM t1;}} + + 340 + {/* Long list on the RHS of IN */ + SELECT 15 IN (1,2,3,(SELECT * FROM t1),'xyz',x'abcd',22*(x+5),null);} + 0x2 + {1 {(1) no such column: x}} + + 350 + {SELECT x'abc'; -- illegal token} + 0x2 + {1 {(1) unrecognized token: "x'abc'"}} + + 360 + {SELECT a,NULL,b FROM t1 WHERE c IS NOT NULL or D is null or e=5} + 0x2 + {0 {SELECT a,?,b FROM t1 WHERE c IS NOT NULL OR d IS NULL OR e=?;}} + + 370 + {/* IN list exactly 5 bytes long */ + SELECT * FROM t1 WHERE x IN (1,2,3);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 400 + {SELECT a FROM t1 WHERE x IN (1,2,3) AND sqlite_version();} + 0x2 + {0 {SELECT a FROM t1 WHERE x IN(?,?,?)AND sqlite_version();}} + + 410 + {SELECT a FROM t1 WHERE x IN (1,2,3) AND hex8();} + 0x2 + {1 {(1) wrong number of arguments to function hex8()}} + + 420 + {SELECT a FROM t1 WHERE x IN (1,2,3) AND hex8('abc');} + 0x2 + {0 {SELECT a FROM t1 WHERE x IN(?,?,?)AND hex8(?);}} + + 430 + {SELECT "a" FROM t1 WHERE "x" IN ("1","2",'3');} + 0x2 + {0 {SELECT"a"FROM t1 WHERE"x"IN(?,?,?);}} + + 440 + {SELECT 'a' FROM t1 WHERE 'x';} + 0x2 + {0 {SELECT?FROM t1 WHERE?;}} + + 450 + {SELECT [a] FROM t1 WHERE [x];} + 0x2 + {0 {SELECT"a"FROM t1 WHERE"x";}} + + 460 + {SELECT * FROM t1 WHERE x IN (x);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(x);}} + + 470 + {SELECT * FROM t1 WHERE x IN (x,a);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(x,a);}} + + 480 + {SELECT * FROM t1 WHERE x IN ([x],"a");} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN("x","a");}} + + 500 + {SELECT * FROM t1 WHERE x IN ([x],"a",'b',sqlite_version());} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN("x","a",?,sqlite_version());}} + + 520 + {SELECT * FROM t1 WHERE x IN (SELECT x FROM t1);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1);}} + + 540 + {SELECT * FROM t1 WHERE x IN ((SELECT x FROM t1));} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 550 + {SELECT a, a+1, a||'b', a+"b" FROM t1;} + 0x2 + {0 {SELECT a,a+?,a||?,a+"b"FROM t1;}} + + 570 + {SELECT * FROM t1 WHERE x IN (1);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 580 + {SELECT * FROM t1 WHERE x IN (1,2);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 590 + {SELECT * FROM t1 WHERE x IN (1,2,3);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 600 + {SELECT * FROM t1 WHERE x IN (1,2,3,4);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(?,?,?);}} + + 610 + {SELECT * FROM t1 WHERE x IN (SELECT x FROM t1);} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1);}} + + 620 + {SELECT * FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (1,2,3));} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(?,?,?));}} + + 630 + {SELECT * FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN (x));} + 0x2 + {0 {SELECT*FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(x));}} + + 640 + {SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN ( + SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN ( + SELECT x FROM t1 WHERE x IN (x)))));} + 0x2 + {0 {SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(x)))));}} + + 650 + {SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN ( + SELECT x FROM t1 WHERE x IN (SELECT x FROM t1 WHERE x IN ( + SELECT x FROM t1 WHERE x IN (1)))));} + 0x2 + {0 {SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(SELECT x FROM t1 WHERE x IN(?,?,?)))));}} + + 660 + {SELECT x FROM t1 WHERE x IN (1) UNION ALL SELECT x FROM t1 WHERE x IN (1);} + 0x2 + {0 {SELECT x FROM t1 WHERE x IN(?,?,?)UNION ALL SELECT x FROM t1 WHERE x IN(?,?,?);}} + + 670 + {SELECT "col f", [col f] FROM t1;} + 0x2 + {0 {SELECT"col f","col f"FROM t1;}} + + 680 + {SELECT a, "col f" FROM t1 LEFT OUTER JOIN t2 ON [t1].[col f] == [t2].[col y];} + 0x2 + {0 {SELECT a,"col f"FROM t1 LEFT OUTER JOIN t2 ON"t1"."col f"=="t2"."col y";}} + + 690 + {SELECT * FROM ( WITH x AS ( SELECT * FROM t1 WHERE x IN ( 1)) SELECT 10);} + 0x2 + {0 {SELECT*FROM(WITH x AS(SELECT*FROM t1 WHERE x IN(?,?,?))SELECT?);}} + + 700 + {SELECT rowid, oid, _rowid_ FROM t1;} + 0x2 + {0 {SELECT rowid,oid,_rowid_ FROM t1;}} + + 710 + {SELECT x FROM t1 WHERE x IS NULL;} + 0x2 + {0 {SELECT x FROM t1 WHERE x IS NULL;}} + + 740 + {SELECT x FROM t1 WHERE x IS NOT NULL;} + 0x2 + {0 {SELECT x FROM t1 WHERE x IS NOT NULL;}} + + 750 + {SELECT x FROM t1 WHERE x = NULL;} + 0x2 + {0 {SELECT x FROM t1 WHERE x=?;}} + + 760 + {SELECT x FROM t1 WHERE x IN ([x] IS NOT NULL, NULL, 1, 'a', "b", x'00');} + 0x2 + {0 {SELECT x FROM t1 WHERE x IN("x"IS NOT NULL,?,?,?,"b",?);}} +} { + do_test $tnum { + set code [catch { + set STMT [sqlite3_prepare_v3 $DB $sql -1 $flags TAIL] + sqlite3_normalized_sql $STMT + } res] + if {[info exists STMT]} { + sqlite3_finalize $STMT; unset STMT + } + list $code $res + } $norm +} +} + finish_test From 5aa20378f7edae2e3c51cda3f7a87609555fc15d Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 29 Oct 2018 18:33:42 +0000 Subject: [PATCH 042/109] Fix minor memory leak in the dbstat extension that can occur following an attempt to analyze a corrupt database file. FossilOrigin-Name: cb874fd87384be397008e953242d5773ef5d64e07c3e1ae352a42a25d70597b4 --- manifest | 14 +++++++------- manifest.uuid | 2 +- src/dbstat.c | 10 ++++++++-- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/manifest b/manifest index e51359b125..6538bbb794 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\ssessions\smodule,\savoid\scollecting\srebase\sdata\sif\sthe\suser\shas\snot\nrequested\sit. -D 2018-10-29T17:08:27.831 +C Fix\sminor\smemory\sleak\sin\sthe\sdbstat\sextension\sthat\scan\soccur\sfollowing\san\nattempt\sto\sanalyze\sa\scorrupt\sdatabase\sfile. +D 2018-10-29T18:33:42.996 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b @@ -454,7 +454,7 @@ F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950 F src/date.c ebe1dc7c8a347117bb02570f1a931c62dd78f4a2b1b516f4837d45b7d6426957 F src/dbpage.c 4aa7f26198934dbd002e69418220eae3dbc71b010bbac32bd78faf86b52ce6c3 -F src/dbstat.c 5f96184b8a751b7c92b959b55679f56e409c3b3bbe98eaf5e43189c16d4df082 +F src/dbstat.c e042b0e7833fdacf2d5ea92c6b536962fea6aeed8b7287ca87ddfa3412bd9564 F src/delete.c 107e28d3ef8bd72fd11953374ca9107cd74e8b09c3ded076a6048742d26ce7d2 F src/expr.c 5cee8fb79b1952689af80ed71ed16ad295f29d85de30c7592993b05cf1ec1e06 F src/fault.c 460f3e55994363812d9d60844b2a6de88826e007 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P a0d47f25ae7bdf98f5b853f23776b3bf86bea7c0dda386664c1e3b1c363c518f -R e9d59384eb4e31957429edb55e9fdfcd -U dan -Z e1a47567ef9afc1d6422d6b424bf5b3a +P de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f +R eb815e43406071d92b5d2a2f430dc9b0 +U drh +Z 086aafd24f9b8312d4c30fa6c97d493c diff --git a/manifest.uuid b/manifest.uuid index 171c1f3dc2..6234af9698 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f \ No newline at end of file +cb874fd87384be397008e953242d5773ef5d64e07c3e1ae352a42a25d70597b4 \ No newline at end of file diff --git a/src/dbstat.c b/src/dbstat.c index 0eb70d6ce8..ca0d541013 100644 --- a/src/dbstat.c +++ b/src/dbstat.c @@ -254,7 +254,7 @@ static int statOpen(sqlite3_vtab *pVTab, sqlite3_vtab_cursor **ppCursor){ return SQLITE_OK; } -static void statClearPage(StatPage *p){ +static void statClearCells(StatPage *p){ int i; if( p->aCell ){ for(i=0; inCell; i++){ @@ -262,6 +262,12 @@ static void statClearPage(StatPage *p){ } sqlite3_free(p->aCell); } + p->nCell = 0; + p->aCell = 0; +} + +static void statClearPage(StatPage *p){ + statClearCells(p); sqlite3PagerUnref(p->pPg); sqlite3_free(p->zPath); memset(p, 0, sizeof(StatPage)); @@ -417,7 +423,7 @@ static int statDecodePage(Btree *pBt, StatPage *p){ statPageIsCorrupt: p->flags = 0; - p->nCell = 0; + statClearCells(p); return SQLITE_OK; } From f4452cfbed0627f3eb09b59a5cf8ecc03509ff4f Mon Sep 17 00:00:00 2001 From: drh Date: Mon, 29 Oct 2018 21:01:28 +0000 Subject: [PATCH 043/109] Fix a potential assertion fault that can occur while trying to DROP a table from a corrupted database file. FossilOrigin-Name: 147a9429a558cf34c316ab8f87832e97caff55d92df696ab6fd045466c8c663d --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/build.c | 2 +- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/manifest b/manifest index 6538bbb794..107c9cfb4d 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\sminor\smemory\sleak\sin\sthe\sdbstat\sextension\sthat\scan\soccur\sfollowing\san\nattempt\sto\sanalyze\sa\scorrupt\sdatabase\sfile. -D 2018-10-29T18:33:42.996 +C Fix\sa\spotential\sassertion\sfault\sthat\scan\soccur\swhile\strying\sto\sDROP\sa\stable\nfrom\sa\scorrupted\sdatabase\sfile. +D 2018-10-29T21:01:28.956 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b @@ -448,7 +448,7 @@ F src/btmutex.c 8acc2f464ee76324bf13310df5692a262b801808984c1b79defb2503bbafadb6 F src/btree.c 3f5e1a03db871e627bf5da21092bf7434ecfc5c5980bbd7d45eba13341340173 F src/btree.h febb2e817be499570b7a2e32a9bbb4b607a9234f6b84bb9ae84916d4806e96f2 F src/btreeInt.h 620ab4c7235f43572cf3ac2ac8723cbdf68073be4d29da24897c7b77dda5fd96 -F src/build.c 0b3d422770877d74ee6d54f4c122d82c48f7d04ee3bfb91702e402de7f5c45ac +F src/build.c bd47530436bcdd6c6111a44c88d6c629ebc5a6666602d1cdb9b6b26a531ee741 F src/callback.c 36caff1e7eb7deb58572d59c41cee8f064a11d00297616995c5050ea0cfc1288 F src/complete.c a3634ab1e687055cd002e11b8f43eb75c17da23e F src/ctime.c 56e2f32d2e5491c152352bd53cffc9979ee1e1b70df39ec97a90920ae420a950 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P de72a773dd3ad58a7f2233e1fc06bf60deb8892a2719ea8e9b42e7d592c1279f -R eb815e43406071d92b5d2a2f430dc9b0 +P cb874fd87384be397008e953242d5773ef5d64e07c3e1ae352a42a25d70597b4 +R b9321fff6a079c972c21f4df38b7700f U drh -Z 086aafd24f9b8312d4c30fa6c97d493c +Z 665cf9956f9ce1e131787aec1eb32143 diff --git a/manifest.uuid b/manifest.uuid index 6234af9698..cb2346c216 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -cb874fd87384be397008e953242d5773ef5d64e07c3e1ae352a42a25d70597b4 \ No newline at end of file +147a9429a558cf34c316ab8f87832e97caff55d92df696ab6fd045466c8c663d \ No newline at end of file diff --git a/src/build.c b/src/build.c index b4041389ba..d143dd7e0d 100644 --- a/src/build.c +++ b/src/build.c @@ -2422,7 +2422,7 @@ void sqlite3RootPageMoved(sqlite3 *db, int iDb, int iFrom, int iTo){ static void destroyRootPage(Parse *pParse, int iTable, int iDb){ Vdbe *v = sqlite3GetVdbe(pParse); int r1 = sqlite3GetTempReg(pParse); - assert( iTable>1 ); + if( iTable<2 ) sqlite3ErrorMsg(pParse, "corrupt schema"); sqlite3VdbeAddOp3(v, OP_Destroy, iTable, r1, iDb); sqlite3MayAbort(pParse); #ifndef SQLITE_OMIT_AUTOVACUUM From 60f34ae09128bfe2ccd9574d1663102933ab1f1e Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 13:19:49 +0000 Subject: [PATCH 044/109] Enable sqlite3_deserialize() in the CLI. The --deserialize option associated with opening a new database cause the database file to be read into memory and accessed using the sqlite3_deserialize() API. This simplifies running tests on a database without risk of modifying the file on disk. FossilOrigin-Name: 5e0129ee9afa7c2d707f8ac9e29ef3583c49bb1d0965085c067d58f828ac8cdf --- Makefile.in | 1 + Makefile.msc | 1 + main.mk | 1 + manifest | 18 +++++++++--------- manifest.uuid | 2 +- src/shell.c.in | 39 ++++++++++++++++++++++++++++++--------- 6 files changed, 43 insertions(+), 19 deletions(-) diff --git a/Makefile.in b/Makefile.in index 3d44a96b31..d89395f60f 100644 --- a/Makefile.in +++ b/Makefile.in @@ -596,6 +596,7 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC +SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 -DSQLITE_OSS_FUZZ diff --git a/Makefile.msc b/Makefile.msc index b9fab7c408..d8fd0f5ee6 100644 --- a/Makefile.msc +++ b/Makefile.msc @@ -1633,6 +1633,7 @@ FUZZDATA = \ SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_FTS4=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_EXPLAIN_COMMENTS=1 SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_OFFSET_SQL_FUNC=1 +SHELL_COMPILE_OPTS = $(SHELL_COMPILE_OPTS) -DSQLITE_ENABLE_DESERIALIZE=1 !ENDIF # <> diff --git a/main.mk b/main.mk index 1df68076c1..884b46993b 100644 --- a/main.mk +++ b/main.mk @@ -523,6 +523,7 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC +SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 diff --git a/manifest b/manifest index 107c9cfb4d..aaaac750bd 100644 --- a/manifest +++ b/manifest @@ -1,10 +1,10 @@ -C Fix\sa\spotential\sassertion\sfault\sthat\scan\soccur\swhile\strying\sto\sDROP\sa\stable\nfrom\sa\scorrupted\sdatabase\sfile. -D 2018-10-29T21:01:28.956 +C Enable\ssqlite3_deserialize()\sin\sthe\sCLI.\s\sThe\s--deserialize\soption\sassociated\nwith\sopening\sa\snew\sdatabase\scause\sthe\sdatabase\sfile\sto\sbe\sread\sinto\smemory\nand\saccessed\susing\sthe\ssqlite3_deserialize()\sAPI.\s\sThis\ssimplifies\srunning\s\ntests\son\sa\sdatabase\swithout\srisk\sof\smodifying\sthe\sfile\son\sdisk. +D 2018-10-30T13:19:49.896 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea -F Makefile.in 15344f4e44dfd9ffb04e9867bdd352a8a5a86211b8919a6ca724e7063694320b +F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 F Makefile.linux-gcc 7bc79876b875010e8c8f9502eb935ca92aa3c434 -F Makefile.msc b946f8806a5d401a299453f61de80dfd1a9df14fa4902b299e6465e3c3134872 +F Makefile.msc 425975b711d07077fc50df2bbe13f4e363274cc63f7352f7be701729112705fa F README.md 377233394b905d3b2e2b33741289e093bc93f2e7adbe00923b2c5958c9a9edee F VERSION 654da1d4053fb09ffc33a3910e6d427182a7dcdc67e934fa83de2849ac83fccb F aclocal.m4 a5c22d164aff7ed549d53a90fa56d56955281f50 @@ -426,7 +426,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk ff82d38126f8f0668b7990e0f1f3dcd74fa2d477c19b2e3feaaba586051e9b48 +F main.mk 261a2292823e3c3107515f7a25c73915b3bfa0bda28136d91999e62dfbb2e082 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -505,7 +505,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f -F src/shell.c.in 248af8c0d785c98268353e58c96715313f3b091bf220d35366affc9a9c0d4e1d +F src/shell.c.in ac4a731dac549746242281d0dac44d53b9f2373f4079cb870cb2681f3e719f6b F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P cb874fd87384be397008e953242d5773ef5d64e07c3e1ae352a42a25d70597b4 -R b9321fff6a079c972c21f4df38b7700f +P 147a9429a558cf34c316ab8f87832e97caff55d92df696ab6fd045466c8c663d +R 60676dfd9c16e59bb8febcd06a129176 U drh -Z 665cf9956f9ce1e131787aec1eb32143 +Z 8d1616bb6665374bfbdd3e19d20e8131 diff --git a/manifest.uuid b/manifest.uuid index cb2346c216..0f7ca93aba 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -147a9429a558cf34c316ab8f87832e97caff55d92df696ab6fd045466c8c663d \ No newline at end of file +5e0129ee9afa7c2d707f8ac9e29ef3583c49bb1d0965085c067d58f828ac8cdf \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index e70e2939bd..73a649410d 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -1059,11 +1059,12 @@ struct ShellState { /* Allowed values for ShellState.openMode */ -#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ -#define SHELL_OPEN_NORMAL 1 /* Normal database file */ -#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ -#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ -#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ +#define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ +#define SHELL_OPEN_NORMAL 1 /* Normal database file */ +#define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ +#define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ +#define SHELL_OPEN_READONLY 4 /* Open a normal database read-only */ +#define SHELL_OPEN_DESERIALIZE 5 /* Open using sqlite3_deserialize() */ /* ** These are the allowed shellFlgs values @@ -3432,10 +3433,11 @@ static const char *(azHelp[]) = { " -x Open in a spreadsheet", ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", - " --append Use appendvfs to append database to the end of FILE", - " --new Initialize FILE to an empty database", - " --readonly Open FILE readonly", - " --zip FILE is a ZIP archive", + " --append Use appendvfs to append database to the end of FILE", + " --deserialize Load into memory useing sqlite3_deserialize()", + " --new Initialize FILE to an empty database", + " --readonly Open FILE readonly", + " --zip FILE is a ZIP archive", ".output ?FILE? Send output to FILE or stdout if FILE is omitted", " If FILE begins with '|' then open it as a pipe.", ".print STRING... Print literal STRING", @@ -3724,6 +3726,10 @@ static void open_db(ShellState *p, int openFlags){ SQLITE_OPEN_READWRITE|SQLITE_OPEN_CREATE, "apndvfs"); break; } + case SHELL_OPEN_DESERIALIZE: { + sqlite3_open(0, &p->db); + break; + } case SHELL_OPEN_ZIPFILE: { sqlite3_open(":memory:", &p->db); break; @@ -3772,6 +3778,15 @@ static void open_db(ShellState *p, int openFlags){ "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); + }else if( p->openMode==SHELL_OPEN_DESERIALIZE ){ + int nData = 0; + unsigned char *aData = (unsigned char*)readFile(p->zDbFilename, &nData); + int rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, + SQLITE_DESERIALIZE_RESIZEABLE | + SQLITE_DESERIALIZE_FREEONCLOSE); + if( rc ){ + utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); + } } } } @@ -6653,6 +6668,8 @@ static int do_meta_command(char *zLine, ShellState *p){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ p->openMode = SHELL_OPEN_READONLY; + }else if( optionMatch(z, "deserialize") ){ + p->openMode = SHELL_OPEN_DESERIALIZE; }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; @@ -8621,6 +8638,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; + }else if( strcmp(z,"-deserialize")==0 ){ + data.openMode = SHELL_OPEN_DESERIALIZE; }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) @@ -8716,6 +8735,8 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; + }else if( strcmp(z,"-deserialize")==0 ){ + data.openMode = SHELL_OPEN_DESERIALIZE; }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-ascii")==0 ){ From 2b3c4af5531eba010283d9846c21d49b930f2bdf Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 14:36:21 +0000 Subject: [PATCH 045/109] In the CLI, when opening a file that begins with the normal SQLite prefix, open the file as a normal database even if it has a ZIP for AppendVFS record at the end. FossilOrigin-Name: 7989bbda70a24611c3b8af96a53114bb53d87a2e1145ec7ad4f1b4cbf8d6040c --- manifest | 12 ++++++------ manifest.uuid | 2 +- src/shell.c.in | 5 +++++ 3 files changed, 12 insertions(+), 7 deletions(-) diff --git a/manifest b/manifest index aaaac750bd..0eca201021 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Enable\ssqlite3_deserialize()\sin\sthe\sCLI.\s\sThe\s--deserialize\soption\sassociated\nwith\sopening\sa\snew\sdatabase\scause\sthe\sdatabase\sfile\sto\sbe\sread\sinto\smemory\nand\saccessed\susing\sthe\ssqlite3_deserialize()\sAPI.\s\sThis\ssimplifies\srunning\s\ntests\son\sa\sdatabase\swithout\srisk\sof\smodifying\sthe\sfile\son\sdisk. -D 2018-10-30T13:19:49.896 +C In\sthe\sCLI,\swhen\sopening\sa\sfile\sthat\sbegins\swith\sthe\snormal\sSQLite\sprefix,\nopen\sthe\sfile\sas\sa\snormal\sdatabase\seven\sif\sit\shas\sa\sZIP\sfor\sAppendVFS\srecord\nat\sthe\send. +D 2018-10-30T14:36:21.740 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -505,7 +505,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f -F src/shell.c.in ac4a731dac549746242281d0dac44d53b9f2373f4079cb870cb2681f3e719f6b +F src/shell.c.in a1fa74761b1bdeca5d40dcfdf55fd88f5139155e2bdd2c6b3e9e8e359d062a7d F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 147a9429a558cf34c316ab8f87832e97caff55d92df696ab6fd045466c8c663d -R 60676dfd9c16e59bb8febcd06a129176 +P 5e0129ee9afa7c2d707f8ac9e29ef3583c49bb1d0965085c067d58f828ac8cdf +R 483e69e1ee704e97514f1a28385e28f9 U drh -Z 8d1616bb6665374bfbdd3e19d20e8131 +Z a4c51b591abc7bf95f3ada3df5e196d6 diff --git a/manifest.uuid b/manifest.uuid index 0f7ca93aba..59244856d3 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -5e0129ee9afa7c2d707f8ac9e29ef3583c49bb1d0965085c067d58f828ac8cdf \ No newline at end of file +7989bbda70a24611c3b8af96a53114bb53d87a2e1145ec7ad4f1b4cbf8d6040c \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 73a649410d..3ec31f83da 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3675,6 +3675,11 @@ int deduceDatabaseType(const char *zName, int dfltZip){ return SHELL_OPEN_NORMAL; } } + n = fread(zBuf, 16, 1, f); + if( n==1 && memcmp(zBuf, "SQLite format 3", 16)==0 ){ + fclose(f); + return SHELL_OPEN_NORMAL; + } fseek(f, -25, SEEK_END); n = fread(zBuf, 25, 1, f); if( n==1 && memcmp(zBuf, "Start-Of-SQLite3-", 17)==0 ){ From ad9bfa5e075731baeb0f3df69466fbe15618fb81 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 15:20:35 +0000 Subject: [PATCH 046/109] Improvements to the -fsanitize=fuzzer based database file fuzzer. (Cherrypick from the rubust-against-damaged-db branch.) FossilOrigin-Name: 3cc01a0eaf54e3d5adf206825cfcab15edf73bd5aea10dfc497efd78071a17d0 --- manifest | 13 +++++++------ manifest.uuid | 2 +- test/dbfuzz2.c | 15 +++++++++++---- 3 files changed, 19 insertions(+), 11 deletions(-) diff --git a/manifest b/manifest index 0eca201021..01be0dac68 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C In\sthe\sCLI,\swhen\sopening\sa\sfile\sthat\sbegins\swith\sthe\snormal\sSQLite\sprefix,\nopen\sthe\sfile\sas\sa\snormal\sdatabase\seven\sif\sit\shas\sa\sZIP\sfor\sAppendVFS\srecord\nat\sthe\send. -D 2018-10-30T14:36:21.740 +C Improvements\sto\sthe\s-fsanitize=fuzzer\sbased\sdatabase\sfile\sfuzzer.\n(Cherrypick\sfrom\sthe\srubust-against-damaged-db\sbranch.) +D 2018-10-30T15:20:35.806 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -771,7 +771,7 @@ F test/date.test 9b73bbeb1b82d9c1f44dec5cf563bf7da58d2373 F test/date2.test 74c234bece1b016e94dd4ef9c8cc7a199a8806c0e2291cab7ba64bace6350b10 F test/dbfuzz.c 73047c920d6210e5912c87cdffd9a1c281d4252e F test/dbfuzz2-seed1.db e6225c6f3d7b63f9c5b6867146a5f329d997ab105bee64644dc2b3a2f2aebaee -F test/dbfuzz2.c fae8599108dbf6460f8862677a22ee517c9030cdd931df0ed3c66c09ab14e46a +F test/dbfuzz2.c 652f85bac1770e927da139db513234a3eba308f72ac2f8b32f0093d7d19def70 F test/dbpage.test dbf50a4d361f9e45a979432c727506065113124478a7d2db12074fa655e65d6c F test/dbstatus.test cd83aa623b8aab477269bc94cf8aa90c1e195a144561dd04a1620770aaa8524e F test/dbstatus2.test f5fe0afed3fa45e57cfa70d1147606c20d2ba23feac78e9a172f2fe8ab5b78ef @@ -1774,7 +1774,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 5e0129ee9afa7c2d707f8ac9e29ef3583c49bb1d0965085c067d58f828ac8cdf -R 483e69e1ee704e97514f1a28385e28f9 +P 7989bbda70a24611c3b8af96a53114bb53d87a2e1145ec7ad4f1b4cbf8d6040c +Q +585c94db09d21ce5c5275537014ba5cfe75d4df9274d6fd8d07f754e4aa2c640 +R 3505f0f95a3c0f6a209b5970a7392158 U drh -Z a4c51b591abc7bf95f3ada3df5e196d6 +Z 0539ca60fda1fb5b50f26b7720439a51 diff --git a/manifest.uuid b/manifest.uuid index 59244856d3..c3b795d486 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -7989bbda70a24611c3b8af96a53114bb53d87a2e1145ec7ad4f1b4cbf8d6040c \ No newline at end of file +3cc01a0eaf54e3d5adf206825cfcab15edf73bd5aea10dfc497efd78071a17d0 \ No newline at end of file diff --git a/test/dbfuzz2.c b/test/dbfuzz2.c index 27be2b5259..0833f03868 100644 --- a/test/dbfuzz2.c +++ b/test/dbfuzz2.c @@ -78,9 +78,9 @@ int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ printf("************** nByte=%d ***************\n", (int)nByte); fflush(stdout); } - rc = sqlite3_open(":memory:", &db); + rc = sqlite3_open(0, &db); if( rc ) return 1; - a = sqlite3_malloc64(nByte); + a = sqlite3_malloc64(nByte+1); if( a==0 ) return 1; memcpy(a, aData, nByte); sqlite3_deserialize(db, "main", a, nByte, nByte, @@ -93,9 +93,16 @@ int LLVMFuzzerTestOneInput(const uint8_t *aData, size_t nByte){ } sqlite3_exec(db, azSql[i], 0, 0, 0); } - sqlite3_close(db); + rc = sqlite3_close(db); + if( rc!=SQLITE_OK ){ + fprintf(stdout, "sqlite3_close() returns %d\n", rc); + } if( sqlite3_memory_used()!=0 ){ - fprintf(stderr,"Memory leak: %lld bytes\n", sqlite3_memory_used()); + int nAlloc = 0; + int nNotUsed = 0; + sqlite3_status(SQLITE_STATUS_MALLOC_COUNT, &nAlloc, &nNotUsed, 0); + fprintf(stderr,"Memory leak: %lld bytes in %d allocations\n", + sqlite3_memory_used(), nAlloc); exit(1); } return 0; From a751f39c3fb8f9abd162b44c6d754142f232f1dd Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 15:31:22 +0000 Subject: [PATCH 047/109] Modify the CLI so that the --deserialize option is only available if it is compiled with SQLITE_ENABLE_DESERIALIZE. DESERIALIZE is now off by default for the main.mk makefile, but on for Makefile.in and Makefile.msc. FossilOrigin-Name: 90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 --- main.mk | 1 - manifest | 15 +++++++-------- manifest.uuid | 2 +- src/shell.c.in | 13 ++++++++++++- 4 files changed, 20 insertions(+), 11 deletions(-) diff --git a/main.mk b/main.mk index 884b46993b..1df68076c1 100644 --- a/main.mk +++ b/main.mk @@ -523,7 +523,6 @@ SHELL_OPT += -DSQLITE_ENABLE_STMTVTAB SHELL_OPT += -DSQLITE_ENABLE_DBPAGE_VTAB SHELL_OPT += -DSQLITE_ENABLE_DBSTAT_VTAB SHELL_OPT += -DSQLITE_ENABLE_OFFSET_SQL_FUNC -SHELL_OPT += -DSQLITE_ENABLE_DESERIALIZE SHELL_OPT += -DSQLITE_INTROSPECTION_PRAGMAS FUZZERSHELL_OPT = -DSQLITE_ENABLE_JSON1 FUZZCHECK_OPT = -DSQLITE_ENABLE_JSON1 -DSQLITE_ENABLE_MEMSYS5 diff --git a/manifest b/manifest index 01be0dac68..55e6767789 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Improvements\sto\sthe\s-fsanitize=fuzzer\sbased\sdatabase\sfile\sfuzzer.\n(Cherrypick\sfrom\sthe\srubust-against-damaged-db\sbranch.) -D 2018-10-30T15:20:35.806 +C Modify\sthe\sCLI\sso\sthat\sthe\s--deserialize\soption\sis\sonly\savailable\sif\sit\sis\ncompiled\swith\sSQLITE_ENABLE_DESERIALIZE.\s\sDESERIALIZE\sis\snow\soff\sby\sdefault\nfor\sthe\smain.mk\smakefile,\sbut\son\sfor\sMakefile.in\sand\sMakefile.msc. +D 2018-10-30T15:31:22.400 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -426,7 +426,7 @@ F ext/userauth/userauth.c f81aa5a3ecacf406f170c62a144405858f6f6de51dbdc0920134e6 F install-sh 9d4de14ab9fb0facae2f48780b874848cbf2f895 x F ltmain.sh 3ff0879076df340d2e23ae905484d8c15d5fdea8 F magic.txt 8273bf49ba3b0c8559cb2774495390c31fd61c60 -F main.mk 261a2292823e3c3107515f7a25c73915b3bfa0bda28136d91999e62dfbb2e082 +F main.mk ff82d38126f8f0668b7990e0f1f3dcd74fa2d477c19b2e3feaaba586051e9b48 F mkso.sh fd21c06b063bb16a5d25deea1752c2da6ac3ed83 F mptest/config01.test 3c6adcbc50b991866855f1977ff172eb6d901271 F mptest/config02.test 4415dfe36c48785f751e16e32c20b077c28ae504 @@ -505,7 +505,7 @@ F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 F src/rowset.c d977b011993aaea002cab3e0bb2ce50cf346000dff94e944d547b989f4b1fe93 F src/select.c 61e867a906f140b73baf4ce7a201ad6dcba30820969f5618ee40e9a0d32c6f5f -F src/shell.c.in a1fa74761b1bdeca5d40dcfdf55fd88f5139155e2bdd2c6b3e9e8e359d062a7d +F src/shell.c.in f5a89e43e1b3255fcc274f5185595f547199757e0c59e3ea938af9676e9557d4 F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 @@ -1774,8 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 7989bbda70a24611c3b8af96a53114bb53d87a2e1145ec7ad4f1b4cbf8d6040c -Q +585c94db09d21ce5c5275537014ba5cfe75d4df9274d6fd8d07f754e4aa2c640 -R 3505f0f95a3c0f6a209b5970a7392158 +P 3cc01a0eaf54e3d5adf206825cfcab15edf73bd5aea10dfc497efd78071a17d0 +R 16663463465bb3df141de41e8b146893 U drh -Z 0539ca60fda1fb5b50f26b7720439a51 +Z cc57e679441568ddef0c9613510d7c7c diff --git a/manifest.uuid b/manifest.uuid index c3b795d486..1c5c57d5cc 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -3cc01a0eaf54e3d5adf206825cfcab15edf73bd5aea10dfc497efd78071a17d0 \ No newline at end of file +90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 \ No newline at end of file diff --git a/src/shell.c.in b/src/shell.c.in index 3ec31f83da..4fcd93c01d 100644 --- a/src/shell.c.in +++ b/src/shell.c.in @@ -3434,7 +3434,9 @@ static const char *(azHelp[]) = { ".open ?OPTIONS? ?FILE? Close existing database and reopen FILE", " Options:", " --append Use appendvfs to append database to the end of FILE", +#ifdef SQLITE_ENABLE_DESERIALIZE " --deserialize Load into memory useing sqlite3_deserialize()", +#endif " --new Initialize FILE to an empty database", " --readonly Open FILE readonly", " --zip FILE is a ZIP archive", @@ -3783,7 +3785,9 @@ static void open_db(ShellState *p, int openFlags){ "CREATE VIRTUAL TABLE zip USING zipfile(%Q);", p->zDbFilename); sqlite3_exec(p->db, zSql, 0, 0, 0); sqlite3_free(zSql); - }else if( p->openMode==SHELL_OPEN_DESERIALIZE ){ + } +#ifdef SQLITE_ENABLE_DESERIALIZE + else if( p->openMode==SHELL_OPEN_DESERIALIZE ){ int nData = 0; unsigned char *aData = (unsigned char*)readFile(p->zDbFilename, &nData); int rc = sqlite3_deserialize(p->db, "main", aData, nData, nData, @@ -3793,6 +3797,7 @@ static void open_db(ShellState *p, int openFlags){ utf8_printf(stderr, "Error: sqlite3_deserialize() returns %d\n", rc); } } +#endif } } @@ -6673,8 +6678,10 @@ static int do_meta_command(char *zLine, ShellState *p){ p->openMode = SHELL_OPEN_APPENDVFS; }else if( optionMatch(z, "readonly") ){ p->openMode = SHELL_OPEN_READONLY; +#ifdef SQLITE_ENABLE_DESERIALIZE }else if( optionMatch(z, "deserialize") ){ p->openMode = SHELL_OPEN_DESERIALIZE; +#endif }else if( z[0]=='-' ){ utf8_printf(stderr, "unknown option: %s\n", z); rc = 1; @@ -8643,8 +8650,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; +#ifdef SQLITE_ENABLE_DESERIALIZE }else if( strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; +#endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; #if !defined(SQLITE_OMIT_VIRTUALTABLE) && defined(SQLITE_HAVE_ZLIB) @@ -8740,8 +8749,10 @@ int SQLITE_CDECL wmain(int argc, wchar_t **wargv){ #endif }else if( strcmp(z,"-append")==0 ){ data.openMode = SHELL_OPEN_APPENDVFS; +#ifdef SQLITE_ENABLE_DESERIALIZE }else if( strcmp(z,"-deserialize")==0 ){ data.openMode = SHELL_OPEN_DESERIALIZE; +#endif }else if( strcmp(z,"-readonly")==0 ){ data.openMode = SHELL_OPEN_READONLY; }else if( strcmp(z,"-ascii")==0 ){ From fd748c6460a5ccfc7db0c2f0564d3f78f6845d19 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 16:25:35 +0000 Subject: [PATCH 048/109] Split the SQLITE_WriteSchema flag in two flags, WriteSchema and SQLITE_NoSchemaError. Set only WriteSchema on a VACUUM to avoid problems when trying to vacuum a corrupt database. With this change, the size of the flags field on sqlite3 must grow from 32 to 64 bytes. FossilOrigin-Name: 4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d --- manifest | 20 ++++++++++---------- manifest.uuid | 2 +- src/pragma.c | 2 +- src/pragma.h | 4 ++-- src/prepare.c | 4 ++-- src/sqliteInt.h | 14 ++++++++------ tool/mkpragmatab.tcl | 4 ++-- 7 files changed, 26 insertions(+), 24 deletions(-) diff --git a/manifest b/manifest index 55e6767789..39de619cd5 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Modify\sthe\sCLI\sso\sthat\sthe\s--deserialize\soption\sis\sonly\savailable\sif\sit\sis\ncompiled\swith\sSQLITE_ENABLE_DESERIALIZE.\s\sDESERIALIZE\sis\snow\soff\sby\sdefault\nfor\sthe\smain.mk\smakefile,\sbut\son\sfor\sMakefile.in\sand\sMakefile.msc. -D 2018-10-30T15:31:22.400 +C Split\sthe\sSQLITE_WriteSchema\sflag\sin\stwo\sflags,\sWriteSchema\sand\nSQLITE_NoSchemaError.\s\sSet\sonly\sWriteSchema\son\sa\sVACUUM\sto\savoid\sproblems\nwhen\strying\sto\svacuum\sa\scorrupt\sdatabase.\s\sWith\sthis\schange,\sthe\ssize\nof\sthe\sflags\sfield\son\ssqlite3\smust\sgrow\sfrom\s32\sto\s64\sbytes. +D 2018-10-30T16:25:35.241 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -497,9 +497,9 @@ F src/parse.y 6840fe7c0b5eb4dd25ee5d075213bc8255ed4c0678d71bfb6744d0520d91c179 F src/pcache.c 4196eb6ed3bbf00b80596c8e0b4f50e57eb7d890c19fb27a7354306abb7f983d F src/pcache.h 072f94d29281cffd99e46c1539849f248c4b56ae7684c1f36626797fee375170 F src/pcache1.c 716975564c15eb6679e97f734cec1bfd6c16ac3d4010f05f1f8e509fc7d19880 -F src/pragma.c 35efa85894f1ae533c03c64591dfc82f916ad78250591082bbae72a2811bceab -F src/pragma.h e50df79399da8c2efc6bd4b7034e242d0dc6ab2016564f08e94103367098b1e4 -F src/prepare.c f8e260d940a0e08494c0f30744521b2f832d7263eca9d02b050cea0ba144b097 +F src/pragma.c 0bb05b1788d7af5fdc7f40f5655a79a140dece8fd2523402eb2103925e4739c2 +F src/pragma.h fdd03d78a7497f74a3f652909f945328480089189526841ae829ce7313d98d13 +F src/prepare.c 498b3bf76a508dc201f90c3e619f597630b1870bdce77eef2dbd380542a4a232 F src/printf.c 0f1177cf1dd4d7827bf64d840768514ec76409abecaca9e8b577dbd065150381 F src/random.c 80f5d666f23feb3e6665a6ce04c7197212a88384 F src/resolve.c bc8c79e56439b111e7d9415e44940951f7087e9466c3a9d664558ef0faf31073 @@ -509,7 +509,7 @@ F src/shell.c.in f5a89e43e1b3255fcc274f5185595f547199757e0c59e3ea938af9676e9557d F src/sqlite.h.in 4b4c2f2daeeed4412ba9d81bc78092c69831fe6eda4f0ae5bf951da51a8dccec F src/sqlite3.rc 5121c9e10c3964d5755191c80dd1180c122fc3a8 F src/sqlite3ext.h 305adca1b5da4a33ce2db5bd236935768e951d5651bfe5560ed55cfcdbce6a63 -F src/sqliteInt.h 75d8266b27c287aeada717a541cf7b7543383fccdb1d7d45a5620f666e864c55 +F src/sqliteInt.h 93692315c628c2e7e96a0e82a7edf421b0da8b03f036e0045824d9fe048eae3a F src/sqliteLimit.h 1513bfb7b20378aa0041e7022d04acb73525de35b80b252f1b83fedb4de6a76b F src/status.c 46e7aec11f79dad50965a5ca5fa9de009f7d6bde08be2156f1538a0a296d4d0e F src/table.c b46ad567748f24a326d9de40e5b9659f96ffff34 @@ -1707,7 +1707,7 @@ F tool/mkmsvcmin.tcl cad0c7b54d7dd92bc87d59f36d4cc4f070eb2e625f14159dc2f5c4204e6 F tool/mkopcodec.tcl d1b6362bd3aa80d5520d4d6f3765badf01f6c43c F tool/mkopcodeh.tcl 352a4319c0ad869eb26442bf7c3b015aa15594c21f1cce5a6420dbe999367c21 F tool/mkopts.tcl 680f785fdb09729fd9ac50632413da4eadbdf9071535e3f26d03795828ab07fa -F tool/mkpragmatab.tcl 656e64fc4e8b5d91525bac1e81834de3217507657e846b1a08375ca195fa8479 +F tool/mkpragmatab.tcl a1334e70a08fdf5de32cd0093613212bb11ac8f880487540987175c536ac335f F tool/mkshellc.tcl 1f45770aea226ac093a9c72f718efbb88a2a2833409ec2e1c4cecae4202626f5 F tool/mksourceid.c d458f9004c837bee87a6382228ac20d3eae3c49ea3b0a5aace936f8b60748d3b F tool/mkspeedsql.tcl a1a334d288f7adfe6e996f2e712becf076745c97 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 3cc01a0eaf54e3d5adf206825cfcab15edf73bd5aea10dfc497efd78071a17d0 -R 16663463465bb3df141de41e8b146893 +P 90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 +R debb9c0d1e782e1821ad97f71be70e84 U drh -Z cc57e679441568ddef0c9613510d7c7c +Z 85000e55a119438a8ba57afecbd7a3a5 diff --git a/manifest.uuid b/manifest.uuid index 1c5c57d5cc..4e4d0bdd96 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 \ No newline at end of file +4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d \ No newline at end of file diff --git a/src/pragma.c b/src/pragma.c index c3c62a722c..52d6338ca0 100644 --- a/src/pragma.c +++ b/src/pragma.c @@ -1037,7 +1037,7 @@ void sqlite3Pragma( setPragmaResultColumnNames(v, pPragma); returnSingleInt(v, (db->flags & pPragma->iArg)!=0 ); }else{ - int mask = pPragma->iArg; /* Mask of bits to set or clear. */ + u64 mask = pPragma->iArg; /* Mask of bits to set or clear. */ if( db->autoCommit==0 ){ /* Foreign key support may not be enabled or disabled while not ** in auto-commit mode. */ diff --git a/src/pragma.h b/src/pragma.h index 93e7116f0e..b1d4155ef2 100644 --- a/src/pragma.h +++ b/src/pragma.h @@ -127,7 +127,7 @@ typedef struct PragmaName { u8 mPragFlg; /* Zero or more PragFlg_XXX values */ u8 iPragCName; /* Start of column names in pragCName[] */ u8 nPragCName; /* Num of col names. 0 means use pragma name */ - u32 iArg; /* Extra argument */ + u64 iArg; /* Extra argument */ } PragmaName; static const PragmaName aPragmaName[] = { #if defined(SQLITE_HAS_CODEC) || defined(SQLITE_ENABLE_CEROD) @@ -663,7 +663,7 @@ static const PragmaName aPragmaName[] = { /* ePragTyp: */ PragTyp_FLAG, /* ePragFlg: */ PragFlg_Result0|PragFlg_NoColumns1, /* ColNames: */ 0, 0, - /* iArg: */ SQLITE_WriteSchema }, + /* iArg: */ SQLITE_WriteSchema|SQLITE_NoSchemaError }, #endif }; /* Number of pragmas: 62 on by default, 81 total. */ diff --git a/src/prepare.c b/src/prepare.c index 602e4dc49d..f7e829acb5 100644 --- a/src/prepare.c +++ b/src/prepare.c @@ -327,8 +327,8 @@ int sqlite3InitOne(sqlite3 *db, int iDb, char **pzErrMsg, u32 mFlags){ rc = SQLITE_NOMEM_BKPT; sqlite3ResetAllSchemasOfConnection(db); } - if( rc==SQLITE_OK || (db->flags&SQLITE_WriteSchema)){ - /* Black magic: If the SQLITE_WriteSchema flag is set, then consider + if( rc==SQLITE_OK || (db->flags&SQLITE_NoSchemaError)){ + /* Black magic: If the SQLITE_NoSchemaError flag is set, then consider ** the schema loaded, even if errors occurred. In this situation the ** current sqlite3_prepare() operation will fail, but the following one ** will attempt to compile the supplied statement against whatever subset diff --git a/src/sqliteInt.h b/src/sqliteInt.h index f0ed023c6d..c8a6fe90e2 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -1371,7 +1371,7 @@ struct sqlite3 { Db *aDb; /* All backends */ int nDb; /* Number of backends currently in use */ u32 mDbFlags; /* flags recording internal state */ - u32 flags; /* flags settable by pragmas. See below */ + u64 flags; /* flags settable by pragmas. See below */ i64 lastRowid; /* ROWID of most recent insert (see above) */ i64 szMmap; /* Default mmap_size setting */ u32 nSchemaLock; /* Do not reset the schema when non-zero */ @@ -1537,14 +1537,16 @@ struct sqlite3 { #define SQLITE_TriggerEQP 0x01000000 /* Show trigger EXPLAIN QUERY PLAN */ #define SQLITE_ResetDatabase 0x02000000 /* Reset the database */ #define SQLITE_LegacyAlter 0x04000000 /* Legacy ALTER TABLE behaviour */ +#define SQLITE_NoSchemaError 0x08000000 /* Do not report schema parse errors*/ /* Flags used only if debugging */ +#define HI(X) ((u64)(X)<<32) #ifdef SQLITE_DEBUG -#define SQLITE_SqlTrace 0x08000000 /* Debug print SQL as it executes */ -#define SQLITE_VdbeListing 0x10000000 /* Debug listings of VDBE programs */ -#define SQLITE_VdbeTrace 0x20000000 /* True to trace VDBE execution */ -#define SQLITE_VdbeAddopTrace 0x40000000 /* Trace sqlite3VdbeAddOp() calls */ -#define SQLITE_VdbeEQP 0x80000000 /* Debug EXPLAIN QUERY PLAN */ +#define SQLITE_SqlTrace HI(0x0001) /* Debug print SQL as it executes */ +#define SQLITE_VdbeListing HI(0x0002) /* Debug listings of VDBE progs */ +#define SQLITE_VdbeTrace HI(0x0004) /* True to trace VDBE execution */ +#define SQLITE_VdbeAddopTrace HI(0x0008) /* Trace sqlite3VdbeAddOp() calls */ +#define SQLITE_VdbeEQP HI(0x0010) /* Debug EXPLAIN QUERY PLAN */ #endif /* diff --git a/tool/mkpragmatab.tcl b/tool/mkpragmatab.tcl index 63fe7ce8e4..5b1f2eea93 100644 --- a/tool/mkpragmatab.tcl +++ b/tool/mkpragmatab.tcl @@ -120,7 +120,7 @@ set pragma_def { NAME: writable_schema TYPE: FLAG - ARG: SQLITE_WriteSchema + ARG: SQLITE_WriteSchema|SQLITE_NoSchemaError IF: !defined(SQLITE_OMIT_FLAG_PRAGMAS) NAME: read_uncommitted @@ -579,7 +579,7 @@ puts $fd " u8 mPragFlg; /* Zero or more PragFlg_XXX values */" puts $fd { u8 iPragCName; /* Start of column names in pragCName[] */} puts $fd " u8 nPragCName; \ /* Num of col names. 0 means use pragma name */" -puts $fd " u32 iArg; /* Extra argument */" +puts $fd " u64 iArg; /* Extra argument */" puts $fd "\175 PragmaName;" puts $fd "static const PragmaName aPragmaName\[\] = \173" From b74cf4b6ea8553aee6f253b08db810d0f1974e49 Mon Sep 17 00:00:00 2001 From: dan Date: Tue, 30 Oct 2018 19:14:16 +0000 Subject: [PATCH 049/109] Update comments in sqlite3session.c to describe the format of "rebase blobs", as well as changesets and patchsets. FossilOrigin-Name: bf93f7b56b1d15682988daf3f1c293caf755433defdecd52ba8782fc40e92bd7 --- ext/session/sqlite3session.c | 36 ++++++++++++++++++++++++++++++++++++ manifest | 14 +++++++------- manifest.uuid | 2 +- 3 files changed, 44 insertions(+), 8 deletions(-) diff --git a/ext/session/sqlite3session.c b/ext/session/sqlite3session.c index 465af8d6e1..df4323f3bd 100644 --- a/ext/session/sqlite3session.c +++ b/ext/session/sqlite3session.c @@ -246,6 +246,42 @@ struct SessionTable { ** The records associated with INSERT changes are in the same format as for ** changesets. It is not possible for a record associated with an INSERT ** change to contain a field set to "undefined". +** +** REBASE BLOB FORMAT: +** +** A rebase blob may be output by sqlite3changeset_apply_v2() and its +** streaming equivalent for use with the sqlite3_rebaser APIs to rebase +** existing changesets. A rebase blob contains one entry for each conflict +** resolved using either the OMIT or REPLACE strategies within the apply_v2() +** call. +** +** The format used for a rebase blob is very similar to that used for +** changesets. All entries related to a single table are grouped together. +** +** Each group of entries begins with a table header in changeset format: +** +** 1 byte: Constant 0x54 (capital 'T') +** Varint: Number of columns in the table. +** nCol bytes: 0x01 for PK columns, 0x00 otherwise. +** N bytes: Unqualified table name (encoded using UTF-8). Nul-terminated. +** +** Followed by one or more entries associated with the table. +** +** 1 byte: Either SQLITE_INSERT (0x12), DELETE (0x09). +** 1 byte: Flag. 0x01 for REPLACE, 0x00 for OMIT. +** record: (in the record format defined above). +** +** In a rebase blob, the first field is set to SQLITE_INSERT if the change +** that caused the conflict was an INSERT or UPDATE, or to SQLITE_DELETE if +** it was a DELETE. The second field is set to 0x01 if the conflict +** resolution strategy was REPLACE, or 0x00 if it was OMIT. +** +** If the change that caused the conflict was a DELETE, then the single +** record is a copy of the old.* record from the original changeset. If it +** was an INSERT, then the single record is a copy of the new.* record. If +** the conflicting change was an UPDATE, then the single record is a copy +** of the new.* record with the PK fields filled in based on the original +** old.* record. */ /* diff --git a/manifest b/manifest index 39de619cd5..1e5c72be28 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Split\sthe\sSQLITE_WriteSchema\sflag\sin\stwo\sflags,\sWriteSchema\sand\nSQLITE_NoSchemaError.\s\sSet\sonly\sWriteSchema\son\sa\sVACUUM\sto\savoid\sproblems\nwhen\strying\sto\svacuum\sa\scorrupt\sdatabase.\s\sWith\sthis\schange,\sthe\ssize\nof\sthe\sflags\sfield\son\ssqlite3\smust\sgrow\sfrom\s32\sto\s64\sbytes. -D 2018-10-30T16:25:35.241 +C Update\scomments\sin\ssqlite3session.c\sto\sdescribe\sthe\sformat\sof\s"rebase\sblobs",\nas\swell\sas\schangesets\sand\spatchsets. +D 2018-10-30T19:14:16.577 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -417,7 +417,7 @@ F ext/session/sessioninvert.test ae1a003a9ab1f8d64227dbb5c3a4c97e65b561b01e7b295 F ext/session/sessionrebase.test 4e1bcfd26fd8ed8ac571746f56cceeb45184f4d65490ea0d405227cfc8a9cba8 F ext/session/sessionstat1.test 41cd97c2e48619a41cdf8ae749e1b25f34719de638689221aa43971be693bf4e F ext/session/sessionwor.test 2f3744236dc8b170a695b7d8ddc8c743c7e79fdc -F ext/session/sqlite3session.c 8772d3cb9124a14f85c7c9ca2bc4931f1180ee99acf5386bdfdd6892455b2443 +F ext/session/sqlite3session.c dbd6f7a89c1236d8e7b58f4e217391670ce91b9e6f85c16ba02832674ef0cf3c F ext/session/sqlite3session.h 05351d2f50a1203fdffbeb590fdbbc796c9a6bfcd0c9b26cf6db3854e3eb4294 F ext/session/test_session.c 98797aba475a799376c9a42214f2d1debf2d0c3cb657d9c8bbf4f70bf3fb4aec F ext/userauth/sqlite3userauth.h 7f3ea8c4686db8e40b0a0e7a8e0b00fac13aa7a3 @@ -1774,7 +1774,7 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 -R debb9c0d1e782e1821ad97f71be70e84 -U drh -Z 85000e55a119438a8ba57afecbd7a3a5 +P 4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d +R 622ca62823c1f2dbd276de64ff12f603 +U dan +Z 735b392b2384d31c91535992371336a6 diff --git a/manifest.uuid b/manifest.uuid index 4e4d0bdd96..995f71869d 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d \ No newline at end of file +bf93f7b56b1d15682988daf3f1c293caf755433defdecd52ba8782fc40e92bd7 \ No newline at end of file From c985c2822c27caf92fe099581922109fc662eef9 Mon Sep 17 00:00:00 2001 From: drh Date: Tue, 30 Oct 2018 23:45:18 +0000 Subject: [PATCH 050/109] Add new fuzzer cases generated by dbfuzz2. FossilOrigin-Name: 79fdad8b42869100845eed36224602452486d0166c18cec7d343040fdac7379e --- manifest | 14 +++++++++----- manifest.uuid | 2 +- test/fuzzdata7.db | Bin 0 -> 11921408 bytes 3 files changed, 10 insertions(+), 6 deletions(-) create mode 100644 test/fuzzdata7.db diff --git a/manifest b/manifest index 39de619cd5..9dd998ff47 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Split\sthe\sSQLITE_WriteSchema\sflag\sin\stwo\sflags,\sWriteSchema\sand\nSQLITE_NoSchemaError.\s\sSet\sonly\sWriteSchema\son\sa\sVACUUM\sto\savoid\sproblems\nwhen\strying\sto\svacuum\sa\scorrupt\sdatabase.\s\sWith\sthis\schange,\sthe\ssize\nof\sthe\sflags\sfield\son\ssqlite3\smust\sgrow\sfrom\s32\sto\s64\sbytes. -D 2018-10-30T16:25:35.241 +C Add\snew\sfuzzer\scases\sgenerated\sby\sdbfuzz2. +D 2018-10-30T23:45:18.226 F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea F Makefile.in 64113b9c489de88bf5ea29d7426fa3f63938ee5f5e4a4fea1f6e62a25efba177 @@ -974,6 +974,7 @@ F test/fuzzdata3.db c6586d3e3cef0fbc18108f9bb649aa77bfc38aba F test/fuzzdata4.db b502c7d5498261715812dd8b3c2005bad08b3a26e6489414bd13926cd3e42ed2 F test/fuzzdata5.db e35f64af17ec48926481cfaf3b3855e436bd40d1cfe2d59a9474cb4b748a52a5 F test/fuzzdata6.db 92a80e4afc172c24f662a10a612d188fb272de4a9bd19e017927c95f737de6d7 +F test/fuzzdata7.db 829cbab68b8fa5223405f4bf0d4775b05391a8ff670790d09154a56dd22a8d1e F test/fuzzer1.test 3d4c4b7e547aba5e5511a2991e3e3d07166cfbb8 F test/fuzzer2.test a85ef814ce071293bce1ad8dffa217cbbaad4c14 F test/fuzzerfault.test 8792cd77fd5bce765b05d0c8e01b9edcf8af8536 @@ -1774,7 +1775,10 @@ F vsixtest/vsixtest.tcl 6a9a6ab600c25a91a7acc6293828957a386a8a93 F vsixtest/vsixtest.vcxproj.data 2ed517e100c66dc455b492e1a33350c1b20fbcdc F vsixtest/vsixtest.vcxproj.filters 37e51ffedcdb064aad6ff33b6148725226cd608e F vsixtest/vsixtest_TemporaryKey.pfx e5b1b036facdb453873e7084e1cae9102ccc67a0 -P 90b2a684f775e1468d63bf950119cf0aaa62b5a449f518e7cc513c314191dd14 -R debb9c0d1e782e1821ad97f71be70e84 +P 4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d +R 206d8a672b40f957971261af94210d6c +T *branch * dbfuzz2-cases +T *sym-dbfuzz2-cases * +T -sym-trunk * U drh -Z 85000e55a119438a8ba57afecbd7a3a5 +Z 02bd651f11adbad60f04ab1db942521b diff --git a/manifest.uuid b/manifest.uuid index 4e4d0bdd96..3e3384e301 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -4f9878107a54356b7105fa1db7655ee239685d570436f6ad4d4221c9bd829b3d \ No newline at end of file +79fdad8b42869100845eed36224602452486d0166c18cec7d343040fdac7379e \ No newline at end of file diff --git a/test/fuzzdata7.db b/test/fuzzdata7.db new file mode 100644 index 0000000000000000000000000000000000000000..21078b73783c848e2f3396216ab5163e7c9b89d8 GIT binary patch literal 11921408 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%0Ap}R}f_%Ah3djH!G8q7A8b(GUlaXD1U7Jim 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

;H=v^%o~A_ zxrl!XR4-;q4S~q)8?;y?H|7rzFOAY1ANqRLZT@MNj#M6FTnimftzRo!_K!k19D(8t z^nasq6ln6W0XTs+`(rmi58T-RLM%u2q}YG}&C6aEBdBcH(Y4@n3@oyYb<8g==^BNk zs)d4~!C|SSD2Ji;G}bNcEWMcI(Qw1N#3O**w0O*e)rj15Fr2z0mr!mx*Zw~q@ zF?x)Z*N)XrRmmrs zX(o4!n50|mn)pBNI1ros58wZD>OA(^NXr1H%wwZ9-Gk7%yp%~ETV_faZ;IABAv|{5 z`hPf^HX5CBewR=KT(`OmCpU)j&0`;x9B{cT86Rc=WVP}COe!jnt>FJpKMgxU34F9q z%dn630AHBA>>nVXtp>DKAX*mYK4_f>Xe~#y0-|*`jIRll|1Gp|FFgWzmH*ZA5B*#! z;2Up_RxQf^(Qu1&7majRH{66GL#C;W@_(ku$GP$NFmndfsW_Yb5B&dIkpFjr3C~H1 zKq&tI#1d7QhHHY-XNm;Y{CSw(PBXYhN0O8<)}p)thM%-CAX@q-YS0ib;V5 zgK8y8m6B-#B1yk-1EGeQ(m)_T!dx2YC0VDtv;y9c)}w70!UD`C*;g#v4*}Hw`ys^P zdZ+&X0uE)m6%jxRiDZ39IqU$2_HrY5UeCu8JEV3yGS+5_W@(EZ7EjXLA5w=8#g0r3 zBk#td;OLD{=C8Vo9ndxF(MGXDB%NdN{!5ENoQU#2@c$R*UNl4jr+uWPcZ>o~WkI1}7}ivEOG!5;UV%uPrLj4^0U@$x{sPWX zU|l?1)p{Yd%n_yr*8I7+pc#-liERQSalPp%*DJ|ikjvn~ z?0};3XCnXN*Kn#Rn)$T1#A;VBKQq*yx0fHkhGndz96h(!b4}^d z(I_^Y^dfod@ozU9B9t6U*q?jazPh$jCD$(%=U3GTt^7ubZ4*NQ-PYV;&C!*{9JQc5 z;;4*WJ~3WCbJgkNYszdjn)2DJVBfcXaI(Ko(^;Ihlj~#}sf?(0@4^wtH9a^rxS_vK zY0o)S87|m!n&p`}kD+GHW%V+LA_UIa z&5AFC6)diP+DlRSJ^vv8zqd8Wg3KmvTa3e6{~!k+X;{l_1pf5Ki@)(f8JRY}CnJeF z5VS}T{Ydz`*tX73$mczJH+}95_b%>Zi`b<}_!fgQoH*NYq9b(1R>#xwo_sBzre%1! zD)_F1ni_+zFG74iTRC}s1%EUeb_jOE)~U^=*NV+IDR@csoRQRqVJq>;ALt8MpY2F%sn5K7q2N=*N!kXwoJ2H41#_8e9_TP637whvVs&Dm24y>DxIm?zu1 z&E@03RHLxSn>490hFvFg@@EQy<8DmvIjXh_Xmv*LdkE61cR>$5wLa@Mt{4&lccTK& z&ii3}b0kEj7JfxeIyf6-y#`%gmKNRH-^JD~Y3$oS_)`_X-~!#N2rxd726cGUnP){n zxY3)o7K;ZpBYeKBYQ2OvD^GX4wXELy?@|6o`TtETH&v#}8@52$S&sqZ=E05fzXxdE zm*kQEf&ah4yRA98>hFA2oSQ5UDgW2;Topsn;SHSzNDUpsaKMR8 z`E;EH;JZr4VEkzsLoGs`A*08kj=>M(cK=7eym(!51fmH4Ao#Oh;aq#kX)9y%Q238b z6KiU2ZDDG~>37XhMl1HERVpyqnd+I1IARctY;#>*>K zR@`D#B_AxpY-!oGy+J)#IR^TIl`}Mr(o)7(U5NU;x{`vtrgaI7`mG;u1QveV?>Rr% zJ6xe_2>m&9$(* z)_`SGU9#cQT>r1W2%u44wz{#Pp5;GiEmv*rOFGzMC{GA1Mj~B{$I}`xl9oH3@q&WFuk4LMt9OJa6;OYG%hF)NlW^C zHB5?km~lf3RFsKeDReV*k|_$IJk%N*K1cbHhk`Eano{%wA38W){*}{7JQo@PobwVI zG66T33&n?udFNtC7tq!us_^$=vs8F(5p0|O|8@W0`-w75?@yw2SY~nv+&EZUqmoZ$ zFnX79)9y;`Eh@R^BGiX)8Xu8l3FA7D|3Aj51^kPN)F;$s)K$A|O%Sl-^0w_x)PsYG zw(W9PO=Vxy9nkgotB0|NcD&qJ?i$Vh{NG`jFY%%HJ&@`>p1lX3r~Pl3tp(j?|6|1M zq08zo^`Xj;(r^TtSiS;Q3at$FtsPv~&x8b(K1yK1#qa2k;J`C=zN*WW;lA~QlY>)( z8~Tr-dM~UE!L>fm#^A-c2;lP{7s0sqC;9xF_J8tg!v4A-U8mLFs*=42pxDWY*iwDk zIrXWdn9P}*gNkS%``--zKi<(_{238}=CiQbR7WoW&&c#vHHz4W%-?47Zq0ya>wxD> zSpnoQW}%XA%}oNT#wr{UKs%!&EGeJlW@j|0}zUohp<^&1<2RPz!B8+9gc>Ub^!;3Os&m77dsP`?YJv%*IRh#oGkN~TiuXwBxVoS5FWr>N z0Xr+7j>y;>u<7~A)}bf*Ma9A6|Nodm*w~_a&zn-)A@$#4XF!M16U`?}24#AwhgnbX zs1e5*#slfUwRtd!5l!m(di30S6UNTzRz{Tbn>I5hV8naQG%^fPpiT20$4_ktHxzr@ z8!vtP$uPexWuFEyxIL?2*q$KA+n#3=^I)Xr<+V8696bsq*=54L3gJb|n|*k^OlXvB! zC;w;n;@Ue^a`&pN)5K#ugt!z?d?HUB*ht@4bc#krbB=gGi&P7^dCJtfa0_#Jej)4bEt{vILiO|u@IvC-}%IJ z_yJj$6Y>-^K4(=BcOOvtv56ZlYG9nC6PFlxe{=*K^?_0v@1pmyd8hID=Am>49pc7D zr%5{XMrUu5j&xu*8?ztJZT`srr}1nd{~rZ)FNp3I$_XeZh#qr^)Rzl6!T4e#*a$5&h@6ns zU|vFj3{@G*38CO>WJWn53Th(mi7F@bc8Q!If(BSeSOntn|7`w`PEI9-cPjTQN6=~V z1^5v>%^p_U00Fc|10Gwy>Hu9v!ncS8%; zN!`LbpoMFtZsA|SQ*~$X$DL13l>brw=QEO0E+rrG|6M7g$f5ci$^UDAy(m~jSPrno zECS{KC;+1T9|biL_n`bQ0%fd&F9Px8f8hV`;oBbn(vbg0{@;I;WFSXA`2Tw|fV58& zk^lDrD3Qy^|3`r}3jbdof%SkXC1d3>R5>61voJkYD#Ahg1dbr`V>8GVD@3O{p-<3# zbT!>Z2jGWPDK&PX?(uh69SmzywqdT-tg5=XR}{^Z8oI(yP^wXZjcFhdoB#ikXed*A zpew_D>jx+M`?U7uTt_M+sy$ro2;`a`%=N;rqDh|5`trg52U@yCZUV~A|9?&?7*s1! zT2jmfox&{UDKGNK|3{%s6#hR-J$O%81W^AU7BS49J_51%|G(zd2juHfug_~NrCLrd z`1+s-8utgy*~q7b%pW6r5Wc=%e1_wH1yR?=z%cx+$k&I*j1c7Oqo5Z29-RLl9IJ3S z;RV!gJ_>hpc5|mcptxWcoB#i6qzNKi+8($N6fLqPT1dT;N#IeJKt}mQ3*&1EbW{E! zJ4B0LIE5C@YRG`5b4Ml|JC@d0pBRm^Y^VhB;$@x5DgIG}k9BWP4;>0a*UE@)Ur=Ub zx_tJkvIKMuu?}Rvxtbzxf7qcN^;2kd z%a$S!rEZs@?8pkFDs{UwG=bu3{{2{drs6r*~XY7d(bVK0^{#(Sor)vkpM*kpCOWs z%Z|@{H;M$tKcq`A6bZ!Pk0ODEbrwYe>YW5uHpY5;eepDML3eS z8`-=xDTFMZIP^oZcwqngmfi7H8pr#D*_|A!I?<6y+;iqv6OLXBA!OE(S+~XlhrJ_5 z*DcIC2mI_sF#kUak;UP!JJT)isl8hze|I}BI)ntKd za^k+;&g z5LomBXgmZ;8;`^PC$h2rN5%}*66hyz4JP^{Sd7Ux0_H7Fu6>>Bnl<|8{fRq7Nn_v{m4LVi%Mn?J#*k$=&h}+yT}i{ zG+ZJ_`_>Omn=zC76f$$SO3>jSL?dt%2!I<<9b^WtDne-PiUhFbt=XeqdWv5lfo zSWOf*Fk*kiaQ{6_{Y}@iyYgB#LV|c9zo>y0Mz!u3HhKJsZm0=U)%btGD)10m`}w`9 zD#6@P!Ewp5Ld|hQ1?N`A)u0I~7+v$23tdoUrD{mQ2nAMI2`PQM*f*d^AB4zOPd)cE z1(&oR)5qu|a3W{PC@Q_?N7FDG2lI5ruzWM-X{}=y{{P>Q|IgWw$WwQa|4*2j#!rG( zfc$?joG@4V2+Sh|`1bE)y0?euZ|VK?hxD`HjQ*|kTh{F@K>okmM}VmQBmd8k_T&E< zN;)YML}L zjrQM%=@zOp{PDybDIp-AI>Y!`N>HR*Evhrp#UE=AjsU7Nf@38%C#o~%;_W2ejE$Ac zkaIr#H|lp>+t?Ge{@dIJS%gNyb=wYZ>q4YMuug`#@8K|+{qh>W@XOJDy^RrX_vdWS zg2zq>)EPgOd3KuC+654cZ%&9koO$I09mjJXTpve&+kj4N(66Qw8=+6oeRMV5MhB?Q zvBUmF8Nc+;)9wV{{@9O~Czh{R2`e^?_D%N>=z8yh9(rmTZrmdYyKz4n$c;MykeDT1 z1mu&y)5RmT+NFIHcSf~Ecj5%bhzlFpCEt?-01Z;4i~rw$WlR6>!hZw-U~ZnVxu+67 z!$Pi#O<8b;&q5o;QcYNG#*;#-YPw@QN1vuo<<}is2$+dga{1hpSY2`#99gq_TrcGn zF!4^gA!@d6PxA;5q9TCr$Ee7Oyl?L7k>44we#D*R<59NpE9Cz@;Ng7<`F|%wk^gr> zMaVhh*Iw1&XUPklM6ZPiOX=_tO0;S67M^Lg{Z{8B7;WU{;{%Sb&G;BPmGFoCPG_T@ zb9ilXJLT1;1i5*yYMrkcPa*&Bj7%bDk^gss75RTBRD_%}e(O~Ye#pGgN%R`>{}JGo ziT{U%nA1omYEDkrq~(O&bi-~y%)UxFaKv^RFj;jq8L12xPCIve`9#wxW*D3tC(T&3 z$51m??J^dtc70{2l4c~-2##E>#!qFh@z$#7jlEO+U8iAaI~RQM_2z9Xpx3RpHh=Ou zVBdF2-bmPA?6mz=wfCvyx^+G;A8Y0ZtFNnHJkbCji*{R#yQ0Y~i_%CjdPy9GkiZ3U z(;PSy$QTS*sKaB+?UYv&;ywTD`>&9<5#?*J z;hV0xp!R;1)J{ikfZ^&dhFrpT2G!{B`pNRytI8EqZ0PUP+LyN&sf?(0;X;xbRGlkf zv<*oo_w|`&wP}^yycx$>urbyKCp$F$2mU|PJ}`o;zfoTyC0(hrqa*k;DFmWVn6uWC zz6~O8ZlM!NHLx4Xji6%*pr&A22zdT~-`m^U@>mYG{sw?MOxmOg;ytDC+P>qdhW#NSe zwPF`E?%Gex+`y%2Y6;!}Yz*K#fPo-e3Z+zeA*#m>`v#cnZ`3Dz{ZiBd96#ZfV$jVl zZH)$%wqn#6;8rIAicyIwD+v5yLIffpuxFt50hQc~>z$g|30Lz}qN{m;_kSAxKNo@M z-FXYj!V=IuIa#2;cQ$@MWF8V8jk^$-T7PEskSkCh__}D0XP4DgBjiPyxIp?+nRnB1uV)&Hat>DI!th5sr1s_=`# zPYORQe82GB!Z!;K6~0>dQsK_RUlu-F*j>1}a9yEV_)y`B!q&nig?ASw3-2tfDV$qa zSvW&^LU~O2j`H`)gUbENy~;l2cIDH`CzM&`CgoaXn{u`C0i~jBRyHc@l(#FZm2;G{ zl+%?{loOO;Wl%X*DJw@PhbRXqMMa^{!vbNyq5nz$1JoWrpx>k4qTiqo(67+D=@;nd z=%?sjm`{EKouSvzE9o@7lwL$P6vhfC7Dfw83Vns63yTVe77i-RgSXua%I}rmDo-ju zQ+{0dB)x#1PbcUq`g*#8o{-2tE{r1dRu>I!D>tOqLGiSi|8#AZF_Tib+VEfPv%-t$}eP%gqzdUm)Z10&l z3AT64ycV|mW+0?S@e4Drf$d++oB-QDpIHXmy)(nG-7~Wkw!3Fu1>2o7OJIBR%qwC0 zv6)xE_S%^N*j8tbgYAcB0GZ+kW&n-i)|r>V_Tm{pptxZM`d&P5=5W}aHnRY>ubF}V z7KdkE1luJu5XH1OI0GzQ@wgcX{8lW_z>q5*J_A~(;(;@;?0r$IT?t!Sy8?Vs{#d&l zwtuL70Ji^Idp~S{S9>39|Gl;qwm+<00^1+dHpBM+)-HnWw`=c)?bmCYV7spd!`S%q z+6A!PReL*Z|E%^_K>NBKP~o@D7l6OYh&I!1lc}SHbpAW}x=cyJtQK+qcd@ z?WH%*KwYJkGw+4%Yi2Hm?eGlLRXTPC>MFf#25Kqw&P>8~;mlgt_RO#vZ>#}LjgQt= z!*-?yG&Q!>fTqTkHK3;Pz8X-|xUBX@*j`#&3EPb|psew>8qm}@w+3`H-cTEZ?HRRG zVEdXHP|$c~4d_*x-7yc2Us@Z5?cp_`l(Db|lrmma14y0=B@1=x^!$ z^oR7bzyyDbN7WhGruHN^iNEwRrb1MJ;&xmdp=|`r`c(@~d)BQ_Sy?0>`9pAKha%!5%`Y8WL z8a#MYNCf1Y|5aq1MfW9?|GSUoS?zJM@;_K>FhxWlzWk42WFkT@&21?EMmO=J%estf!#z0({ekazZsU7gcAo-QsK!$Pj+##eC# zpOuL&E^^V{YK>SGmsP8r`%dLk^xxe2XIEl*IkAvF#hg`TR(*1X?TUxQ<+X=1#cOjz zUBZHp*OrhdsWd4#pIux?h_&!vb4kBL>Wwbx=GvaHv}eK4;ILFu6t-$;cdnF@3L(3s zQsn<-B{cH?vQkD|yO95HVI7^{@4T~BX3V2_{6EZE&rL!GI5(t>*^%H3aF;W`#lvDE zjkoha02yE&DDo}?nP1+BX0tr83^08TLLfawfB7W+F@20aLLcM@T6ekA@WZWDQYRN5 z{dcR(m`5@Af9CS1karULUf6I?y9+Y~mE0{N)L&L6F@nM6h`sNdQ6R?urT8$i5tm&j zv&) zfagT<%Eaw8X|NF!da@=YunnAe7e#Q>F~IZxa-80mi!mW{Cs4;ABXvN>z?#)dr#3+tT60res2T=sPKjvD4KNIq zQmU%DxmOg;)J|MBwRLLq)F$EKJLD!KED^wcIiQ7!iEe$9*ylS;Sdqd#%6@wZ`C++0oIOMDFc?~mJrAcj=eMxgQ` zKKxh$F9f0GQ2D?UO)M)(1W@^qB)S~S&X7=@p{8;q5Ed04fq3$Ny*|^p z&o9Pz_)b`NXelPE4P5q3V?~Gv>i!jrL&v`@;&OQKf{XbXq8$1orsBHe&1F*#4d8kT zoOKo#>UKLby#HZjj1cynq2x~q`%5KVciBu)CAYjAwK)uae{Bw%IHdgY$zQ$jz|I>d zr(nU&C~Iz3hWgeHuIp#SSF`Gwy}YG48eTtHK6_QU5cmg)RYsnbl#eLxB*5pRGNave4;rBlh ze(g7j`3$$$*f{}$wS>T5BI)`CGbNRLVgSGI3|{=c2OebjeGd$kYesLm9&CTF zg#SxjZ+E=V=Xe%RIwBCqp0w}MqROq7$(k+nD!7EjEd zECMd}q@$9p6-)OrKO|G%1hz-RtM4<%QlJj0&= z9wnkY;{i_RCHdr;;t8E??26wg&vXTubJ0nZXJjQK$}_T3CU5PEBF_{Qg(?LK8&@<~ zu?2DyDcneVU?)MEeb3ARD!C&KgCYn+Cxb!m#b}VT#sSJ*Vpqm2o;bT=W2qJ2yAtU<{!ns9aRU)?@&I;;GJ! z^pKi3MqRRkA9MyMa)~^`6q%*q%YVGmxodbHem|F%FY`C9)k5PXxaJeTB z0)R``@U+AT*!llTgcYgX6z%&-`hhki241qJA^$HKL9jV8A`p-NXX39$z6k68DW}tq z(j(ze<}~}_nFT7@ccd8as5j1@J##QPV;wD~y0dn@e5MCh>N`t7b^PXh6<-G^9V8B= z(_#I;19AO7>nV+4DFffXG59~uZ!B1i;=Yg3%T}0p)NXL63l0r|8W#WO;7As^XM zyCD-DQRbJ48tJtKW&ZTA$C@*PKs=e>-p%6c?Z3JHN{(;89@f5sb)PE3nmzhs^tGV$ zfNMb=L(QDaDr?tWG*ua@3@MEkOe|lqa=e^}wY9j8fm{?OAK%Uk*5aAGO3G|GC=19$ zI+O)uqDFdcL0KR@?7Ob!6EoZ6xUxX;4PCAOM>!(1BR`7`mrsr;uFN8ivD=J1e{2Xj z7JxiIM=L!QETCSKN>-n~43JEe-NkpJgtN6^uZ&_2BI*oJ_F{Qudu26oF2VW%4pXfLRxK*CT)vdp?_sezx^s8AHK*B&s1MQgWRqYjFcwxf+5%4(@pk;O` zOTBlPXoONS(%Wn7CG+4+p(#_Q)EiB|{Va4jk1QT=v?_kteI=5nELsnBL!-?FXuZng zSACT7U~NS2lJb&5i#DR`P=NB1z9~IK>3NhdooVb&XSFTt~&sWckRE~ye>xP`{uAEt3 z>4EGtIoVw?(_J|Vz&uG#cJG`yvN9jC8<3OT*si6OBf$s2RtecTe#c^ZLR_*9Im-qf zf=l859qFwhS~hkNSitI0`T~8JK11)JJ1AN`2EL#M$1}`M#hrY~mjDKG*ogwW$AN&!%hh zzzbXvP*DHBoNEO!F;x&ikdJ@r7XrPv% zJN)5LoAhM^Z|&ZN}TG=>X!hME&jopT0f$>aO>%L)AgY%;{opFpmK7 zeD$RwEi{a%C`JK>ks`POwM{DM99>1B$5tjZi~#iLK_IsF$1~$F#*rqvg6_l6eOPmI z9BKZMz+;>LgZ}@XwDM=@BHOed@qkQk-YOj5!2|50FrmW2sGDJ1W>FmkJiW&RqGnVEpR zX6*vS>jflVPcoF|KlJO4!x1-cotT^|4~^F~XKie>_rg^xN7wekxryFOR>8h+d|;x# zFJ}$xUshY#d$>Go)RP`taqh*Vz2#wuH8n6fu(7{SYmPZomNQ;c9P*elR|H;T=si8w z)WW+r!_>kfbiGg*IkJ|8-N}>#Z<}la71d2@&7CUJF+yLW&(p`~ee`ZvdvzO}P%ad2 zP_9TG1p+T5^Lu)FCYcnhjU^Oov#^jWK(NKp*xO>N@6CLULV$^GdLajgCd_m@#>hdU zH37FJy-=^EYNygR3Ds@{re>u&rz>TV!~8jq>N#8j!@5G#>*P3laDX9!r{c3#z;`h* zu9R5E5qa%rzY&Lk(P|MGbqRLqw2ns`?mW-NR%|EAL%CKhcnGHI_zI5tFCptUY?&;# zYrrhQ;`@Ci+aXel6{HR|SLiY-NB)I@iVR={U*6jGwVx$%e1P%$>%YO)V@mn{j>R0H zu6dd#^l7@6uA#TmMeswZ5X!Kn;`g8RrceS?0O3z)_-vu_dV~Do;ZoW!)Fg%N2Mwb_ zTWAIoFP1_7pGqs=!sjJ}O%McCb5d;AR`TvK5ls`3bk^d)HltK9aJX{|n!IDl!(UG?& zLr(FRk{561SCisLQ2)n?MEu$lrsRcyg8Khh$N5|6!62kqYqzmMT~foW_HU_aEp7xt7Q~+B?&5u*IaTmP z(EO7fKh}O?_P6lII#|E&Y{8@+;q&k9yHKhycxQ&s|6@#P*2y5zE~0-AyUyXaPO6+_ zkXtXs*8{^U)VKsE_27K=DWB?JY(S!gh7{N&Rd&V>bKc+fg_b>AR~5o-$5j>@L1(8ipmwpkt)0oBV8wzsX`DoC4>Vig_Gr6SqNj^=I9W zum!{sp&j`tW}-gawUrS_yPIucin|{Go8lC2ZTf+Sd=c;>d>tBq>VD(+0wppv=;~qK z-DZ166!#fNBKwRBf@bmKL1JTE@d(7{H%@%r5}HE~ITU!9@7`4-(3r!6q+ozYN|>mV zGfZk~O#X7;0ST2#EX9`NI0`#6V-aowGmX}($l4jD+X?((hyj5;TPi0Tb$s4pBfdSOg~o&=lf?O6=#*91^<-R44$NLKKif zbpEf?VWM@@FTxH(X9Q-BtSkbDFar`OJ7{O0o_SrRAF_M1oa{ci`(2ejgFJY)gzPdj z?&Olj_%4ME641In0so&uIgC54w~}SUQ0KQ`j4@&}zx*i1N=MGx&Hhrny_Pf%M~Muv zzXaykV9@^J4>*h!3j%0^i3N7AOcQ2*!NCk(!X(icyl2urE*9@V{U7yz9}Ok$D5&;_ zk${`p&(g9~{^Dn>WL@SD<0$knpgY}zYQGaIcurLWQ0-SvGN|?|Cz1#SidXHg7u*{E zOa6hdztn|WUtc-JAk*h!UltQBx52fmddow7XMnGQ0DV~tC;Izx`JV1>x~$B}mC@f1 zZ0uh^tu&W@u+tb;H75VTfQiQ9aas=M{J^9iLod*rNnzfP#vVo~6MvYa3AUng4`Eqq zWWQ2R{LMaZx=TG6=S2l7p_`4x)!`7P4!*^@2}2HpG6)T zuMOguEW`Ac=4YX=`A5LxK+|MS4w$&?=r#TSKL~-pbcb6HuYh;0=|0pYn4Ecjh60m; z6a08B=DdyT!8H>p|gbD)94{XzZDxlT3xG9R}l zO>+_TTmgd3sGv9F+z5dSF&!Eom>3AE*SfutGA$|^>m%a)xOVKqgWJM)-xYT{=Za_NAfQAS-U;=7TPU6V<}>58CCx!8 z&gM9l$H-Z86W&VSO zF+R2Mz(>!loNkcYuE*z`K@;`-lG?EG>-fga8;+N_nkd8%ayK*<)}pObuOU8%?8{ zPGJMj+2^qFyY~M(AsqUgpT-~FjvKmI>fiWsEQ916afvc;z%fBEzqy>3bh`L?Ng0XG zMlz1}{D@k$8m9QX)foj1Rxjk>(1c-~#~9Z76V^2UwsEKn=h$4Wi=w}%ea8KD}ih}K1aUuXbe^whp}za^##htuFVbW z=AM#zMm-K#{Gw<8UWOGAqvoN+&>N_P0L?rqG;Q}M{lRUk4*m><04n;SU`yXk+g+>F zQNJ!&%hDOa7PEsMCS1(U74z^H1aSk_|EFsY5d9AQMA%_K1XM?0=Jd)^=!Kq;&@BwT zW4}K$Tv-CyT`MQM--GOii>-g0G0m+6xQOXLEw6{5PW^`WTge(Fi9Yebtoz)0sbqG>q~~g7BNmxV`yD%P}hdEpRCQLzwb! z)qC>B$*r-COIIBEq!sVS&6D|)R(Pr9Jz8pR(lQJ9s<8V1$tpqz$oF6uG2EtA&I0$~ zMLB(?U%lY~)3HX(FO~<-`&p$r@&=BzX_kK)TuXa)b&s#mp zRxKE-dG$W4Z>oP$KHqc1e7bz|)``g}SjV6|oUcc6T-pG#>uJqW#4o1*Q?iY)KMCRE zuc^GzAfGzE6M9WWVe_~=94t4*oIP~)(K#DMg(IGxs)D%m5jCqZdn$B7wVK)WzXCl5 zCkKjMi;O)|AwUa%3)=tuVu$uW=Krhq{r?^T>tFK1r_QXLZIC_a_tFv_Y7@32`wlHx zS%aK(ZKC+K+Vc<2ztiad8`l4Q6R!VjKMk3FKeY94TfW#97HaE9)inXzt&r`?&EA`; zx^%Mz8+_la{})p@>(^_br7dRkv>CkJ1iAz5iGkpXD{}E0apkO7zDkUmZ2m~&h)MY^ zWV>sYt|KPd9ri~BU8cC=hZlk%z<61aJ_1X#?mMub(&y=O^eOr{oWOtxv>;F@YCRUa zDHQ4lLHz&M`2S0Uz+Z;KUGJ})W03D|#ePU8^k$`Fvb?0cq|n-Xy~OUl?)KAreMW!4 zm9d1bnA3SFQNwe=95D}tBE4e8`{66|pqMHunJO9v6c7s<1{4rNqX@-sHxBW@5dky| zIKq;xliOXZi-rMLXz&7e1kf5x_y|a(NC)zc+Jc<;{?t zj4?jIg}!swy2>&z44i|80oD}IFyM1Yk&oxbUlh59f#SEI&3_l?|9H>;8JG}iq52>= zN0}@SmIt*~tJ`2){(r5ODz_o}dpLr`!u5ZAqE&p@XT;Fa&;?j%=tA6>^anRYmGPE2 z2qX_7zz(6no}()6va(y?o`NT&usNq49~{OIG!khx^6_o9NXXM9N2Qm`WQ0=^7(? zmv?~Y{}JyP9#`9dOUh5B#-9Rcjfv)3jzZ84Lod*rNvWw>{#l5Y6lAfSEeITZrR8Us zAGRJJW-jPWVKQvH=OORV7TfpF*5Ng0KntgojP&+G0`uU%*@=A-emnX9TLb6af?)rD zyq-s2Dw6?TBYn-gX;PUi50juCxvESw#!(l#RbIR9rLhwh7F%aW{h2}|G^Ied(pu~WA^Tj*-M@ri{Viu&el!ey zXV;d$J3`kB1=|>7cY+9Y6K6m0ZTpr|y8qyz%UI7pJ%hj>2HyyL?EK0~P#X?IwShr~ zuRGrjCt}3lue(xCE7-3x-O#9^>ujTe>u=rm|E-am3B49JlEWu9RL(cZZ(opwr>OWR zA3MAlitGe$gObb9{%=7I7GITJLjt;?@qIL15HPHT~UP~V^3_S@~} zfjVb)yDs2-`xmh#3)KG!ujju7SC1bJPPO&!%`jw1KBe*~TV^gnU(@`ao|;!k%Qd9s z?mi};_kg<1sZEyw4vQN6oj6$CEU``7UBXUX!H$AmYM)&^(A1ao^4I7ZdMjN-^Q3WL zN94U{J=aQvS$O9Zr)K|qA0hB3CETu8-eQo?l~4_4a0^tcV2#P4ar^TKD^b=LnQXEY z_KEdt;LlPRQmtyV)qLX!4+0}l{8Q)ye4^>~NcReVD+Vqky8)jQd`?0&9Mx_@{a6u+ zq)SJ3P@Dao>MV`R`cH?hT?p4-x4zulGRlP<{Ixw)6ZP}XNV>-G(9d1(;dFuN|2jE^ z=yzy;06VX+XG`TGgFLhjHFt(mtQtuMr#lt@a_8#Gg$8*b)g36sKfnDWl?x2=1x>To6D-ybfdWFSy_tIuSmKIGZF4V;c%Nm_ld5 zyt!kH99Y16ESq=R+OG@s+On@l){1P8j%e)b=Y1HfL)TfQ8nFUMTezb9QMlM)qI}yg1t(6%M(EW5@{3|m?o67`s`KxTpQ)ul`%M=Q)zr^`y znBbWK95bX(!z})_KNO?ILM_ujeyC;o$4XvI)G*~?jX9~NWuin>MIf^N|D!k-Kvosa zgqI8Xh5`ai65jy+|2OPg(=-HI0R*EL0r`f143Tg6$4XvIIedfF#{@@{tPOwzBMccu z0Qp9W1%Gs{Zf^7cDg6b3KMWZ_VE4_Hw;JTZne?irX=c`;6^v>RQTXP3!whhih?Z(sa7c*6bx4K<1zYH)ytzvi5PSn3&siq9qh zHvUCSuu;gLXOEUx*M$u&sd)Y1FQFJxL@N~^(DC8&^}KmKPc7H@NG0Y})Ofghg`yxJ zbw?t~u@c4SQ2$5$pJRiMJi{r&&H;xflNx^?%g=y;=xfG`5!^J*15y!lRYTrq@3H5(bk_x8(Gdbw=n{54`1+c@A1Oz_4u(BG~h*{;>t25Hu z3w4+W|Mrr(tV*nB%lFc`>;?$zTM2jm=dQ~uZ#T#{&ybK^wy7w9{Zp7-bE&-9HU9!x z{;cy#v8WByo(SAVM?gIW9KBA7OQFGj;raiMYc`dWze>C#n+b;_q_dmBv~?dclAd9e^z54D`9s+yLTs0;!~Bpc$aV9y?nGiqB`8bRqjm zY=cfL=LO^dzRE<}1TcH&Fi3TYZ1;gJMg|;Xa<*Y`T&en=lB?SMUm!bbpTe9f?lfFV7 zz?d2&$9l&Ny+Cs&B&}&oBgIuh6=*my6#=ahF#+$HZB(lSOWb-z81s!nf!Z&C5qrr% z93|rkKVC!xVn%=i|JRNp@P`2rs3Wj@O=S#L2|eAhznSj@BOH7doAU|a{`=s6KQ?<| z2y|xJlxX+r7S*DM4zXR(fjD#bO+rACoqIYfDh9KJ`8l&2h&bk|Nl#& zfemmY_W%0_3z@cmtmMUv%CwPX%ac{|bHe`r|8E0> z{r{5t|Nj^G|0_27xR;3lng(Q|?UEOo21xOM3pTP&qiMiD(r6m+kCnWbXc~}*HRgn- z0c-*;Szc0JQaEq*=!&t?-mw+uUOd`cUeY(!zbH=u zCwkni59fQ1=%&jzZ=C=?XT$K9uSdRc)ymPey>P1cl2x#Sdlnn{p84H$v=(;=--(=B znv`THled~-yL++lZRn1Tv@7@~%;cM}_QqiRpOViL_NQR@)H^C`4RY6Ff^U(E2l=MwnAv(`!c{<~u%?Mn8(|F>12_;~e+mmjUsri?P7+3&wbPG{eL z*mMrC^wbs7mYy`ky5mlntNo@i-(PxEO1 z(F0oM+pCA!6*7}Rx2d7^1uAlEk#UlLY|wjTjFbF5z`;wL5x`0QoB>U3a?$+%f&R~$ z8s~ttQ7&!tEk5LLzM--rW`Mt$hXjKpp4iCY;=$d{75STuMCU#7x6T*|j)7!NFu+2S zKS5~foD=t8YDM}8p$F)Gx(^m}d5%6sABPjXLuCE`FaiB&yeo->A}XQC^A-uF7Y2b0 z5Q;Fc$iGJrq0oO7aQWp({(okN--SKu4E$yNr=Mqy&ba=%_2u4{fgI%EukC>x)3#;7 z_dt%NcGfKeIbQx6T|;lBi)fxS4(y1$_wqT7#=8oU)2ogD`4Wu((N82_ikzI71U~w~ z%GCz>#ElZhM4&E|wz&{A-{a|H)4j>|tsmIXPj3H6<=rsjU6auGz!-n{?VBoB8RYY0 zaE^P+)!C>klhzZAYe$mgb}ad@{r!@ z7JaC1d|+Z=a$sZsf=(s@i}*9km_eT;Q9E8#eyq$RRW6;7vf=k%2&};pP0RQHESJR> zlJ))9$x-b4|1sFr!^}~Y37CX(Elnn%O;e*=F1?Us<# zffxAwwf@B9KK5zNF^8fl znp-yXM^rTHMmAH5lrWQ41h%*SZ2lEW(QHmY@UiVa#5}gsH&Jjw{3I{>?J!Xu%C#FA5kcS|Halxd(dS0ysu&vDvlQ&Loy}@AHg@s%J zLSv}q(KUSRB^T|zna@!OhN0_)92}aarX3@!Ll-<^VTcidu^99A%DS%4OBk=Cz$B^r zy^xT0?WVBd?9MlORl=USb3>t^)!tmCyw-S4m2$Jkx}i~cEwPQJQCJ@sHeM+QxMset zJ+faFD(u3tPI?F`+bvQM`Vp1$M7m*G!nr&pEUYoqP+?m4Cz5&S9fKjLB4U4 z0%Ix^0M&u0facq~b8BVNAP-!fRglc%0EH7;IKq;?ss2Uz;C)SAoeZ)%7y|Gfyy|We{ zK89Bbqv`*wZ5d=Cp%to=JK?}7%p6j=7N!IDO6Vqm{)mB@BP*LBy8$`b^?&*Ul}!e@ z`+5o4xzDsRPu{bkat$mzjDAO~7Ux+~G-{)OW;5j~od4jOuBlAE}!aC`1+!rV}jEo2{1R4{H zoF@^Pi`=zRWdKZwUI5PJm|k#LH?8{-iRc{!{LfniE#+?Ld^R(u5AfMeeJG9hrT7D@ z=qhQ@gt&BaxJ`sMPicq00cqVkU}Ii%d&G{v*`(`wB6c5FV{a#}S(C1z*Gn(ZoC&k8 zHLL3@J=3FG8evDs;Ta&?;ZYv%xzXHB=&Bg8M zxW0JXBX<0qas9tVVd@ALYW{5yq2}KPh|HfYZ8yLVw=$yU9{|LFQ7z0F-Bu?A{0Oxc z-1P&*)iGado>G1>xvHc2*Q#uuE~V<(%*07$ZM5#X8%iAYFSu=Zyo>s!dj zn~wVO@#}vUZGE;(@@Z6?81W}B1k})$d9Ad?3l+ZUm}mJ&54B|)Gz+0v)!Ub=?fN*7THi!^(+_S{UbSY`9st=GN)1M5z07Dq*fb z{a*mpME!qGOH2ESgzEq2rd=+x^+WxC77IL58v$v`ErTI$1vi{1q(KxnJekw~SM`=r zw-5GEfGIyzFju1fkNSV8rh_-NAP`*tf4Wdhpy|$*6kUGswf~R0s41;E^lPB%yWKkyR~TK|6w>i?+!2X1b7!yE*fw0NI~O6dO= z5VBWFm;)G|;D7*f8V(?064DSzgwo!M2CDz9c(ncsIP27LjwY)At(XS?6;}Nx=0zTv z@sKSz7nA8pY<-_khs@>m%ysi%c~GklE*o2M?!}|M<-xx70~`9;U@n6`$rfpTkv|5_ z?x*{by@rh6_jfQ4xBOyL-7u(bQmqF17@;o#;E&P!=-qS&-A2dww8(6x68xLdgp>V( zxA$f~MPvZ0y&IgeV zD~Db%U?{w9g!&#T_TcXh4y`hGsO{e=B1|uZUk)C5c{BE#%7uc~V?EBLyjHLu;!-kFjwyOSrXhyv3<;z z5E@w`qiU`TnuN_F#muBOHEVu0%%|52G-pz<(^`}29SyZUimn(<^-*GsG6w;)P0fKs z$cYg4sgC79{@)QIe-TUuUvAA-`meL4 z=g2j~rqO)d4;uxYeP1PWG4} zH2u3Z^4TwGJV$QjO6_^aZ#U@wlSkI7Y!4aEfpY?0uAQ5}OdBg`s+zb%9QPs)+wdue zo{}YaMppP5;hhR2Ad4v|3_${l)}+^SKlG}8RH9&BgZ6(J_J6lo7)$Ndh1NU@Z8R4pnA=TU}GX|N`)ksU<812)Qp zyRNBx*dX6sjV>sdNK()PipCFr&zAX~&#$Z849gy$BcbU--`_^~-{P-m?y&;fTzi?Jn`lfQYcWv{uW!uJv~;ztFZochDzdfgUrhBaj)}!iXr5|E^~cm1`Q) zMax4(sU8vW{^Z;q)%0L)OHN%AS5nlW6%d&S9a__lF>*Z+W?igXj+w2W3-w$9g6${I z9$0Jbi-g$cd3(AG2etX$aQER|q7cBYM^VT|NjEd}APPu$FDC?$0B`~_^~prj|5-bu zbUT4R3^5?EXG`T4gFLiOLU#`i^HzA6H+v4{k6SjkLjT_lF*N(EWQqJ=0ZAkO_Y#6x z_PUDK(ge+2ozEy3)LbdHJtUl08M z1N2$?q%8s5ClUd)GbkXoWZD_bDOu3L&<6|(A&@=F>j8fDz!>pBL#0c||5cI(mPIiH zqVs>93=;ZNx&(He!_IA0%^(kK$ZUtT`Qe?tRces?S0)Dn^Fw=#Dly2n=Ow4iott9# z7-(mpuh18P``-xvH-*R1&z*=h!y0WYe%gxCaZ+kyF>h8Hb%(+w)6U{h5do)?VPn}Y zpyp~OnLV>Y2RQ@>1o?jlNbz!(5s1eBLI1y{4LwxYQDJXu63P6TQiYwfFwBo|PH=8= zsIbq)#6E)xyN!ez`{4Si8s!#Nir|3oQ`leR8>sDh!S=|Y7YxeQI@5B7NllGa6}+Kh zKm?M5KxF;@H*jJoP7F;>drx*r)#D`QZzdbjkfldX;tm{g5_fFkxDs3ikE4_hdEVpg z)s`PoK+WC(eLR(H1fpv8ernI=9clFYu>J>ZFeD6t-OH0Xj0lReN!5+W|N5+p=WSj;#Oh-xJ;Z;PYUDaaGmWd(#NSzVT+ zDoY)LVtzsaF=7##5Xhb?+En?t4zmaPNL)|{%op|lfPi82EFln0|7RwAO4kwi!@wDV zyAG@74Dy`?61sA52qzBV4AFYckAwYxx^Ml!hJNhJ3xS`yx1`WGA(a(#kt|>1gpfWu zc>X_Gpg9w||1^!g191Ke7ttp&k<@VDT6Z^*xU%)x;sh>~|FUA^95`{pxsA-&lreB5sPkT3}#E+`R;mzIx&dOCZi8xByyu^6u zi=atFp!}1RG@3*rNh_&l5j2TJ61(V|(Ihg9a5Vl8`u}euKU0&RVZZEbD^JUjdL+cW zGX%Dl13hpPV>{F{HJCuiJn0#FtLhvg?Tp@%8cj1v^2;9RBMA|Y&|c5XtM{)aq!nN> zT@Z+>_0J}2w)gs>!5{tq&o++)AGPb+zy8%PfBA#|JZQc9Y!A>mO}Erms+-gr|5l`9 zguVm=E*_)z(YwKa-8MLp=3stScO?+!8g+H}Vzjw{(?1RYQg4hTQhov-`<7tu>- z2U+9g5D) z5eQDI!sdkcH4w-i=p&7~hdEg86~ZJK?jC;T1myqWB!G7*j6gL05BmRIbPc_gE~0t0 zDv1<1eu}JCi%_RDY2trPgGpP$F~~#fu=9?=lV)bJbz*X=JPd#N^Hz_p z7#r=qaMjAuwY_kv_mWkx>znFdY~*|9chk|$R@@=cbEklz-ZOJt^);|4-Z>K5A7uBt zGjFKQgX}Jnlie3)HdVX8+s&AS>{_P!K~?v_|J^Mo(HKx`@X)TU7C+QCJ}}YWm&^Bb zchhC%^&7TKmWRv3M*Z=qubemxv8Dzl2R8QiY0WW*%0qff7kbB-kQe<(-`$aQ-`qYVWxVD z<7p=u&b9Q*g9i%~ob$axAEhtQhv_r)9+;8vL`Xa1X}rXnmUFDbNs&X<7dyeOaVIii~`-@Ka$Q?uX8 zUqx9`{s~ii2FsmQ6lf)Ga^!y=EklGpOP`DetoeJ64_CBAdEcF8%8mLz@75wWy`<~^ zUy=)#og3=^1bYMR#(;Y#1W^BHsG$B2T*1GY9rgd(qhyLUej_GYq(+Z z#>uUdo3GhaHs%|JLh?q2MpyjnZyfXYSvODJjy=~pU8A#ps2{fy)e9DF=la%&mMrhP z(@boV+H`o!Snc%8d%2Y_;Y^4d4zVWWFc$V6Dx>=6@7nSz&sB?x*{3o#A$9RsM3<${J1oXY!}y z*M$9LF5I=PdZb<$q1NOrYg4Sv;A(U26KdX9 zV=S$fGfZk~tPQ~WXc&}3fO(P;AJRHJLenTLd<+}V|G()9W2%`Mb~L)mJ#`mQ|92Ou z`7QTr+^?Yi&mB@sP!IyB{|f>(aa@oz774K5geWFCVD}8JM1v1 zgTT%ct4A8-{tJ@SOK5%SGvimLZC%?r1`Y33y)FBL9zqWP|^M{{L{4ggV`e z`hOPm|AU>HLGrJsSO5QBvV`NV|1;vM{pkHw*&}r9$m89k&M!!{x1XN zFnOT<9|kpr?m_)OiZGh>{~!2SclP#(tBko7*8OX~H9l|EP+0t$yGcy-^9}9KUeZ-V zzvEsqGk@rHRn|2*uk+^GBw=`063W<&X*P~S>y9V)P+sc}xlh_vO9nWkD7rk-Ite8@ zGAgBTlfd9r&*=U?b@E!GnWO@{<}g#J_84UE;S$E5fxi9NuJ=@rGRQZtkdPfNcsxE) z9?I3%C%Au!{uS4bus&4h&44ZIk2(6Piu}jR36e>W2R?C!RB`(9tT9AbN3nRz0oPv z4TI_?x-kuiudnD1#x{8VABB}rEn33K;I{kDYc@?-6Z31S>a|7Z>`pklQ;zL{^`jd~ zU!u!oBs71hD)!JOkbo8t&17u=J#eVn4#bzMVf>)`4(zA6KuH9|bwi_uuCq;Z|KA@Y z9d4z=$cG{{GQ8CjfzCXLkQ}(?Y4D&NBv+(kguVptzQ^c&^lrL?Zi5ppq2J}a>uK}< zx?W221qUv~nFq}}DC@|B0BBq$JI$>vTHRWBP_(4*Za)af8I90TZE@{AKSD`CoM?S@ zVgNAz6!m}9|HZT|Otl>W1@-?wYcFG>ezR_)ctTj1ka>hfF1GvFJf7Gxk2_;z9}*>? zJo9*CTabuN(z8-g`)3@~pg$n`9ok*mVmQE%Bm};oS6^$8AC@GH+JliIe>HPv^;j4Z zDr4a?$nMFVS67b#uY4;d)J_o&Y(6oQs~!yyA0na70P&x||NrxD@R=A2>1PV0pc#~`OxRq3DLgt@K%?>h42m#h8EC9sX01iKr-9nO)UkfpQ zfj&&1q4z-N{1eG2ebP%QZU`bS0+#f)k)`rSwJMl@p$PZ!5*m__q`49Fl4gdlsYgQ0 zzs#gKkc4DX?5V3Xl8`t>iXi@}*6PA(?p*p_#BZN3K0;vCohAuTX#xi8{XV25;=u`A@`bc7N{3mW90tD#j zECP6VYd{2A`s!ZVe9fkEDX$f5kL9J@?6I@2j)2+uif;a`uV@%43oCLaNzbWeVDQj#N5y_5(tVl`r+d&y^e5mCq6-4JNu6qe7aAe@4YZ`Wuy zq1$1Dfsij~)z`s{x}u!Hi=|5g2fM!9b{TK~DjuJM1 z>Ug^2$&|sVL50m6g`gXTUZ6P>*Z*m41KV4F;x9A`#n}dM>_?pFW8SJD(8B)%&;N&y z-hZf4lN6RCypr@1o&V}%^gf!(H7Dgt+M~0vzmO|Hus!fK_Vv*)BlW$Rw=_dg4D~_| z4oy?jjxlmQ5N?>fadNBm*jXFv=R&=fs-4Qwwfb7AgRQ!es@9@!vgIaYSZ~t&Pr1^- z+&UqEdSxes;lK%=vf?mMubQuP1jid5Dw zMAQFkz(L_?&9^xqRS z^S?bW<3-sBApMt(xS#xx{`)}*Iho=|3_53;6#F>OB^zDG?d~6c8mE0K9}?zUXxougOQCZUER0ezYE?FVKhS zGxQ$1gFYd@B$(qY0%!o3#R88+BY^y0G{R{~p9lZP{{OgI1N8sD0sH@L^w9ty*8pJd z1OC7N;?dsnVBh+I4gKt^W6&pw+)~)m$315R(E7j`&@joVZGC{}|E0!^*O+D?gh3VW z5rsf%tPi_HArwct0<90MIx){cz}W|Jv?=#I(fZ(yO$x3Ux~5T0r?6p?ru0<;e;6`{ z!0xTp1qONWY8-yRM4vV51L*$$3;(ZVuG!10Ffwp?Si9!Lje*Zg<^2BxuE61iSP;Mo z0I|T{Aya`2JZARIDvk`igZL$1Mg}e!@Wf_^{r`y-9TXh;{}*Eazb(P6G4Qy1-p!YR z|D)y4Zhrjt$p86c8aTyd@qbgY?=SOUU_kK(p$H)V7Yc94#F77p1P*TtfdKOV5TIr9 z7Ucg)7CZ3&laT-05=8zlcjUeKYeGtFWO=YWsGYZZbj8?c@7RiS;~u2oqaGL~ z3<7As2!k4jdzvk7aoaCQsX!Xb9E5z%dDK2%!Cf8#<0k{Q??k4*r=&$2Fu5C^V38Z6AqA zEQ*2TdHNW=kKPS_+qcoW{<=&^#rq?sTI!0JfP~vUj3f&SxdH^6sWkRS){12_88e@Q zCDy6I!Gi-N+(=ckQq>{Z0?nD|KT$$kP(2GYkf+@OIG+ zEoYe2)GU>%*~+UbB$+E0ShppFhJoY&-B0(?=jn6wDf&2lL}bth;!1bKUQ&pcp9)2*jbvr2#j&b+}1j@Ty6)&Nr`=rClo>CM~P%Wu%_EmpvJf zSggl+uu0oCXf~`4Lc49+RKj{(>aLXzx2hn3yh9a9G|JIK4mH?7xyj970=72A+CaIs zN4sFzfej;X?S1kNv>rEb4tqe!M-JZm`BQd=y+6Qx>9rsS00E;agFrM2!sx9=y9wP6 z8w`ZZ3|9vXviDj!g9MKN|39ao{~x>IVKRCtsGt3 zTOJyp=)GhW?EA(CCi?qw*8Iq2wfT|5$O3DX~LZQXNi(MUbc3wZPZ}C8KwA#U% zR=K3Sq|mA>F6o=q33{$Cj=m%o(?UblG2ha)w?i4WEhJM z%_jSF>R82*%*=NaS~5bkX}l!>0{A8l0G6nz%D#n_7~aAI^_1{$n4U&q{wv#PT7CWx z>;Kci`KR_H`ULs_<p*tc+FT8ljvzHXgWV|oh@tW(VYLH|EqWinS6 zA2JiU14DT{HJFA20_uGaORsk*X8KQw{U%P{IJtFpu9)R_VxeAhR4AwK631z9Yr?(U zQp#XL>b>tWCC;O+g1rYLwQ9RUTr14^$mW*8R&=o~OE>9&5}=DX%rw!z|@yk6rrz`nZ)HN9o}xJ#LLD&V;h`sxL)d zKv<-pRDIp2XKcGj>18WzRMmOQ`)@^r(1py>M zCTx-uz-|68y3M!cg}h5H?<$?Lb7^(RAonNT)k^7P=>G%XF&G3PfI5R9V1p#9s?MMW zi7cHO1WSx79)UI@nZPa|@fgX^A=1d=6JR=MKP(++)K(2_odb&N|H+qT_#AQlzwp@M zo%|7qHvSj%|I@nZ>AqJWz%>E*OAu3xjsOy^uo#w34|}KMeMq((VZoCMB7j6oL7`Yh zl18=;nk>JROyyQpn&HZYM9UX$(e!_-|4%!KXg`Au21LLSft{ySmqK^fhQ!W)EDi0_ zt4m-_fKpiL+F85(?wA|ik7ct=Js0d`krchcE6(`~MqfJ3L z#Fzmm1kk3y2}thApiO~0q=`#Vb(=y2cG4;f+WgaHmGoMa(izQB@t7+D*-#<5LdHKa zR3E)CEuHCg6|c!h098o&n0L-GlKRM&gTV2Bok31O4AoW01VD&IY30lb#(;V)IyY80ALGj3t1$s^hTJ-cm_^nv~kC-Be`8irKQmSceaf_uRTgp zt`vF64by2uAQRS`(wo|9t>90z;3y~*ERrJvXuWZSMS+uO!BId6F&80y)|+VjAN2oa zF^eS4*=It7R9%3mJ$gx~^k%QCcuhV6s6oodymO9`wa3kF{y&IbFes(qo;zol)YO># zaY|ZeiKID3S{6-6vy9ZJTQvQjwKEExfAEJP1_Yr0?=0;9vw_E+Be^|CrE`G)udva_ zy+{Pm6d)2^pJ}5hU=C2FbLX7G6RIG9rT|qW(OeD%OaTd5th*UCJPwHf+5$oXC-t_Q z1O~5)@ZkSdLaSbR;57*d>{(xZBbWltPwHT1z7U})K!PctGy?p8l&|10wI&3R^f!SK z*CCRAFXT(-dtJqA@)1DNFCX*HIf^6wxc*0H^wo)xz7eGAV2dRQjzDz&uaS?l{{N2$ z&zsvFJ147eGROm~GRA#N7eN32+1USYw<9F|5=g%dHtb6);s3&>6Rn3R4!PoJMIV20 zLjcV%?ogI4a=*s?3YucLLy8FsLIBM$f`E;jESh2>Lzwsk&gQZ^OK+Qd4$r880IHyB$f30qq1Dfmd*}_5%oT9-slZ7Y|GT>t zI{Xy^0UZAu0yOEj2ps-%C+Z?EA(CCi?qw`JV1>x~#l@!d=5=^aZm`~Rr6jldrUL_jnGyFOffGxQ6kk?q3>@s z{J&GQ&@-Gq5@H2}ACM43i5oQ5rmZO^!=<$fhzN_&ga8uaCNR`E>>-C5g!E9$;AL%! z^Nm7*Htbt-#ii|*X{;!c<=KrVHsVKWH zu8sgMi{RP#9x=d17B!C;5Ir>-$NvTwrs8+t_}^v$g&+TW z)r<65m~V(7$q1k#t$_4UiB>=eSOnh)BwLZj?|-wPLw^4mh#I+#(4WC3#<1&c)pMbr z;dtz4U_#(*2L~hX)pr)ED-3e);Rvt*fRpK71e(Q_@V`EprAO8hrD6ORA!CvVjM z{o&*l3-$kIbVBO?R{tM8n`n2#215V@c3oCo2|bpJutSZ3#<|C`)+Ghx^cq-o;yi#E zSDmn$CRdmN-f{Tfgv%lXcMI5AchW?0ABCz`<83EMk;1OjtLBH3G*a100t| zUnCm|@BEMlc;n;es&pRUr%Xx`YihP7^`$`~E%{Qvkb!L3NW_tC<$*7@;r0T5^xk`{>;;GJPAIzz`aN z;NOgEi*xdv!4J10YEWHo-|BYj#y<;oR zy?C^@JlMB>U_(E%8yc`8fZVd!Z2qTvls=$_9U=^>c#kLqkadbe zHcGkzY!IwC^_jhBhlnB@nfIa%LMGa3=f#2lYX*To3>igW_onIv26=ESQzMIAWt|-x z1aSZN!~cg|p}-4K5kT%86+sU7E6csr=>NZo1H_mFM+A_2a|DxHQUbVlJMZo^vz1$2 zFrn}WAomWB9p1?w0S^2h`~Ufi#b=7p|9>I&|Jz_?hkL8h=U)0C@c&zE^l{G}0p$PO zAq}2jLioQ%!K)1$d*kTUCU~`d-ckC9&xjaJ5(3EoB>^2M8|43i;7V;|!2fS84;!uW z9_||-m>QTI*x28v<$Joj>9X?r4O=G5L**g8HRce+oUmdppjOPKwU~qDL9I0=x)w-I zv+!L~w6pkzN?gQ9cNEgq%lXj1X8c zQ2_{`Aw~eGT#`g%3>O$Nk&Xx`Z-|M;|3UxX>45?2|ET|aG>_z5LjB)OR;68TSA?8L z{a*;In5X~*Q2!SIDwiZB=>JAZV@?orth^eRLSrHcL?Gq*KdT<=|I^Kw`~RRLY&CX- z*$)WvF1fs`v>Co-FAJI-TNnS z2kr2ZeZX%&a&!$KdmU+e&(S$FWY9>J(5LBMx`y6L7ty?0qQN&jzTwqskqIqLHoh=^ zgrn3erM`oYa zpXL{2>0aRizzhN*kdn_$pgJoaxrZET5Yj^}AHUY7INvA~XoJ_*HLHR(lFu;m)?U+c z)~LZ7CU2bFYTaej?y~i-+Fb_;j{j3!{!PUzHXVyQti1ysA@l&2vfc`Z#?= zT#lG>G7*S2{*U$lQC$BsHqpbh$9LegM;m@Lj>;WaRJsTF{~y@s*bLuDWF zrkz`=?*z9i>k>PJGE)6Ze+c}44f1~*MCAXH`Tu>u|G#FVKf6ac$d$t^@_57*0kpq# zgtN4_V-yY%&<4W+L`*^o0%(7c0&~zz&;}C}u~f!K`%9}>qw#;x|L<>2FA2X;ty4fs z9x7dbAy~^?x{BB2BY=hq`IvXk5&3^-j4%c- z1d#vpLNe{?aNz$q|2MWq0^@%#$ML^5{Aj3J$1^`dWRpezAVO z_O$kt_UGE4Xpd+QYv0oLYWHcsr+rSF(LSS1Yqx6KwGU}!ZL79P+n}w})@YY%7ilZC zH*05UL)w6LlGdvos~xEwq7}h0`LDp^#V_c8(0`%N(!ZmBMW3L5On*qfL%%`)klstb zNcYek^wYFLKT2<*Q}lYeg>KYG^t1IP`eMCLKT$tUKT1DLFM+r7SG8YiFKEwe|E4{s ze}P_2ub^Xe6}^C-OV6Qa(9>aIjRo|0dNe(p&a1b;E2ggpB(9s@2HTC(TVT6k`dZko zpWY1HE2lTX_VQ_fYu-DiCt!Q&^f+uUm|hRtw@hCJ+w-TdgzY)g?}F`F(`#Y7Wcr6rcZ_KH>U?+`;F;SV0-`cBG~@nbRTTLI(;&1zcPIiZ10<12-`1D zFM#d6({F(7?&%X?d*}4)VEfVO*TVJ#(?`Mfz0-%ocJuUMu$`Pf1h(VTphR@7n})h| zy<-|kMc1ln=qB&FcsdW;3#JX&uAJ6kyKEX3IPW@R8bIhez4~F;o?5*Lw*A!)!SWyLqY7A+zFGyWN?)$N1GZnRj=^?!bv117 ztX>M+PghsLcDnjD*xpvX7`7j+z7@9Hs~5rc=IVv8ovK~{+j8|Su)VH&KH%R!4e88V zIDHvx7feHH^LnS>4%=g^t_{&IRH zZ2xEaJlOur^a|KMHGK|j|7`k9*#2;O3FNi03UNyBuAU3q%c~=>eMj}puw7MM2HUq( z-vrz9s&9nt^6FWzJ*x`$mIkX!VY{e04BIzUp@o!=sh$Sg!>iCXO2sO)ig~9_uYqHu z3az3|O-}-?K{m{OML7yaYUs{kU1`!CLu~G!80n?Ohtc2(P;mNHF_1btX zcr~!lGHwe#891`4h6`@zB2a=;MY@B110JO>(1+$8}|2y#i18V(nh(hqszjOollK-xEAPR@9O zGXlOTHPUI$$Y(J*q|{lIdYC%n_@6MSsd5jD|9KaV|FNYZOQja(Y4U!JwB1) z#ZgP&2mb$mZ1i!@9RcM3+#wB~pvwIJ>|K9G;$0xM^k{HI@eYv)V3)c`bi<~N{68#m zcwcY?kpBnAESq;A|4*{qf&Z^V{%=bV`M=zu^d(qNw)B5(^l{G}0p$POAq}2j()j;j zFdIu=DE*1Nyf7y}2q6FWgOcnx$p2*{p5^?I|7ThHLFyiz|7+y?Z2dpz3rt$rxwv|j zLGHggsRPnWe+K;jO631`yF>mjng9PW@c+kc^m*-3igKmMOKzA>8v>cI-jotBRlCiC z^V9MTlQ&LowKfZ-FEs;=1RWx@Jt_FJfdE=>8c-;95ZQv$f6b<{G2bW@sQm({drCP- za0M5|gzZus@Ma?+G^{rVz?a=Vv8xzG&Ni?KWTr=I4;Ksg=(aV z%P}h4eBvouhIM3Cbt&N&;d1e;gxrbWsEbHy%sAKzfI(ENP#TPl9jPKm; z__9t-&N7v3^+DTIE)=wy1`yQ$mrjo*+6M5beXRP`lvl!;b=CC-`T99B`W8V8dur#( z>eU8$V4jTp*rSuDc|xD2d+8c_D|kW&pWq@w=`VMes_!<)w~kI%y~1LpQr{S~y8j3N ze-*YaDR6<-aA=NJjPR`>1$SoHic$J&MdTOJlF_g?d2S6+@9`qE0a~Y{g(gP}!0p--^*ey(Og3Xt=Bo%4qxo|LaZ1Zin;8 z;(<%KsqNd{vY9>KHsoSc#~~M54nR+W8OMI5+xu{4Z$RqEky*HS9C0-YwXESm4mQG^ zf|h>7ty#@Uo7V}ISQGY^@{(!>(@~ITl>R1TazLJuF@Yz&y2vx+NH9c?De??=(Krv4 zjK3S#*8A;!*7g6t!{LAKjTos{cKU5%>Df*J3}^;JK^y$9{LXsf*e4d*Fq zXI!h3VTIO*(Y%ij)*-Z6ma%+|HZg`{K60^A;cDvTSgs@`#mv^$s-qGn*{F|8gz9h1n50LPZ`Us$%!c9h{e{j3v^ZeO9nv4-D@D1JIY+RwuOKl4ft z?FfQjpeiMw06Rhl6R=8XiYbc^GXp&T|59fR9pH*|*=8fQk-^^cGh;9W8>vcgY!y~w z%6#_O+jLjm=3A)w+6}XH% z#}=nDZ|uzRoGDubxKAtssMCuUU8;3@|KPFyzdU&p(eKbt)IP19K<U+RJ zey@a%B48>1yKB69twFw-t@(4Vl92Lw1=wGhSzg@?Qr6^1`M+mwscwQ5-HC+ke9_+0 z^E30S*BE5)VhJSzyni-xT6H62w?R&J{|Z_Dhc6&pTcVT;Qkwf}t0VNnRVzo=_Lhgn zCwebg1$$TsaiYI3*SrWKE|(}p=xNMELH_@r4mfvUx(;`EokIRE$ij~OoNOqJ_Zu7e zzt^LQ*OWv6`9B}AAj|KFW9h#-MiCqVm3y39DY%KrNnSnWeonpH6?@?SKW{rX=N|79 zNmTCre_q?L;rbIh3+g9Q>#t6jQ{%u+W*HV%0s!j z^Am4t5{~~}MI86yjSyaqjzDL|if#v^ zW9^!PgU$=~|Npsha_bF~uvu8h6(BUMME0!F`ubpgXN&H>^O{W)mRqt~s(LL|I~6-s zwukR*Bh}Pci(KKy3jq;m(R*K@=yot5e&VA0UL}lDSJ#8iZUJN+r-8E9F3jI1`~+*UTM>5R}$#1!ia>bXmtbbB$ol6AjYcL>JLK*Ahfd ztUm5&kPZ8pEH5c9DYUMDv7~RRe^EZ)b3`{?zIp4!OF0^ z(vApuiAod428lv8Tj_p=Q+1<}0oJ{uk?#|_9X5#zI~P~418-4ROK_GXq?4rdt36w) zTMY8hx}?^CZ|B9HXWiBmTW?CQ zb_OEu7;P4upO!6?TCG=&&!9!weRXjoiusE|0IfHokd2zIlLbd_AMNb5UUL66o16zN zq6H_aY-HV^KI=_1{_lZ1Qc?y^GKPpu4s7i2)0%x050!`X*1;^6C*uJYa{;wtF0BoF z87vQKtuY7t)(>pxXQm;8K1t9yna4vC?2;Fu2$oVKw*CEb88q042L~{Cy7?zNevAp3 zk_p28M1|WAt8O*O=N8}#g&~YKE_|VgdeVZXTRKQcmxe3A2E|Re_>6SM5;_fTS}1EQ zdn~nAAk#L}*rvdyu`V5IA;3SqG6S3x5E2%lfdHDv8c-;9;A9@7HodU-UgojQXdY8c zq=Ac*KJ!>$2$FU~H2WXp|2p{|(XONeuuE2$8Lhq#)}}i|f?)x8QgPSos_!+(H{L8E zJ0YWu_zJg!9RmQ%?LM@+%^=@85dmY+cL1y`eX=2l2n>Qu?VoH z${{4AnbsYGIPXq&K5dyDUa>Av51fQvlH#w$P10#UAKb>> zgh->6)U_M|rtYTPBp$N%tc@SDsg~uYa-pF0Si@LLd9C5Zvy_`XcJ}|(WhS3&B7>3G z?o`VP8H^u^xH6co*!qtB6x$`v92VmeufyqtsD^H}aMbYJBI9}a2xN=FFnq%**>19N zY~l$dF)9)mH_T%^kD9&{_?$F-r=-FDKd%?nXJ=?KaTe8QKVo)OpZ(mdRGfCzxr=>b z!v$2I!{LT^`9mOE>NBd&?yW*a^|?h}X#aN?UgRst3Y;M1!V1{OU!#W+?Jr=1f$Scr z-T*_^&>xr87L*&Z<~eW-xa^_3j;me|V>HjfA%{$W-tq&yy5Rq??ryrQHWeHvjYob3 z)*)AXNeT295LwV^NuaCSy(Ug-cVj$7eIZX5#{=MO;4yk1y_@c!+vu2k7I>u-0>QQ4 zhKPg?d6_dTSTi-tmc(X$CN6AGT!~dJaGO;yVWWaoMKx-<#Lez(U9r{Ftnnm?difZQ z%1T+iWWX|y+O1W~(6d^Um1iCn8>dgxy>tz|RoRutPmgouagfU4@ZW<-wJzum>$Y1f zx?2vj`}=auZne=u!s}&teawMZJra|SBSnYj|LD2_z*aT{b?7ZGA2-MScw(@NtDwk` z;zHglUj-P_{a)q6YpFtjakM#(iV`>nGF3vEQ<<9thB=uvorvcD6Tbh)zDS>iWnR)0 zK9{D-_^OMeawkWz^Hsh~L`qEmi>W1eq*f-Hl9Wm&n_Zw<)Z9oy`v0=*|Kux#{tPyX zhh6>E55U}xHE2O*g7Ti*(c;qql)U5aEL3ka$i0Uncmcs%zIp4!mWy4-`>YAF8=pX7wAc|yHnWKxK7j@B-FKo>!^js}N0*&2xplJN=PF|dO;!t> zhaymxVUw2QOv|naH85r22t?EWSv#Y2JApq8F(9yK zOLfX1523$73;O_ln%HT@p|y6s9{T?l1WO3{e*nCY{|5j|R8$W9|CLt`f+gB8biI(v zQECEHKgP)QK$xBKY$^EG&xLvpR#k9bS6My&zfctJm~J=(kpG9nP3&FB|Ha~qsW&5l z{J$9uJa$I_`M*0h>R$o=|3T#cww#dv%XNv^^#U_(Fq>KNb` z1f@cACUp6r%LMk8Qa{+ks#SQt)JF@R|A8cwl7AVKz^#)|M*fmfJw@dI{w0L`-#=Dv zF_HhfA*0gy1oMAbvaPmin@V_MS>z(HdqedmgFJWvT4NaQS+K@{?!O5BPeaRy+$YU{ zZm9qJ$4XvI)c^fsjrzZTtlVOv{_lp2O6QZS|7)a7=%-*KDSW0>{jfoP?`YIC8Q`|2 z37Xj8og1n*8|2HVgIg`pMkdZRvSwGjPUFf?U5laB4I#c_UVO-_#NZk|RpeFCF%**m za;v$xqW(V@6ZOs{Q~!tW|B_2t1H(l?mG{>!(3?4`D(byZY9$h`s&p+?wd#tOD=t-K zY_zvNP;&{aJh3RB?>VBIs_PEtLN=t-T1t6fa$sZs0%|R%ytGC-2g_+2d>XycW@Ktl z$2J=s$rPl3x_=UcC{FkPpuo953|ZE`bh3@;cjza=PIUO>$w6nt zLWPl|KmNYstVKOEIIcBF-Owm_FlHM~qnb`(1N#4)z@U8Ls+FT_dts5|WUpx4sv(1O z0}P2nAd1WM=P53k7F6I}=eXSA(INt`qDsiKoj1=<1tyy>Xfv(N!e3FzDL&G01!Uzx!8!RXh39|7TDZ*L>ScgQ!@N)E({wLg zLvN*vXkG!Znu-wNrO4A5s?JE)CT#FfBm(%_6p3ztw8g(V=e{KA>AP{%dat5A@t@|%#VO2&gZOLo`bJQ5<+-!fi<{jt&KhsJ9KT8LUjK=X%4d3c~p4I^JLpf5?&a+b9t%-Z6t>@W$) zSD>%E_W@rKr9{Gyl@ypU6CVf+`iLVY3K#ybEhg}X0TJkc!0tCs8!*C}p!tIVm2~q5 z=>DVde^Cdax`9{DO2lbs=5+f#?|7&D`(D%cpL#Qm9&Ku-T?EJQH3d#O}aJ_BM2c~ld zdFXni(G1CuK(;Q|k~q&*N_3xhUC0EGNF>j33-;m|gMI6hJ5U2ZsjOjQ@IU~j?puL} z|Bo*b`q$)39+|~^Y1gsSMez6_!v%Z79eaRwamh#frwazTZ4GJ{tkq^kyYQ6u=!)4f zezV_2@YeyxqOMEX0!@inO6pvXrKFyTcPXiOUyvEfeNXTZr9Wo=t7-Qr+Vys6tw)tU znWz=E{3=IHB+mPxyUH3YCUrh-)Cwma^{4>2-~T4}OM&Z#Bp~c+-JhUB7&fDgCAab3=0bt-Hj<{QdlKFRy)r;jZ zMncJgC$Uh!2wv#Wjx0{*=gGoxm9a&^>mu@w-69hgoOT`@XsYW?Gh*dmI#>%Kl4)qc z2k3sf58RDBN1vjP(?>!im4aI~l?w%}$NK1(^0Ui2m2$JkDX69IDq!PihRR3daPt4h zK-9>miFPDx6bQTCJ6$r!Hzz#1GYDxO8&Mo^yzcLWVzN~ z4$uEu=g|SUmIto~H1>4bJHWdV_1^En zS_=2CLDPC&UGK8WBETX>k9+R)VD;=AyZ%z@#LJu#>N%pDF5kR$VsffH41f7VPJ2ql z>?SAa;5kCtd0J>!{QIHDO+7%JG!^wq$-P9OJMj7S-?KVx=U%ZyB#6C)o?@!?|2;zV z97$-e`kvFK=NaVN8@TI8t+)x$k6JU}^9xB^6MOSV+PbdXdChc}K^|D0xhB+gIq?6h z__Vwfq=LMavk`V75??x0V^TBwv|9>?TR2B9^S(wJ`)3eUxf3Ly$ ze|BR?Z;vYI{#VVM`_|)0chZtnf z6!$*nRu}~IF}G&G=T~~aQfQs#(?Xn5>6!o?;2K2O37g30@Y5R^LQFtB0$rQxd7z0` zJlJuVc+tEoUak>yK=ZCMfN0`v#>EH4YmT1wV{9DF686zJ-0c4vxr^EV?`lp?iQ`@4 z(}#gGz>ARLGjT|v_`nCR1^fS@X#cmL04cDqwtR4L@&r~J&p%Y|UEmzCdh7&KaD1kp-03||R zAWq~-Pnqe2{Wuv(K{1Br1^yPRJNPQthj1>Ef`X5sNDXFyi^Bo>QTqSrxkS4gHW)%6 zuNp?e`A;B=>Dkz)>LCN$gigEJ*kMnW!ca4#B#>lRV|pVI|9i6yJM5=7v%r_;h*Ni z>iv~4eqYG{TQLsF{{#L1PF()80vYfg$^U?W*}Nn9Z-XO=hrVlBs!0APfjy=f1_31h z!=NT243hu;P)>&YAM}^GwD>~$-&#{4>3;^IM*ff}e@x#>eg!w8-RxNP5RL5HC}8;v zc%ApnE~zerX}>6@crHkACkP|zSr-+(QdRlG*>nYclc-n|+_ll1OU zI(+H70qK89?VW5Ik?`@iK;IxSwAv4GBuJ~N0GXEQ)+oaqo4_|z6^1;gSoH5uA^XP6^~ znoeg+dzr+xbD;_a84xRX&M5k5LjX>k5a2{|G=&~zz>qW*3iX?Ld8Hw{nwM+dJK6tc zIn9y#i26QdJN+@;2Dh@iU9YIVOe6PRn#wI9eKWHMRu6|ANQ(qyAC$Xx?CP%`25228 zAi1#XNPQpJHCa7WBln#zaVBHv6@53)ZmAAv)Y;LwCr%=Cl4Yg z?q1KC|B?z$JegYPyG3NWUdwK{>L#)#GMpACLkDcpt*3d+z-158C+TPCPWos%pcBc2 z#EppG@!P-hBVV5}99wxx+?b{({@{~_rECr1R$cPj8;jP4B|%ZQtOYCU58GHvFZ4oT z-v>oy*hmLi3i=X#jy^>n6AF8j#CUP#b90WlD3T>34&15ps&v^g3K1{s4R^G%Rzzwo zX#^hueGYrT|KA!wVU1NGE}6AdPL>{1PdcyLJXKj%Syrf@Ub%Y3ndeWGE6d=Fi{X5J zU_n1UqjtvSvD20Dy#0vF@#*pftICye=kqX5wtJ5GJWRhTBa0(C)^;7D7-GzW26I&E zCad&zMsr-1@3>1}1VD3kr}sB2p?fN8 zks|zC&)V*RXX`1-wn3vgu7Izmvke-Z#*A_^oZvgzxdx#Bbr)4QlY@vZFv$?t@PacB zE4Wp)B!@(McM^RKHMcW6MEBxKTD-x3BY;B#OjH%s}y=Xs1!OUr4(9_xLAf!k98It^_+$b z%gFal`fD0?aL(ZRLt z7LQzjc6}YR26zuDImlVl7L02)y*}LQ^^y0tzK?jv$Qz#~HvaA8AgSq8N0tHi+Yts_ zr>OB=Xav$lW`g|xqb>>$vdj6TGK86J-XEQP`&te{iPosC&whjweIMJqyn2L29?&Gnj5YHK-QyBdbd|8a+kpPxnNS7Vlf~+c zUY&MC?N2f=G$_Wg*GcWk!q6lk#_9XGQ>O48AdoImjz2NZv|)~PP%(JE(`q~)YCS|_ zFwkfu8!jy47z$>hj-R;xXKpu-iAx^IElX5!D+_bA4Vn3=S z(=S@?+ix2-kWSuW*n3?7#|{-t#alCzv2Gr=?$H}=&mg`Lia?`1L}?Bz$8;-QEi~s{ znpkSi3d<$vWNI5?Wu|eL{MxB4i`Ck}c7`dmL&vzHS~*mof{Q-a3ns zE7P*6B=F|A>msM#MG^cecv+L$9%s#|qp38>bW`_OGmQ745b(C09V*Hc2MT@Ir$d?h zK7;f>SNUq>y-rB~J2cabypoXq|I>^>8>|>e{|Cd%%{S8jZpftTJ<|WN)fdwLk)TD= z-wGd3(jVeA?EjJP5%o5>WX0WlQuSDk+**-J^(8TIQ?Og(RI64wZ=k#>lmJ&#E2++w108-mQ&te5wnY%;F@h{e7DCe@eec;169^5V-01>LQJN;35HS2xUjn zWk+YMkJ9i8J<5P#528@0-^|M^1=AkHyj=4hj;ErqSj8@iLKT(5rPlxV5Q;=`iN{i#77Wv#}R5bfu?a&Iq|TE^5<>*8f@RkqmR8usT8o{@yiggXyKu?th-rXXw-P zary{-$QA%kc(%dOoe$CazcK$SrxW-?hX@2jV8@Bo<217KY9vt@aA_k^fdBt9qyLlJ z3Hy`9ZQocuUL*QyY*nmA($=bwniSiQIL!a#uL=80vDy}_Ws)tQn2NAt~RV--%CZ83byCvj|j_gFK>LoE*W!gy?p zF;^xUzbW1LVnq$_MIsPoPmsubradiG35=}(b+{ty za7iiXm||833bhj-Oe+KCZ=LBfj}Pk2doyi@f|+r-#)#E=j)V-h48Hs1a_iwltX0e4 zLQcv8vtC>OdpRNS=iqL6OZ62n%AbzIE(3?pu-j$gRw1L%DAZ0vpwu$Pi94M)$x$fe zP*dywSy=xY!Sz3L0LO8PzC@p+Pf^cn+w$?us<2kvoiqi#!+i*aP7!C<4A9_ z%|#VoM4qiuhOpR<9T11Uw z3Qwr4UAK9vGFll`?8g+2HU?J>I6yxnAwwbEPGm_pY~6O1#U@3%fpf@xxePCh@L#Ze z?16jh98E3X+-{kX4W5f@HN_{l)LP!}WG&yYncVWhe56m(&p;{qz6LMyG*9RgbRS(q zx6@&GkjnX)5OENbs>(uSX24ilG!_{bfJya&xi)Fa^>bjcf~uNE)!v%jiXOU}&=)}Q z=V5v`y^HSTY8F340n!i=3X3@QHu z`u`g|SrluQINl=%&<$b?TwB}j8IL*2CWv#+W;0j($N2Z6I&56Vx<4Wv;n05 z!=M&2OyA#z42Z#ELLdzNk6k9F%D`yTfIyfolZJ9(9y5!89Q1!p|LRyk4j^qibBWbof)R7ds&8rU#|Mop_ogI(v&$ilYER~3n5|UL>PT${S?aGA!GBa}3M=dwF{wHIth|d$Q|B1(3-V`&S z|MwW0`x{$7X`F#R27BNphXxxv<&b5Nx96oGXQ^Nr`u-sWNMaVf5kQu~8=qvpBFm5r z?y{wdEQ4${!Yw};p#T37?f-Q?{})*TZe6CUBa)9L==-Oxu8_drJt(zi!#&y%aNPG{-1h;^5@Fwa4X*JSzJ9;BVSsTjP4*Vf0)Z3%mg4T zf8?x&0>>*Zh5|uz?5WwqtEYgmx|0M{93=NIv*Xp1A-T7SN$!WUYpbsTl~!@~1EGxH zn;os51ZCVHri|Z(B)^Yme_b@OV)aD%+*K6o=MDlytiP8izQl1Cms zHfSS6Y~$fKR(kkZ0wk(WOMv%A$UX*57XoMsFb(x}UDF-kyybM~1wdr`fB%f@f1TF< zkPGl?ff2qX%mi$Uko9y1ZRG-h|9?W@Var+J0)$#;MlL|czJ^?YjJ1;4JRuj5hN`vD z`+>Lshq6Vb>m8zWeAV|P(*H>RJ2s8@Un2bo|NWqpX+KE+ zXS#Z2E1XFBzdx{x0WDt&Fktqyul-0SKgLjtWXVX4@FjUdpP>8bn(u9=!?G!Z#Q`0WKqm%uS6X1}s>fEUQ6R+_1I~BEINS@~hw&gl3A4AD|shNsXo(H5|Mwafa9vXXITHw@8jien>Y~ z3I%1rIEZjwUMZN`yz_F+dpKa2YO2aEib55Y!Ug!JpYSPMa)y2bZCgQRhfj59H>1#MKWpmfd&2aj7?i6r=~08@RzS|E39u<9G^B!myQok4=n+|3;XFr%`fa@ ztc>OCo^5*@{qFS5GRahKZ8~v1$2I9h%WsY`Q8{`RQI{!qE2q$V;TBym1ZMNq6|iIb zKn`P?SHf&e18VJ;v+t}fhh6Dg1SIFB7}ob+v&*YzKt?nH8G&;DeD>Pv>5$yj0+RD8 zH|hKLT_;sfgM+3jN$13?wfOti_hUfzKm7TP-9a%TTMm~)`M#P@D z#0f<=a|MB>^aBR^`{`+wwd*!dRV?NT{4e<)UH6&+Ktt9``iB70_p{(-r<7_SNi5`G zb*{HpQ4Z5`1K^qxd_xXtJT6vq1#rs`uBBqiB^$r>_c1N><=R~E!tw}#{gnrb(c{QK ze+>$PcVA_(UAeI$Z+~s;z_Gmu3T&MIB;UyOOsbasABb)7E+_{7g1pFrY@wWETR-Ud|2$B;j!Zx zGA-ScW0{@$DvMqQ&V8=t%*DNCsoMxdfiIf5Nd7Kcw5SbFZyA!!tK);EML2$Ue%TJ_ zg-0G~w7)5!lxwo9LQQscXf1|TnUyKi>dhNU>b@jm&UxYY)`iITNTBZ-kB?$MA(ihN zZzLmpLlvvX^pg>N|J@lNC(1zvs-Z3CmZ_kA+vY{c3+$dkVD6Ym`nzYxBDQ)6)>m0* zaqDwP<+s*W%X2$Xnk+HeKAy()rUi&ZAKPmo!>mEy|DgQe)RaZlAmeqjO3 znwBsLJk~`JqcyF#WtC-xx&nP&)omH5*$)TTLG-B|)hsYGB>C~WHA(aBf#!|nx6o42 zmQRgaKhQTk$8!^mC>2MLww1P>ylL~|`l7!5wz&`2)n|wg-W;X#j^BoMr|ThZpixc; zJGx4`0l#gtayw=prfaCP$)=`W>uBv5uJ*vmzG1c5)U)-Um#+tOEit=p26}%q=l|5e z;CqQ$is0|jwV*~$fA{lW{?b%@cJCVIiEb=K#lA4roKBUi)>g{nL?JN3byTGu8XDZt za=0Q{UM@rYMff)-Ubv;t)H&tfz(d_VY~FDG?fW(72r;@Q0@>P2-Yi$D?%LV;IE5;$ zD{zD~)(y>d#CUby1J+I7a{&XO_m~lgvgbSItaWkpp-o#c%T`BEZJ8PZZ8)uVR-k<| z%p9?u`Zw3hQ0BGAyo+lro}&9;xH%+@#;rJj*cDMkJ12y-GlljOdLvxW5i+~9dKT>F zpKP*tO%BhQSz}UD|I*Sr#`WF&|F?H@^-PUCaG8MQaG9sJ%=25Oz$eyi;A2dzy%1 zV;YD6A|O2i$kR((MP+Go7H7tyG4%m*#`u3qK1|r33~u}8>Pn61$PXKp5$}emOHH*$ zZ`~44EfN{pOqTP&do8F{&Sdm|x`4nRx*7sEZ>mmcWXGCTsF;oiX9-}}OI~mY65Q)r z8#T!P_BXZVIx9nUR&v@fw1^tA(GzMqw4;?##jZo!z2+hXSGLIH!yLb2bo|-Bx`qoSd<-mG=`V(CGX99;JG=M!wXO zWG>{X&v+%f-}$(oqo08GhXcy`=Hx+z5E*bmd5BCcBBgmrjXZ>HJErYfc!3TPuptnA{g0AACG1aPcjrX)9F2T^J}w@y zN{Vxl5|Jc8|97>v97dWT1F#8563*pR?x>Q4A9Kowm}pWW zN=TR@`a-=jq@jpdenih0F;GQf+IYxRkpB+}T-ODQ&i^aq5<;G37k+M6u6mwE?v;&U zFZSMXUG-dzeC<6bNnn+Yk^~-29tciTY~dB1d~;?o2lT(O0mm!fv3lM(QM)8c`obW{OVU?A7AxdWn4AX-bHm)+)tkz}!o=mH(3)%PkEHiEtE#@n z(0pOJ`$Ix*W{n`^ptT8{CAJuDPjqlGB$G^(+XA~L8o`2wET6U28Bw^U+7`d*vF$_n z7mTG+>D!3%LuC{EpoQfjF2ZG~lgul&@k&U<=8TrquWKReN3Vzcag7!} zL|d=(iaFf3qSLYRTqN_4-cr6`Rk<=gI6bsPYcdM{G)!S-!f@+0PdP9OF8vKPO#QTh z7<4JJJxcijHMM?O&o>=s?W=VMD|H z6c%d)$7iX$KDmxou3(efvdXf8-9Gjrm@tR)`GE!f^o*KhZG5^ip09g4ch$;?OJG)= zcAQ+Ncl`a{J(aPX-7{?IFnlxl+NAB2Lk0#+u-A`k_B^;uu>K`+(`ffQLPJY)P)cr? z`|KxPvFn;C(++IRb4Ohko5BO#Jk-4dwE$~8wt&_T#yx4gG5r3vr4&Gl+ zULe`Tqrfu8;XyVn7H*US05WtDn4KNF4Sa>tUW05-(*AYvU>R$$yYj?qdAz$&i@UV( zS^Q`@wH7UY#9ft<;*ZEQ`b@hfJ^_m#`|0!a*_2!S_z5@X6TR;B7HvI&wK__-5%@zV z1cANpsjkw<1Jmw8xSA}?k{OP&FxrrXS>jLdHq=7XDL!RkhDO?`Z&_G?g(m-Uu!_ub zu;M|W12B+a^<&aO5kUDuP{d;JpC$Q1@z59m!YHLe0Obo(RYyHDC|@x5aRjWLi`j|~ zJ@Tx>w_UZip+Xxlju76Lm&*|96!#@0AzNY{CLqdP(Q7HVBIt2C}Tzvzq0*<&e<}wt>+IU#` za22rYRsoAgLNhpqRX#dS2uQ`5b1GBnqR9qlE(Z4Ev0~D}RNN6j&fFcF6MA(QKqWyD_g-JU2zLKok9;|+4BY)oU!u>^ zr|4tCo2D_T6_2j<|HXtZ7M_FjBzW^1s~2lz#~5~6R%gLG?TN1DE5`;;wAqH{afnP5 z)0OXD%S>{5Y}p?swNqr6wB4)Mp4`^D;T)NTZ7(^!SaIh06Xgm!y=VQT&G@H}_=_pj zv5b#1BdVbQsA@`1>jmpohKL zSOfgzZBP6*2L}*3pFju*nkN(XDme-c>}RV5n(Jkn-i9^6VP+{%m@5v7NJ{hwFJn6r%J3Hg5sDiZmBuSzJ6czxyd z4f%inNFx95A1iS_k^dKmHKv68KehpX2t?=q71|H{KU~leGMlfi(a6371u*2mdo2O} z{|}J=Hyd7-`Tv^zO%K(Ax@Lh$eW2nnw82+p(f;2L;K~WV<@K;!=ObPsyIDh8BgB*3K*a6%~E?LBP%s`w4-5vWS2f z(H=6y>1#V>*|NN!sqKPGC|}W7^_VhU9E&O9kkK}m%nV&ke`m)Ny1IwH0EcEiOz)<6 zfObgeo54JYy&>TTXu|~4NoCfF*lU&s?>rDFj(dDe%O_kild-1k973h1W<$At-dx>; zGAS4vE__&CHcDuQ;=4^lM({9C0TEyvg3UEp2Kwy&=V{7M)V7r@z(Ws(BgMNJfB;yf z(rYxPg7pzf?j!6kCGO7GRNttP2d@>dLYKjnkryklGBVzIWn|Nq$*Guj=x{AIH^3hRF-`tysvLLh*`j1Zvl4uZlAFGP#4_WFw7#3O*h4DpzEP7#F}oiRcm zybwUy1urDC9uEipA2$Eu{@-NU3F!Y`g8IKE_CfW3QJ7&O7w)%s0`UJeQ)MV)2?t@S zLZLW9g6fh=90C3R6x6SX+$w}xY>S**j362U-5{XhY6deJ+!#7>1eiF&<{I(|+gp4P zk3e+(UnNV4asc@*{B(4?O4T=OckPn*FdG8p31C4^`OXt?_eQiY@tLJJ#;m}?I8Z@vv`I- ze^QApP-Nk+(z?`FH!$ewtXkBfNN2sJFV_tTMaDNjMC1Q~{$C-yZZpqU0iwv9G@Dgz z(|uCA?wk2Y_AWR9EhN9iGle9BiTFn#Ci1m*_!Zw>xb?2x_|c35t@s?C<{vQh$pe9$ zL7W@sq8X+)wAy~{gKKf)&TIb|XMpz9{FgQjKH+%G(P;Y%Wi4f7`hO+va&0*^m5cq) zRP1v7ovf|ek}u>Q7#Oi}55)-!)_9wK1dw}3e;uZ<1S#hpkYtyw%^}H72%JMtHC1I7 zMWKpH;lj0^ShH8iGeo@&E*W<>A6QEiv@GD^Q)J^`7>n!jTF}Y&SL$a(yIvkp^F=Vn-8d74g=6J z0_qlJI>BW+jswt!siBed3_yWfFzf#+c{`zRhWY>PfrAGLFnd*Xtw!#-JdxH9W8L|) z7gw)<3=9j%03>%VkQ;ABa>HyP=^!`K)!SPrjxgi~G}QAlH&;x7Khcs&2h93#5mH~e;n_t(+keY!>QbzJ~^dl5a>Qx*$9;R3Q}oN&QpJH0tjp`og# zsRf$r?PKSeF(R!yPq;XqmAva+Oe;EFk83Lc)W<0lwH8@dhMFU2Ccy^cPq;Z-wD{1D zKvcaSGsfcUhiTq?kmENPuehN`?FX=FPiw_gz@j`-`$4L_5X3Y3B~5Dou1!~NtoS?2 zPVnaC;wr4Dcn}bCFlsz`7agmdByI;uF#}1Po1<;I(#>&_wE^qr`qbkN?{k41#8V_o zM(Ps0lL>u-?xSnyb}HSR?q1@|eZf7>nXA%p1?oh{o-{Z;G@Q>5Ea<0a)XrP-dp1*` z{7hPX+YWUitF4~|-#3Y)00;dFCXNI{B0f0}F=&W`ejD2WJ#KO!-|X#Gl*6>#0J!FM zGouw4kBik@0i1d0uetNg`1ND?B^DSv&;rdVpOCf}vV&fOuxH~1*-uOF(h~>L{L~rrpSPCk8q?sgqC28cc*L@cA zC#L{4i%7SWsr!Im-hu!=0s_32>^`J<1T1Z;fSV%(IUr=nj!@o0UScLVz;v37WSDbl1SX&rtGmwT`Q@W#d z7^Os-OoGbhOOth8YlZ%Q$(E?=tbzX@UM20u z#8}lS^xZ@mfeSiu2<&=!bpsrvdS+?_9K}obEU!+%;h|aQN0uq7MlEtK?6OhzdI6@5mp9~QCe{gBKKf1KKQ6smUgsdLJ#EaE?;Hy8{@yHKu z`F^;4oWSZ;|F+ZagWpbR+6bPRn{0AwDXSh2E=|0JML*kyyK@=4cty(ERb1IMIkmXr_Z6>o zGNLchZ_{7X2kDdaGju0?)K>)PDG~xVx`vjAU3ASNe#i_0(s7KLK~}ng3`WaQw2eos zol)`vVSioZ?s#W)lSaO_1vy|==~kj+s#v%z_U&;)$!6Vt8|VfuE)96Ni>) z`GJM~bfRX{YOIrdW5_1osEk*}Ia*hcQ-wWZpXb$6i|91(2zf8F8uc*FFBh^c> zXS3>b=-HP}tN^>m^(`O4diJzS&+cI{I$Kg6=+EW*>1nlI*bO~9awn>csW#g(kt6I7 zLD6O&u!Cp(><0m>!B;2${KS(ZPSN8#KM05tPY!|MZ!T61V-immomZ6nK$xf>MxcUw zK3FD(gL#+8w<(_NGO1vvu{7ZtLaAWF70^}5qg1e~syk3&D}{nGVAxQ0-T$Mx?EfJL z5xNsDhTDC0b+bmkIEf52gTul=UvG-W_%qN(jCBSYG%~K-yQcbfjXbav>mZpr0Fh<+ zf>m{k7#S8%7S}^-+t@9oHHJ65@Is&yWsXt~UPwoXr<0Te`u`?4Y2naX5{=)3>(BMy z-n?-rEu2ZK7Tj%$$S&!K0Apf7YeEi`awJv(ViN8&mWs)RXDTS^@Pr3Hazg;69ATgg z$N$6p|MoDcVHghtI*sN?8GC>y>Qg7mSQ@H$ouaT25svAK#T7Tl5^d~}B4ykay8=3m zrLng&?*x!4_QnUl@sHa)yTdz0v4cv19``; z>#JKda^Lj=l1ss1hs70%D zxT=X;4P11^1`xAt<1bePnv#{fHi6#l0$8tVJ4QUGsFbRjM%7+waMs;@rhM^gt~F4P zOq6tm)pAGeYRHp$mVB>btYkv>k83bonRlWTmkmV z9LUL&#F@t4GR1?OEN&QDL=78kC$#S;j*eH57#bp={q%YIZ1A%djHA9-f|b$1wQT!X zaa-gT6(s-R{5Dz?3+~XOqV8iw1|?j*V5ooya9~ij?xd8$!F|EpwNqQ1t*#ZXfrw1< z*!=aU@Q1{AusY!AyI>r_q-lBMS5a~Xsbp|M#vTxDp;jnRvpP+^PIhpUN;RtFv|iwR zjM+X_j86faS(wIeC}mY_yBu31M&*q_RHDs0cKn(h1fp5<3WG!OomNTzIGh1IJu)@2 zVQ5gX7@e++wVEZt(}Kf*ot-c)gzOx%BWKRcC~1$mzN1Uof&af2iT#+XDO~g(vcw|9 zXb~k6CQGy`$_bMthAUZ+P?p7iM_Hny|p zz5`AXmhU8=;`E+_s#j~|OM{}|$kRNbPtbjI4c$(M;Xx`V;{p~mAW--#CUx$&jF9ja zg*^5zIN%C2KZKbMQV(SE@HGU zs1X&fN6raQ^07B*J#;ZV!os~p;TKN?Bqe-`@Ab@e20uzEzXhC=*qd~G2J6=>60Urh zNTl@__y5>y&c>C56?T{HaoV16|Bqc>TjxqLz5nM1TMNJk6M=Kg8!3L9)T5!_k2~9w zsFg%1#~0`3zWFn-dItqJ*Er1m9Z@L9;*CilnZ`8vOpYQ;&T`xXrk%R%%rKDu2 zyNC2pwVic08Yl3zs-VtqFL&D;F63-mtlVFO5VB8J#zm;0axZG22#u}e71tdjf#UMv z8F!%g0LjbCYirKtg{h)Y`ga8W(4`uIy~k9q(a2ZM={#mPirG45`&oTV+nDWQg2Zv# zfRHh}!>B2Alq9Ei-S4xMw~sKRKAe#A7g@jVHR zY&6Ok`li7)h!^$L@*E-q)26No+d(-rSU*Z@qFg(vz`9|r4oj1}VK0iePHjPz(mFKa ze~`u!kGUKvrjN#AxUpQLN@=1kC~+EVh`8A==zz<`Z|LB`>ody#z0mRT%}xGK$&rNp zwYiU9T)kE!Ul<-S2g@)EPV9?o0aZG(0#S#7!T{|fmjQC|j^jJmzYR;NKT?mQG@unKPU zJ!Ig#+I#WCyWUWJmqzY8F2l{HScPflHZK^u_ZxDn-COrACC?{|Ea2cKa?Oht}NCFq|kibq6n4 zRR-Hnp$;92@oW=bJEO$bOiEHimMA3^6(pO*j|K7VG_kvMeeBU;FXh2Ugz=#$^^^6|vUU7_u8x1Q>l3 z{%1A20KnCtv#$*p$bh?bWe)F=0p|c>wxWp4d>3~CAien<1*d7MTFAj|Z?B>prsW2} zT{CrUT}9g1C2Tw{R&xb##_=OD9ZQm}T8gVQ$biR%Y=+}?V7^&t#U4u%VGpT98nj39 zaEUdw21)3}#V5fmJ0jwX{A9GQ!cL$O4r^qr`D;Q#j`rJsUUf|Py=DoM61I#Bv8R6fgb&qA$Gpp7#{53QA=P|ysC zK;HOOl$;T=DGktSp$@M3Hbbk1Z&g!rS}*NYSgS=!zriHbuu9-6Ev3KOKN!A{xuZQKL)wo>5s=F~_G?t6(t3*vTQ6M4j+_SiP9ju0~ zLhOQJ*HA)8Ld6y;Za4gYBGF8s@Ik)86@?G-)k$nQD*mzGsACa8pzy&j{0aI);X{Jp z-<)9Dk(2H$fk5elX;Pm`Xi~qy2FSKV7(j3kxe+@=(BTwshY*ooaoJ7j#Qy{R|0j`h zmes&W1822nLzgR?^l$N#p#kZtfJg%;Sly|mfzwO>vfAz}&PDqlX#ZpV$n?lmyBwGI zaDnT85fOEw|JnMVM#_Z#4ILxjf}0k%>i`|T-z)Dnx8k48o?X2`BljHGd9Z4ftq1PH z?8F0Z>9f0(>iYnZ9s$W+$Z99=<4~01r}r+Zz87qqo-b3b8gL80X-F+PE?#!`+E?)| zXwjb$UOkosv8L!t^f~$zear$1-ugiRB{Y6e>gcEVryaed%7a`|n)BftR@_jXss`kd zS(E{JfFt4)%7MC63)}TDYZ0x^A&m^J|NTGTY^DPaf?gq;fNVm@riN^SH*m$fy}xJl zE3ye0tyoUQLQvmXeF&Ft54z!GMW&@Ao? z2twC-M`E*Ut3G_eQ%h*FA|tWMP-qA&aSuF$qv3=L##Orsva!MSBa_C?qeav(UwuMN zO9<_MH>${X<3#^6ag<7)A@uL)o8c$ZZnjTXHL~yU&ZAlbh90;Jxl!ngvxn&lBzK~i zHXkRj^gKm|GzIy)w#COHM{AC?IN%m+_aV5wuR01CB}!tV~ks5)GvA_R?^hk0azz* zF%G|40LNq1PQ8L)rpfD^qEZTLJXGza#_~=NT}|i<^cngvy_?=echar!f`c3Oh{J)+ z@bGQ@RJ`B%B;!2@wCBhXTaS;Jx8Kjr-QXvR77OVy+b0XV4&bLG;{7mkvWGrI=zjV< zeHOaF)AVur2)qd5ZVKWV{f0xJPA0Oz8@6t{YHg)F4o#6#vbFcGV3ngyfW`3aZt!Ih`r)o75P za6#VsI-C52wS?KYzpmBM(?FO_Hcye(57%8MuEZ7Ad^Ea;C_h);t;~ZPbh04u;T3v8 zBX{LFi2b~Z#Ke9e1%3#$BlF_4BfmMjSkFOnB2Em3(ml9a(=|BUxhMe4)GVg~E?F?(vF#M3NUMv;$xAA71f%LzB{Xbl&4BO5y978}t`u{KGt{K$-L;b&?EwsD! z{~XYAU8`e$alOs~vAAAklgdZ^zqs0qJ>EF<|Gw2F^ndlyTYj|fo*z~1>eT`F{{*7{ zudIwkQ7#``JF;%5wm|zBiR1jAE|&kZEjHquy%URj^2Kei>@XxK*tehZsuZuJgM70N*+tOj@?i#(pSJ$v$a#cwmOSpqC)EqkbYPryROn3_OYCX}p|5c5=%HtqoBe=)89 z$1DE}Hq`O&+twZ>_C6*3HxwvVDrm~h(v`7OGF0>|kX0m5qyJYD^)|9HY=qm-)%!G} zAA)2oL(p1*Q5b~orOKoos;pHTSKs`=CHg##+_p?WX95=VuUY@6w4cBqI)=c_Z`X?& z*>R}={8L7EO&RkBJ!0$9Hv5Ywn>JEA?cd)D2J-FeubuYqXQEZMt;0DO{qti+yf!j= zK>`LsEA#S7!8C(0FW0q>)=ioCA`& z5oM{XwdGDD2|H@TK9Yph24sL$8PhsJPD zWDwb@z;15A>}U&hwQIBC^PzL2gIV$UdRje>Yk^)FiCLE5m9z}sYW@GcgutJ0xBUkF z0FBHjovXN!wd|imU>IYZs^GZNsPlMkYK?BW$Ke;e#+7*T&nwpAcX-8=+ITn+bNo(u zN-c^JGoBU=$%g4{UdwzDaf=$f_*m2!x-&epvfe{?GR6FF(_hmE>67#`FbX`{ooL8X zYCOD6mYV2>d@$~b9e4NJD97D(15lEek^hRL8DsnfH_rvD6biKi!UD_x74l_5kAq8k z-0Y!xKUj|xv`YHjJI>Y*)X3KkL_q~>B6b1jvdXy2fr-II_?;F5MVzhea?(%in=zB< ze8s;99e{sK-Kr5bxg;73rpW;T`9w{{f8tQAv_*l;yNor4%)5-WlGQvR^PY{GHCb)` zzwzS}jd|yizvB0}M3dr3lzwB&e+vfWH};sdh5r9UHuY9-OjX^<%DA?-m~6I|R5cdDueGppQ`3m7X*57B zXp~Yg7m(9>LEg#Q0JlRzSX}5*g+Sa=jFUZCxhq|+`DUp2 z6C=J1%nR7V__mBp#TJQYsUv|rOQxCxufkx{;)Nu}(;0z6kHwEczyvw(!xFY}%anZ- zC1=ES&D6D1Tc+44BHBW&P{38Z21@>Ka6Isj75a>dK(z6Iku;QSBDEEvcsr6!5sbNeH1IDo zUfFg!UnTgCJbT9QDYFQ$`Cp;0B4ES*Rhca$zk=NscI+1a9cX}`2ZoqufDYB=<78Q$xyeFYm%zc8 z)8z~9{n3s`e{jq9zYAx@FYKoio3`NY`YhCLtqd>KDMMR{?(}drkG6;6f7%|~9^yTh ziAfs`aieiDq>qc$Tmf9`rbKgdqWQj8$${Jwb}4FVf#!N?!!X;8b!;+nK2uwT;ERq3 zNUvo4v|ABwa{JJ2@6EMV0Y~cyOsd;zF(u^HpUAt5Ho=6}Tu0Ra6QW zL;g<>Bk+gLionh5^}{u?<2+=l87k4av^rO^3Ye3@>7gaQxe{xgr1qZIcI8?(_JV<} z+y~JIsP+G0LWjL##czb%e3AY#7!U?=Kwzx_2ZSJfLhk;rkZ%!s6I{~icD+(R5@hn1 zr?g`h|NEwC{RoYGu#(aOaBej?vIGG%(#QhzKgj=o86-Vlev_+0JRs6n1z9}-P09A- zqH{qYQV*jK)4Sr*vxN_juJks^vw>Uqr$M|vZCI2_F;bi{<=>KQA=aC!zk2);e>!vM2 zr2pF>vAxJV{r_uQaYZ~J{ZCLyNkl`FIt`@%rLG=7nM3;D4@&a;2~5`e4iJCYqtXAY z1?R}8hYrW}jEn>|=RS|j^L1Rw^Y)fj%RPYGCmmuVE&2v|+oPdRd zvGtSX3t+dp^gD{a$;)}Pk%T@)WF&&F4<6VoCLB`ObaQjf`|RBnf7@0j*;tge3?}vh z*^^YTCj<2cvScLC+_pcFcGW?)6~cOR0E>^T#3PeKgSq@be?L8~vX&W59j}aQ_1SRs ziZjojU^ZLUk4%qDjcgbiRO&tx!OA;PBlBaGG1Z=VV+uDizla){KcTYLJ0cmra_1Zm zJ193WVD^j{O8B%}oUm2QHlMori~K$xIffV`05(#ABOo6l0xa4EDMs=4b@T8G(IRpX z+|Vx~5EKFKV|vgGIQTDSn!9l*u;Z(MN2f$OGR@AHj>5D+DOp}FL&l0m=HO(Oy6b^o z&3u4gKl5mj1SESc@q6F;7Kqh7ddC*g6Go!)5#<%Y%cn{v6Z@}J7H$Dg2Zi1v));4gOpFHo3lR6Krc`@ze*UtHJ3dYX< z(u|p;Hl6t4m*p6roJxc5I3tiA)%Dhbw{;(*U$pw-{@fsoBE}qkf(hUM+2XcBb`WJ5 zT#|Kr7V3*M@}(tq@_4+JJZ=)lgvdo6bA`{RR9Ljo25cTFJC^ImYUJZ0w)+JV-*d&^ zcVv=Q)I`}`bYJI7YWAy2st>P7BKU3(-QZCw5@EO-5Rb2nC98ZXXfokRmY^x2fBy(L z)4`7XVT~80R8ew9DB}b+!_29+(4Z<0t|e=7m8x-iG+2_$X}xgb+C0*MS|g-MugOKN zHK=x}Y?QK29G24Oesm5s0=m&{+SYpC!t%a6u<60v~?6 zew;?`y0nA1tto8dvp5RmVeg)E^~D+zc0&zI=c(qSr781npVgY1Fh~eNONL@$HuL zx6Pwb7ISH~@mpWAZFq3I=|%3{4I1zFL7SaYH!`C*iMl_9n zZz^~M>Hn-{Qo4q~A3AOb=tt?tYh*W`SYjaRb4C@d%8Y8Sq|^ue|9o!EUSvc#2Zu+y z+vi|e2>rk|clhhyu||{@yVBtseD*_1H5|qPcTx&6%l%T*ZH4AF%C<$^@*+C@Po5y` zFI#TsA^M<3KDRXHYKYI;2G{C98azb@C~&QLugFTk{+IfvnX%jS8o>1`AbyJl0ja2s zlnFp%sgMYfmJW}Y={fEQcP;A)`ZRY2|J6&f@1SE+S!EO}#QEW5b>uVv-L*cH_%>6(d#^qAk!|FGQ;t3xqsW zseNl>C z1c5pX4^i!oBvZna2$M~4djkVj^>%ee{eb#@^?LPM^=kEP>ZE$PdWm|G zdcJzL@`UoZ@*U-Gl!ufDl`kp#l)IHrDR(Nfu&!8DwktO(?@=ns7Gs;?S58vKlo91PrK}vT9IVV&dK88J7OYAAivEKBls-j&NdJ*OO8<)f1^p_$pMIWx zmi`IdOLx)_(_86H^nG-iZljy&26ef5vbs!Nq7JIZs7I)Ws0XU^z()1&l^2y?E6*tZ zp**erF};FbN>|fW^c;F7J(ZqFmx6JbMf50oC_RYQ&fO#A(wSobiHl~AhU@EQj)dzu zGcSYd#LQuET{#21()=@LKw>g~#mpgaJ#A(oTwgP@0Iny^fF{-aSI_jrb$kX^R_2e+ z901oPGqA&|^b36(T>n#l2V8%qUk%rP*SEs;-}EhT{fT}RT%Xc6!}VYEx54!X`X;#k zlfDtIkLp*#^>6hlxIUy$!u9L=I=DWdUjf%I>TiYXJ^JNv{d4^-aJ^f<46c8wUkcYx z>2HGT9{m!yepvqlxPDN716*&`FM#VG>Z{=TUj6lOy;eUTuG{qU;JQUW7p_<8=fHKn z4(r0DKhS|+FI}jwfa?YN8E{>tpAOga^wZ#awtgyHC-hU`db)lxTwkr91lMu>M7S=| zPk`%)J`UGc=rG5WhV@an9;Yvb>tXt<;JQG61zZo%2jN=OkB4iIejHq>z6g#*d`^dY zDL$h^jTHY&hZ-sVLO&d?|Di*@6o0BijTC>RLyZ*wRR@Lr;=kxnBgG%+tVR~kK<&;y zb_V9|`7fUVUVi?|W}wr~KWrus*MS-60`nKlK=++roB{ob`S}^v8&v(haHab7kcZ#v z*TMBA{XKB~l|BvE|JL6L*Jtz!T>neI2GaTm9qPUKs17w=d_U;I!N;xF!~UJKWotB}h4SIn?@ z{;-mf~Bg&{~RbszP@z{y`PmN%6w!dbplb zT?^OOR-uIy&#poXDV|z=Gh9!qvQ}{fWFcYK4P$Lbh(FiShcFKv*yJ+HNNj8}%2@f; zGmP1tTnWb1I2}@xZs>ZCdMIOc!wuj2MIaFwE6ZH#1S0Jq0GhpR3cIn*Y^~Kc-1;Jk zXCR9?xW-s^1v@%IzSFr+f znOPS8{$YAIy$b|eTj^@Q33BpRDszfRmS{Xy7KaM89Xf~B^4eGftlM}nckcAQ^wONh zXWtKqn;NmkxbH_6>@gp~5Mabt58cU>x4un(O&_FB($Bys0ODtK$s$k@=Gr!Wx$owR zd|D@93L-h#6{ja#g z>Ho$3bhNfLri1i-%bTaBE93CzNBX`9{022Ecw%K-s|)s5vkf~;qVKe9GbQ=54Gzy@ z`x&I>hdQ4FM~;~ObcDUnGOXBwc4eFUP1~EqUU-n_i+zgUxtiT#vo9!jHk|W33aX$M z*RaFDL2qG=C0@&|A>wVM6ORQJUZOr6YiXA1=yW?(8TUOojfT`I zxXyH)GQ;nC1yqaS{O|uH@P`f&$SwjODdWB^~6OF`@(21bZt= zgRohlqf1k{eDgDtzWA9f6ALH%H_;IMjQ=SE_QddYA*Ue5bBzwJ9a%TTCWhF}iU?D8 zp-24^Hp`%MK%g|_^ior;Hf|R(o*+R{$cvLsecTvBdL3N|l~8~i^3{en1E z3|bS8@OT4WmSZTxM8-JjuYWb$KJOk+T=Z%85QUSpGA8+)3 z`Z@xC=%OKT^QbwfIVwcO!+wbAwa}s|y)iM=He7 zU9{&EsSrCJk)AePxv^p#E8DX$#9nYn+W-6yV*prUMHdVKB#wjO6^rix>w$F>x27c) z^H=Qo&ckx@vnB4jXR*|F`XhDO3;JmKOP1ym@Zh*BT5X;-%}CYFOQ{7gA_a#nDmkqe zwk@#w7ioPZ&9#!gyno+UmYKMvhdxB;emLadS^5lpnm$e+ffoYZ3x1uzJYiCy5eT)( zxUv7&SpTDMB=Coh9|CtQ)KApNSC^o0jA0sFI5s|gw69&}R^gb{AgqTjfKTCA0CALG zT>vhNV*J`D#8hJEubiOT_uL!$6NaheMbyxtH~|mNQWFB&f~oX8~m!GS;y#*#^sa!H`s>%(|?Mh-WiT zDBF;@UZeB>3M~+294_7Kb|0#rq>=lVA-~SrfIGhq*n-9671GEypfZ=i|7)brC<-XLcVxDd{P@~E3Med?M87RL*%R~?tuP@43MhQl z2YPZx00k88*d+VKmyn`BnJNVeD3YxzX;aUHfZ}4XJ8+c&@wT;<@))QJQA(DV%k0(M z??|0JuNuFGE|K9EE_Qtm^R4;YX_HFnRMRK^c0>S4(2fuZ^MK?h7pP08aft>a>4X51 zpq&s(;yaR`NuZv+G&4bhdQ+0AuCxPFoqLbWb6Ec)VE^llaEa!2P3tFXB+<>k>AoOu>QBamNZt9ya)9r(l}C=XmH_7F2Ye@se{KQ!=)82 zA0od-0Zn8GF#Rxx%V8c1dGh z)Gn+*EeWBtt_2YHM>v#rjvTQyYK8rNZte#6M4DgxN$k)HRui#qy&L3Ea2c$8b0|il zQCt??C7OR>iAP)iukruyC-nWoGK>k?5ZL=R{WK8!U1H(NVEgyDb^CV_0u(HP@YwKy z1^x7lOYV}tIDU0gXyg$T7F<*Kb@%gHIEHPQ{lDNRC+D&|L0p;7ROs;sZB7E zr3OnDV7w&_EOjnHXSNryzoplUO)tZ#A^-2Ya*_Y{4HbG6i2(BdBGGnFD?0msnS10} z`oe+#C*LFNFEj4W0sVB1JUE6dHLFr?i}J`)OWQ+2E~S@VXUPA^3}JuCyX{-_Gc=-K zfgP9C1;>tC0a@6fDGR&JkeivZu$~pGC(7rpS~+n^xzciM-avmY-%n4g9sf378Q1Iw z#f=ZHADK1|iW^jngW~Ew$0}nTEw;aNEjwUuv@)vL;~X7aJF;$wwMvaXMg*w9CEw@+ z=O9AwXiJMBt&lSb)!-7!?OLL*(8#^1?X#sf+&rx>*T@buTx8Tg=TQeF@U~{vP=HHL z|IL;knI1ekwrK$vmVRm$fFa*jU_Gt;o?sSo$;gGQ!{=$9)B-#K^8bs>ue^Twx1jt$ z&d(Z-5B#8vobY>s?xSnyb~+4TChzLAsPjCYv(C;O=kZX*P9&%ORO}(PpqFI0PzZ?) zRJu6E^t?uU*JO24G0q?!8jP#qif#_BMRomv3Tv*=IDTN$S`U4Q(Eapz`Ye5hK23#h zl61@%zLW+5Y$MWCMWl?>=hhg0B4x{0U?0+YQs0BZw(HvBv{O!?PN7guRTQeIEpnTd zX_G}lpP8GZ;MD-_H;rf?HonP0!ZtF+UGino0$T(JFq)FDAX;FS%=y3dqJB*EC?9*h z)Yblz4CT{p;vLbG|k9(9j@zOx>pNUVIPTzpd~yfPGs&50WM98qsn`{~QzMq>Ag zt@?yUzPYY*b8QqNtfnl8MK0U3PG6~!FP|eIxu#S`+TIa|P^YGt8+J&xFC0W!jHoSe zj8>r5-!yxiewIe|T_~W|A-OdlsOV>ETr8l;HkVK}{=*2P;1pHfH z>r&WKVM}2h8lQFZLD&IRY#ZBDnJRDCy6q~bjTD?p^M5rddcx!NxNm3aO!nK-CGcDy z-Ivxz!okY2g1vn^onmg^c42Qr_9vIkEU*IgMv4eAsHxIh6G$}ONg^XEWBnn!*SS`@i{0ytMqhEoUzHrJ;hntl*f(3WBe5uopU0kb;P2| z;GvLVnjnBuxon~Dk`q(nuU1UK2?1ogoKW%g&UN8~g$}%G=Nen!n0#eEtS4j$J0sU! z3}FfyuHf}QMx;^l7-4@IaCaW5pAD8jPxl~W>N{E+g$=U*zzpQ6S894n{uftG(SV?5 zD=b|B`~RkD)^-d-j*F;aDoU)eB+o43$Jh}-sY>h+2TVYu=%j?ZUINw*dQS!ci^CjcEh!mdW6Gv{vX;`@Vk&Biq7^A`Nf9iV)viWB26+qe@XaQOJUqi91;VFx z>b+Tsk?!2~@J5NWv^h#>3=15TrnXpyD-;@5uIf78KFoZhX`LvIDY_=CMGLl@6j@7G zMS&f|#)^OpBv`BkOl9Oql%}%U(wb?MPNbpcV%%nUomcsz?K5O;i_$3qf9T>u;EsZR zu13C!>t_bQsFf^@R&wd>z`b4_SF^`>tq7o$z=}pf_b4T31HSZ*wpaK<76g$0m!&4G z`9S{PiU!`ti~#cgF$2sc`ZV+ZI|$vu1q6&FJOX>y>gQ?XfwNJ|mSKoe0s&Hj(pKRA zE8&|ghV+j>X#T(N1^NtqnBGl~r#tCZ)DrLydAm>K|JyJry|e8VzK{h0$;XXn50knkSN3K`>hZ{9;28&=4$m<84d`NGbp-y*sAzN*gT-fuyY(%vcKoC;(~! zM4Cqw0!dR9Qe-5Z{6EnDp1TXAfHo7Eh)(|9h3kJ&TLO}PZ3vdGZ+nF=WI+JQKUr$R znhzxXtZ3kU%n0E6U(5h=i9Vh5e{KIS>i=?S0?{IY^}pBS`k#p*F8c^r_9?vw`2QPB z$niH$1cLMbl#m`!_igC^BL5$`evtofgRpdC+bet_3j)ah%Tg28d?5dCMFa0+MgaN$ zm;vSzJ@WrtVC>#Vfd5~G{J&ZM$p4Gr|KA7v{~wK3MwPnB^3^NOJb$8G868|ZvTlgY zI~skA2*`+8>-ZZV0w{op4_n_c%O-$;{(qBctG-vsQE;lJsRf$rrL}Np^8f3!rB&9iUj`9bvXiiuFx-lV}6Bgdd7XH?FWU$aLljkk+VSizaRc@ z>GEdpxA=be=Q(iXi0MyLwYN65vITr<8t}pee7{(``jd@+PCxHl`hX2=6av`bzz5$5 zpss>%s04cSC97chDHJpi{%Km?_*Img5%QX;Yp1pt?1i>aD-@_X-kJP`YWN1uBB%9& zypXj4M{(i3>_bS$CRIllGQPA0L;gPvHI^9v-xHPpSKv%#dVcd@<&J3YR`oY%cLl^3O&C!Ug;|*3H$9oim7s(spRKJNoHpW$n7nQ?7W@M*{xel1U8HIU@ zT~g>xJG5olAST-0X8na!!h!z&tiv6;d~M3<*ND$@TxK$5^q8p*ehF& z={_DQpf%~z$9IkDt2J`(h7^~nbo=bf^@}yK?@R%O02ceUT{-z@M^ZhU44U|AVi~1X&>Iy#DVO1%Lk91UwG%ogD0_Vw~ZTKFYi8F-(yIhso^=93;g7 zQqXYQcgt|X`*D|eO0zB>e7=^8;6D+!5c#Y(^wxraAA(;}9ln;51bQs(YIy%m<1Wz~ z*>w2)Ny_c?Q$teTSt8%S+ASU2|I>Lpi?^-$k~%?_L~-{N$M;Nd*;>G#~fIv?*)_ehiSP1a81iphIuOEaj}{!fHQaA_=?t_ zCq<<5m!-P)Mj^8OAC>5YK1+TJKgqh;XOagnJ7Y%FUOT=pmkrwR_j@=PYp{$8;^4+I=+${0ViI$&G7S+^fPoPeN^s}gw9tH+T z#WQPatqqRq;>ioIWOY!e4By=-z4%R8l&DbK`mHt>3=G3DQ76>`p zDXq0!Q_jYb3%Q(GRPDS^sf$MwkNVE+C;51l(p{Ma+pAz*!>f3KfZq@SM1U^>+_oXS zg>SyPBDNp3Iqt>o;~rx(!f0!G&3J;`l|C87H~K{cIwH_z0-=t0$l<|pI}FR3d6t*? z8}F7FIl#bNAOhJyAR5iUs8tH8KkTpD+{Y^Vn>6xgn>(!LHP`Zpp{#&La{?X(6`P3F zIJ62ytl|4@=}$oa=QH8MW5_rVK=L^bRHMe}NIsh+v-yjpb5xiyynz5WDI(&TaRhkK z|ECZFe*xXcPtY&b$mh2p`OJVzp@ssI&jDL}=De3a4fOy2L;auiG3ftb@5)?v!2(4_ zAf>!*eSGjNez$1t+mwLY5wRWuZ*GEX_tpBw>lEKszZ{<7xcUSSpm#68;M$ROL++pX ze_?#4LcdJZ+u(vOEePybrC+9zkC&16Vl|c(-V2EFKl@Ncf3rqDA!1PqlKU)!uRa!z zOpR<9T14{${r#wv&Tv5&8iB5)mz>c;Qo|V+eCv!rS9TrhL#3b{E@U-2PS@?AnQv;W zhN1sM*AnooGotGjvSyYvm<|JNe_Z?-e!|9SL(6U{Kc zrLO}2|4nO1tdpec#9AA89~uFa#e{~AZ@_Mq$IJzAd=bakA|en#Oe1Qio_mR+(f=_2 z|K&v!D^^dK49c>>>7n6#eqcerADe783v7lB=eqei1!6pR)k2toiSctJpSN(LwR05iSewG*QFJy`_0X#QuCNQE3glz)K>A$OdlPlAA|(#>MJ zX4^wyNP2}KrEh&?p}t-tpIU-#nYCz#whXlYU%>yjn++cC00AT{C1?gnREi=hOAkv> z-CdG}0EFeE8HI!{s~9IEj#fsMvuu(l{!8N-g%FFCH3ZQ9hdec!HUmYG<^O*z5B5TH zf^@!6xSbP2I$so>?~FgNyMN>M1>c870O@>!bbi>z(`DiQ$;EXO3`qaWQ`_A||Ff1y z=@A6}(6u0N$A$WoM!vQP7mye*4hu*&@f|9TwKSg;JeK|n=>JEs8dFeJn8g+ZG9tcl zVij9TD)}RdaFQ0`NZvqFmp!LG>2fGz+V%fy`hVv#{l9Y~)e~%Oy%M*!nh+wfoV4a( z>F+`RZv*Q8d9+BN{r?XBzhipA--rmLnIu&Uxg4dvy^3;}mKy+f&D6D1Tc$Q$xv^qg zjK{@lt^jWN!8M?kAKLO;f8VP>RFtZkrWRd{L4bjR_P<*|5%nm<{#Sg3iLC$k-T3m>^)WX&g1ZOp5Vhp>Z=+WqZ*3Kxs zk-#6i1Q6J}S>LFU2QEV$Lk2!Bn~GgFE&T(m|9vlkX5TGIBL6QzO?Rt;nm_1E-}mPa zeThN<`F~MJ2T2F{{~&0g-)IOR{~ry%?g@?jf12wW`2S7F|C=?4{J&uS|8d~|{~4F2 z&Gsk!7g&1WHf9^SA8pT%V9Nb%iFu56GIjgKz9t=wkIAcVzI3#0Vh&FLC8a zl{F6hKY1Bpe=Y74Z_wYSk#8P{OVbP(WKG4grY(&TA9*3rT#^Rf|A+AZue@Szj|V#q zcAEB9!ShXr$%&9cBQ>Uit~H+UChG{KR8~$S1(0z0b-A;$$ zK`K`t{+HIaK`*N;E7(u`2xc;{y=b=6XWKu!yfKccove)I>Y1?~Q|l5W%IjoLzID&J zaV9QdjYv^$BkDPDL5Bz=jliyB_01Z&_q+}hdvjWcozswK>%=a81TFpOwn6>v8u^pe zsmeAfJqh&x(=k>#G63Do0O0Coj9rUY)TJMHjHxLyF!n#kR#wAjjZY{jK^{8qv>87gH4%jL1tR!b|xVVmep6{PI6a zW(fOB-fiEaZ-EYf1$KB=7jbv^nhd;W#p;Q&RR%7m!LC@hd8&ekfQRXG5qd|MnF<>h#4Q(Mj9UrreU&qIi+zA2F55@Fk}}+ zpsvLl=h_IvsrZ$q*y9F5`on_k_g>MB9wk! zlmAJy{lmw*4)34y=F-S(|| z1-k#b2nECyIs2~G@o8hhdVJ8fSJtux)D=L-)H&>m#=`l4s%8jCb1Z;@bU=`iH=?8*^-NJytr%{86V=TyC8MIlFQ z4Z8kgwZg#4`}?`M8~l_zQ+q3iTuV%!rjOG{=tHg^@IwQE%c8qRT$#R!zW+}pA0*11 zbUFMa=fLjEbo%VR{O|7b^ml3Gi-$&_$^6VW=`#2=%ERCnP^Qm*{6EnD{}&@VNNVCzMcC$rZAVDkDLo&yf;ffq z&#G`rFs5jb)a4B9p|$vOV5x$t0*tia`d_00k^XN$5%>n_|G@NUQvEa)VIS09U{<02+Xe5-=mRxMg(XV!ZO?bT~vQJ zXt?GDBX-N!@5!3$m@`G!T_9{6F4wf<00?qYO+N&70w}+LaAus(d=^S)( z`gqo#jJ2Qo{b;YXIvEkhJh>pi7_uJNB1res=jpRR7~q~k7o@uVbu`Amj-FxvgC0QO z4;>*lU!`BCksX&y#G@rxEy-|Q?FZ~!ZJgi1mFwzYfG7;;hlB|fJxtVLV1D#0gpVO@ zD`MeGn$D0RS9xIXVqDISqi_Qg%L}y5(VHB8v_r-0#lfe<5g6o<1Ek@jgNW;YJ~50o z{~Po_`8r{LsdGEW_3JhAxwj#;&Z@3^sdd(f(JWku?pvC(1VSyl#;T3bEhm;LNaby- z(KnxkNMwS)-P`%hx>Vjc%>T5Xz#lq>fWBUTFB}VW9?}#H4WubJXxK9#<#h8w`(S=f z&b)=l6;d!r!31wMHPge|Lal(pz2NAjDgpAlowDF<<%?BJb$8G zSq3K~4d?R%3;O99wF5B5rz_+6fTt+g4CR96xC}ZBKBS`ajj=Xo+a2!1U>o+M$>b(#s#)MGqhf&J{ULBN^M_5hf3izy#$EEAz-ysU z8Ji+UE2Bz%t)ebgSvt6O#IJy9elIK-Mc)7@wAd>rE-6>W9M@Rf!H*s4jXvEt!JPPhjVN>NspxHC-tkN~TRZr)pikaP|@R+j!e;$K2b8r;gsy zLl+}}+Psz21z|WZD=j|JPbS-{ms_V zi&G;Th6WX@9nG=Im}+NU*oyn)2=lp!8a_MNY4M@s)EOf5AqxVHBM@pj`3qFFP%tfM znypya-b`6Qi8&wh4{}H#UP5Q;+NoLvPi?w#W91t5xLC~Wlev91Nm=2BJ52SV(d-mY3( zY4|9UaR!`1-%gY-zy)2L2<%=uqiN*+$!1kSU6fP1Od1iY;A=*}svf-iv>6pJ%*s-; za13pGn*h)Q;eVm+B?2wUZG z3j|OY;88QrdVIrA0TD<>7$BDYZ=JN8Ol2Eb9r=GszE9X+cHH*kW^x*-Uf4thS#3I6 zQ;%F$Syr$wx{5M^;i{f#-DaJ_M(Br8iKAG-MJUIbrcJIk-0F#|xk^?o#z$U!n3^F04hRt1fdr{%~L?^aRf9idx%NQ}54(+%%qoc^!#!jHrJPcIT8!Gqt90jMr&Y?mMZhLzbRywl^`o$Y=+N2`!8k5eR?)j&ojMmAyXl z{Dxy3Pc$RORonl67g63p?}``|29E=Q53Zb04&l^~ziDS!Rm+P0OeujVy)%*{Er|3D{AlpUiG@iKU?Yv2E4 z%>U%y2z?V=vgu~m%@j3q&pEsrjSEVaMgs%uaW@}3)2ESJ&l8twp3o=gKDvf(r^A$g z-*YLpzt_Q=DsD^Yh-`3B+xtH>)#I_@bUwb_*WT3usInJoKJBKBC(bWdmd0V)_y&+X zcWfti5B%&Zhe+I>l{lUzB1RgM8H_~jl6cHP(EkT5M?=?+1O^B@9}OK5XAEvdfVEoa z%3+-~DoO5TZSdIG6KNnFWbb8`DL))6mtB*?LLlfklW6oYLSLfK(Wl@hEiUT(8dEt_ zJlx#g2@=LxTK!zenD#udcujuK`q}fooiUtm=?%d-iUip-Pii}sgG6qC`PmcQBtBw? zY)9RL;KljB9WDWHaQ<%x8R!3YOv1jw`QIOMt@FR3|F67A;13-l&@~9$Ha%0)$R{iQ zCbJIwJ$GQxO#UWH0qJg8kKpvKUawE&PY zi8=y|M(d#u5xSo~PoJgF(5LC+^bvT0P9g-7+PfcZ-@ZZrlXD3Bi{d^$I5S@(pI_bG z^puHUy5y++{q(fToBX)7>o)&?_Pzzqj;g-@oSC`z?v3%@yCh))M7&@EyI~FNZh{yH z+et&0Xe&64Dja3?lHmn^kS3)tiT3F&S zJOm2RuTVIyBGm%$J=h$>6FA3|J?`AhG3V%$Lj6B_8KkEKsQ<@7)-l%qm8S^&p+f}X zj=+sa=tYfu`c$N$Op+aFDCqvj#!29)b;U_qaV~2#8kfBW;e;g*`yY%U3o?w%I94xd zuQafoOw_`@Xvb?>?Vt2^g#>aqXQv*H>Z&YD615)QQTIZA&_Oso+OU=qAa6wi}hykcKvN;PxJa$5$u)O;GUrq@8iFF@Q^d61qUHHH=+>`OZ zukEG-Z2!ZsThdhr4qUvw%sUtE2?i=){b~SC2?ewNvy>}CTH|0!cVmE1*iK@Zx@TiW zx$R?n_b$j~a^S4dGE>Ld)yT_h$8fADQw78mDG?C!{F~o@<=q7S&>;f65x91aK35~R zEJ7uZAuE}Z2Yr95s`~#I2!TJz-8E`yl3Bw1UMQiuH7bc?Pr2I%kR>dIVG z^Oaao{lD-gPuV7`-HlZiR~F|Q*^h*)p|_cV5zBS=qgmLeUXyM*_tf-b5V%7(n^}W~ zZZ>v>=>T1HgwU5@Z<)vGJ@hVm3*AY{L0mT5HuDVP#oX9~{6C2B(;K(`P343_u@`r)mP5qnu*o!ra0Y08JK*_bg`qm`%dHwgA_qkKW zgMI&5$}#RqwNb9ec8!f==bBTi!F#+B;Qh?kr{`4GV9&p)|C1g*X=SzglbjW<#DE(FaHzy)T-KIBpH8oWkxmV|2qx--|8;~j6#`!2 zfB-M{FJ?duJ^XnOGq4J0Z~#bD5=>d1)zdS!9ri;sy-S&?-}EB2_uCRZRF*|G4e9bp zo~|z)#6Aned8t#>o_)$enrH_?bKzGpnEucBpGKb~>Z!^-%877-F185lK2|?MBln8f zh8<|*J9n?v%g{$WQ^4Fl$nLB?UHWS^a^GwL*?H`lDZFjZQTpLfw$tS+n{#6>tOsPp zkdl^ypml(V?!<190bbyNK)kI3g}3v-K#DZbIv|A@un=|#+zk`!P{p=GN7!}b|H7b- zM@FI1{{!LIKN$Z9{r?>v=}!1nYRv)30+NN+RuRW5(vgM2h7K@#>rU*Dm^`0vaqh4TLJy`ZFd0&ED`9^Uxm(_;AE}W)KR#{)s>6XW*`puYTR&S? zQ3YsUdMX@zQ=4jGBiR4Xo8B>2P9vY$fWj3iTtFUn{ViDP1*hB?- z2P%V^#=sKx82pC*m|{nf3{BI28QhQ(yVRH0-Dn+q+G#*c(_omov=Vw+I6sn#xshfJmsNN89jpwhwRA^TtZdv4ps&|gF?~exHmtMhD;9D4@loBTDD`_&Hr?v{v(4kz zx_xt|ToZ1~z@upO$#UoV*@jqd-LbZ)KBA$H>@NGND&&hqc^Ev&-E9;4QP2fg!CoRJ zs04KZdhCD#&boc?Vts)|9@v3x!GBu-9LM1Q0`?AwVyk*qa&+7gaKo(ZGF@JGqs?ct z!(@^st)nh2JmrOe8|ixD&4mkj6-| zfl7_QjuKF-r19BQ>?lvh~)z{p9*1cgnYq#yIp>R?C<@B=3 zkR@6VGMb0^vKxebG_{ycEkE|wJ=h+S7rg)x})1(ZM`TV0i%j)mQ(nc*;aIXTw&k9 zF4+9N{ci9p8(m%cG^ABPTGL%#m#cMZw|J~|Kg{D5zFnB5vPqlIveY(-`@1~-E&Mrs zhTcohqSw%cH0v)hF|qi3z(X&qn~!z1|4$?DCd$joWl9cC_`2I>>kBpVV81(^%FMe9 z{AhG4zEy9Nnw;bcx`1}=-l+G%UY;k3kQ3y0>F%9+FXSg;tI~G5HWcCFJ(uW5YvlfI zBC5>3t66xf$@YpX>;NR*BiY+l&Zh(xNvRE4LWJ_?!rr+ z5pd#Dw#3L>$K2gJ>AKwVYMBCjF5&sVB*1%#pBcg>x^A=@G(oro(^oJwLDa*BCWv}8 zIGp=1K_LHki97Otmq0lNOBDZy?|(&Bb}}smqy+S38tpjrX<^`*e*_|-1kRR+!h1Vb z2eo{yp`)`SU>pKqM`II+*Ejuc{AuxN4+}6h2Mx84a=I&YYIu&dx=uC&%kjf{{HmJE zz-d0OD2Hg79&pp^@tceCn?Dz*nH;#ORBDU*TlI(Qsq2D7{lD>9u>FPlzb!N#ZX`|r zzYI;=9;A;!83O+G*lAso?z|vl@WKa+47cpW;59c-Q6@{jZEId3&}8@dw0Aa%ES z3k$bp)Lg=EkS(mx*PE$d&1R@FWErzw_nFr~i3*pu8zF^bg4|(O^G3gE$49 z@zV%o;fluJ_{%K<%?4z<-)_^BGaL_=i40Rt*|Jg<-rv4#ZYN>2j~(IFY08#)jQ*NF zLZ78~!z{@sBP_MUG4FvwsAp(d%)Ck;pv3`t3zBS6r7;aM^Hi!Xq|M$WFRW?C9UzX3d;kgR&k02{u zk3X_?H9#^`2L_&oi~y3EkOAhByzhlzTtsv#U@)3t>i^^-!u~>cx2k%-M!qydfNq0* znz&h8=%fQXYGIO z{$uD9umGeucd%IJwqiX!bb9t(gj?^qEiZ8<=6_&+_Kz#lr- z2;6?W{(6mk?P4@!FvvR0SO{apJr2%x-Bz6f7XAeI|20k_5^)dtyaZxIJ}-d~un4XZ zm>xzM<+uw)bd!pE&XhfiFfFVe^tHlRMwP(gh@EvqdS zJ`DQ*$LgPiRGuS0kU;Fn526u5;p5Td8~0q1AIK;{9GNSlRFYbz`u;xp0&L0p9DQ1F z|9MiO6lU34{=S5elx>K@Gngfpb7Y?gv8ZCz6LaNXR{ag+T)%AORs4JD&aEfPi6i zhCmZ(=lC;xd^zxc@(^KvF>-e-(T~%}BjZTOnb44sCxws;egq5G0soh9l6-UC~lvMbYO)LK&K>lwv zF695n|E;#*=~$Qq{{IP2QIZ%K%?%Pr70nIN2%&IGH2KCo*J*PDZZjm0EOEGjJhDiB zN$SlFIQ~Dr@@^vS9Djz72?zcUga2{-zmue3{Qn@1|F;lAb3;uNWCF*S5JfHxxHR&ZlO`C6!H^cZ^jADg#Pm$bsHX{hRyP z_fexyk)+^dJpm~_qMbwn!Sl6~!1KR11KTs_^NMnamgxaEz3%bY_Vc$@%%2O?Ob*=g z*;N3R&uu!^t|x76bhDP_YF*LyhrqO*1lLh>kD#bw8LULxD&~XUHAl(b?p^8euW0FzGABnOKytKK! z%k;$>dEiQ%MZhEZ^`FjODOuR_jXp!~rDxG==t9{xfD70giG5mi&BFGy za3}EpPjBfT?d#3dkNh2~3~7zyd9e%67DT*Jj{urE>d}bk+`X9tp8wBG4f(T1_gbTQ zvoJ82jr~*AT!>wG;!GV8NdvR(gg}d#<5_w)MKeby*ph!gwbVDY6;FPf=3K+z{9mEZ z5akl^&?N|gJ(~Uojodd=E^|WRvwJVskJrdoCgdttRDzGv%mKRppTYm%8u8n${QXP9eHJgC2K_hm7P{h;&TNR9cg71?EB9IOUc^_`{U+r zJxo7ABVSsICSC?Bce;d(M!oWvU ziP)Vo3V#m#AD0q9mL9>IuQ^L(>CK3U`CYhQOg>4=1zEa`5=E9Sqg0YwCS>W!kZjYS zJ&r%a$A<_1$NfK@ltq5@Aa6 zA+S%=Pt?f6lC1_56;5cuU=|GE{$GLruSF$=l;w*YT>^o}lcR?TT;c0srjBU`LjXB? zF#N)aEtsPtKMzNYF-a9UdK?55;`TpRIMtsA|G$pV>zwkydm<3ncb4 zXk=&+Lg6o4F5v}P5I`e?ERv`%hXh6jT(qZNAjv+rtPHpopv-cPbN~OfgkCE%wy7xF zzD@ec(EWcZcKuednZqkahRY)> zR<0c`R|a}F^>6ND-ysc_3J_4RR6OtzR}u{p5etB2AGJY(m0@Zp+_~%*{GMGs=9LTu zr)rv-qnSLVc|~FG0Guye#V3tE8YEb^_{66n65 z7yk84Bl;;C`D{N5MG~Pf9er6j30;pzu}xL(uwHaqY>tebRt6Vt*pJ%2^P~*_^o3;YbySr_p7-KoaRCCKSay) zfV*^T*Vy>j_Vc$@OwateK+WX9S+S8$Skk~_Cj^jAbV8`({b2e(eE*;5m_^$F_`Yuo zi`a|a-}h5*Y0Joi?|QK!OLcC^d*2sQBu{G~0#0|3Na(@7|4gKmoI}_jXLsuyeT7E8 zv#^$WW|Bqyr!#_22t$c?CvnrgM_W28aBi6zV9>~Z+VW)uHx5rINowX*z6t#WZ`MZ z3Y}jB@cZf)IgatBpWOO!sZLL>^=w&3n`bNqLtYF2#8D8Klq&=}d|%(~=v?K1fp{Yz z!J7To?%>1G0d=t4o@_8IzWjeKox2f8~=b_oecceC#3 zZYZ_wlxUg^|MJ__3;ziG|3{rBZwjj%gN{{ui>_~!tTF{&Q~+|d88*xCU6 z%5thVsuJ(_+h zjIf$1Nr7rW7XIb-SLwq*{|}X`T(0HJIUv%1sb+i?ehB>kS&?_}smf#XRoo?2+_y%eoa8eU6#iQxc*GS24F%$`#+-s7fQEu#_(dNZ z4F%E5z$`%%J?Hq-TLl+-3vPxE#`NtnEc}n%9lRbG0r}Luz*UN00;uXa$*k~mr@JEV zp?pN3jCt@tpp7biH_qANfh?v`kAOuOaQ)AERPekNfuO9Q@XOXTQ+5TlbO{6=J1y|F z5`e~`2!;RUkVp!XKuu6aq2nrjGD;<>WwNw%oc|wh33KcQXi6%4T!QKUtOZkg6oEf< zwg}vQs{R&@e7%H&6&XZ0SW)a?McZZ>_(tIuF#hjXfs+X_0i@<3g6lSEq~>msY7Qqo za`61Wps6{U$y1tF6s8W4gcvrOWr4q25%6imxV$wbyuuFw!A1;LaD`v#F{OARfJO|` zMA|w248JLG;Q!=1g#E?R-EoY*RwIv`jntfp52<-lsJW1bvG9MO|NmAl)xXz$R!XeGI9xo(5?uDKeoG?`fJF@Lu~@N=$y}b#oid; zv)&jj3Ivei5;}sgJ4OR3BFFQ@^O*t?pHCR(18G>Ic>LtGm>T z)eF>7^I_v= z_A9?rey#jc`Kj`p`bl~oJ)4fub@a`2B|V8APmiMu>3n)Pol6g*Gi!jIZL9z!b{WgT zf3I;e_&bed;BPgSg1^~#1Na+^hQL4F7zBTfF#!IsaV+>J8;ihSYV?DDym1Wp z#~KR>DL!eu3jDt|y1@UAkpur527q7us-c1ZB|`=O9{notKdWB}{wMVhfWJ?NskX)4 zI_%6=yjhda92l(&OF981?`Zn-KbZ7v@GxRa=*Xg6+uhqAJ|7LwN_^b6z;4jzD1OFub z-QX|L-v$1Fz7hP_>*s*qr=Jb}0{xxfAE9pm|4{uM;2*5N9sGmz5%3H8+rXcpp9y|e zKLdP4KOO8(`}OtUzpSqV|3&?+;Qv}*3;y%^TfqNM{WS2O(cc9A5A@aGe_vk({*yXL zs_<7jNUHFd4w5Q-TL(!M9??$%|6%<^@E_2b)Q&dhgFoLm68zT~W$+I*4hR2W<2B$P zWXuDpYi4C7Gnv&JD%wgbjo@Lw?w2LHFl9Poc-%mV*^jDx`cFQWwhzZ*sHe`pjS zuY2`3g8xPR1n}?Hp`8>yr7r>hHhnSpx9ZSN3ODJ{P6~#89QfDj&{_%~(HDXLA^r8> zU#&x%DSSYOHdENCLz^jV(_vMf(lG}3g-trtqVO&qYEd{-KLY%>=urN`n{_C8VOWPU z7gp;~=E6$72mBQ}l)SJ^hmsfGs6)vMC+JY}!W;B%@P~9Le_=pp<);K)LTN(QuhQ12t1^4}n!Vwx@g4M;@zgVDS$dJBQ~`(yOi^bz_j#cib` zlt(q|*mwEY5B~=PD!SMpfSf-zqKdenJorD3{}(7k82^6;j{mm+M^4X~(_6s0ITl&3 zGxSKKixdGg8AJ+yHS@HZ42pRPz{etZMgUC)o*@$uA@(K%h7p<#I<*v}=baG3`&9(o z(evZNaRYBWe#vpiA3rz*BUWK(k)}{hRhb9FY!#J)#~L!FcN6$SCoKZ|PSwu@lL78O zXi5l82E0rLMK%t7rhLsF39$q+;Z2Cyt~!cxh?eOAcj?%!vGK9(=WnZ+p80cunqjko zt-kW9zVl9f=t{o2ZygSk_0wvKOa(}SLqhCFiebv(+)3|C(n^=|>|ozd|vP<_LgZvpmd+0sAJKi0ps zuUDymUkp|T)!MtL7SepHm?7s=Gvt!$n`NLfpfrXY=-t%6xsN@t8hwh*6#We>koQy| z?2ByuuiDh)KnY>w_6Q)YZ;y-6s~%`QtOdy2)DQ$~+J4rYwhy!R)m#Qn^Z8H)GC->A z@m|QCD4LbB@rtlQAUc^4Kw2-8G_11VKn4p5Jcf@z0EQQS;V=h@5a7`NPp>BMhb{sH z_U+K$4zzwF(s~9y(t0km-gP@JvK7s1!>e6K!hr4(K>qI@tI$Hq!T;egTVAcAWnGYC zF~B119Dq(H1d#vBBn_)9$p0-Q@EAS<$p6E~I2kzv=l=>hjq(4}g5k0ENc|ledEm{+ zWEqZbm@IIw!+`&vh5X-Yd2Uc!n9X9hz6DsoV-a==E6zhi1Hy>W!$$xuDIsB8gk1!^ zIJBmCK?}pWMIhrgpoeg1N$~)d(4c5d5ej#TGfTcDMd>luP|D?MCo{52&RRTaMrQiF z-TZ&h|6iNp#u0YaQELqwVHfG6#_9x8vFvnL+Iv?@Te83fL#;J1gdrq=8fyrkVv;rp zNUpVdnU!o)!w@egvKzq;ui*WE6vzMCfgAdD=>OY*{eKqBiF|OyPwTbd?07654*dUh z9fM&2zX%}z_lq3Ic-;7ZHj(px=W~P_lj48?@_!B>a!;a>|Fh)jJmcHe-UPK{E~imS zH7#o%6(wWFy7XLYvjc68mdjCV0)SiT;yv*QApaMSdFLD(`G2LW%H-|%KV_7DivLe-c8L7HGtd|U5J3Kq&A=T3$p78p zBxfk#|7Rorw`7C-Uoiha3i$sq7W#PPjsWt1?vQ#<5c$6oX2pJ|yLeAL0?7ZxW8OJO zZ~Pzo|2rd!A?y)A{%?;B-l<0b`F}kcaXSb8e-840OKQmf1@r%f!2gf6(8ps42%rTZ z1W>&ui538R#EQq+-@`l6Ab=KtXmEGV6)gbH_~2bz1Og1aM@xV$s(1qs;KBbtNazO< z%xDnUcY(eUEC3sD-E@XOS^z{^0E&x%{|`me?o*K~vVRH0jO^b@2*t%tck!Nh1d#oU z$GmfnLD)Zz|L=@1hNwpXS${nmcy5nCaQ?55jcos~jrMu?yR)~XzYBH*n~%(v;n&J+ zfqNYf{r~4;|G(9~S}|I6=J1M<;qu6em1~E~mBqaieYjhdg;wxmaS+uD zS@9I7yLeAL0?7Y`Vjkw}0r&qBD$3+!hWtM{vJAH-$p6E|H{8^L|DT8a-@+LAzhM5q z4EX=bb*qOrlq-WoWpd!G?TDAptL8Da zP4VpN?|e1`n;X+a?t<A4*R(QX%XoCWO%@wCRVwSah?PFk8q zkWQZx0$ZUsx}Mt4Mg6C<%(FC0=ri3=)Zm3?EhCj zNZ=10A`k%rdoR#8Y2+)o{+WrryT`iv2yY)B9h;~O!C$sUxz|*w{LqBSD%1kjXWkBzW9+)Wwq{J$kp<_uw?z>HiVfTj!=APEmrXUbrC zGrMKi94(ilQzL-DSjk+@+{RqfvW?rBPnkTmYODr3Cn2gCTGf<{mIs?AYXd~6Nt0!W zP8I~vlo6^VIPibvEd>71Ap$`Vxa|mii$)$i)$912x;z`k=hR)VKb=VuG(LwXA*{IZ{>$MCwRcU)?b7yry+p{o~d#{7SHOk-~A|mz~4+pX?{>FMaO%UHYg- zZo3#iSxok5eHT0XF8b%K_*T#XPLIAEsVo6%ClZJ~xOP&T6&Gl1APfy`(tYg42BINN zf<_Zz5zwF>2KeFV{w&onO52zw2mPP!Bk+e#G6ZfO(Z@9M`F><4Ofbk!__LGZdeHyh z#-Z7xF3SPLph-CCvew+zrj;I=v`)+7hB|FfS@@4%*EuhuW1bZhJLmn2E9Nn=b3Wz* zBpmdAvW>96Fx{qFrO-3y|2hz=aniKtNbWO>q5RA>SbCGVtQ&VDjuXoIGnu4fQUudRKA7 z4MY0*8u`=(u_d*|w}bxwPOAaokvjsYLUM=HdxEC=I7ZC%xuzHCs;<=4)E|<r9$EK%b6q64!iXMFD1dSawG7WpFeW2snz6i zN{@LmBdbj9AmQ|EP^IZ4BmY z-HxWce&G2(7x(*VL=S(7MgSR)P{iwA4=mpbZ=(qAdMs3&$;b>Dk3Ttb=>MbtLX=Cu zLzg53_Ne*=8o6(VRJ~KhckjJi-wylzOh{F%$mAYnr!DCI=fMAYkyRcC!ahaB_E|?L z>SSjfU$aMXlX%Iz6ke8f+@=$+2{8HXifPK!cC#m3&>=htCnx0=v&a1XXJ>AqPbQ~^ zajl62oxS(P6+0}qZv?KeaZU*aB+TqkzpaQ1m7f0R7 z1;YtP05wG6kh{nbwL=#mVGv#jgwr#|t8|!76#*O7oy%n>jDzX_tZgae!-QT7UQ}++ zCHfAH+`lc&T|&jJ`!?wp!fZy|Kf`Q>QFe@_WmPfB9XsUe+e2*6(cI!v zbVauE7n)o|np|8;27`%40L?9;5qFy(nq1r>h2a7s5TUun&RF17qhS2sA>|}#PzxRE zDfKOz;Y_&nnINfgFiAPBuNnDfrtD=$$w`F$d3DAK`b8SKqrw3rr>rB#$fFOhSdc)*Xjq6w z2*vkAlW*K}MZKAIJYYw`1u4zXbdLEsW3rkQ4(z@e1JoS6gyT?GgFE1foa&AB_--e-cf; zG0QdT<{2}%qAD)(|EQ2pW4_4$lOc8F|2Y2NsU-vdzZChug%I-p#PI*Cfd7BUl51*@ z$p0k}JrFGGGhDa&KW;1#wrGmc?fV^e)j~}l`~O3Q*JtA4^Z(RrEI_Lw$oiB-8loZp zPll8&#e@Gbe0+lK|H)b~#r6L>hzat3Yj+y#I0L=nEfeSTSg3SUv^#5gqE(;a^WG4QJA^p7?x#t3$7tG{~v>#d~bH1lPII}2HlK&+3w97>NP3ps$8iX=GjfATV6f9Z0!U!q?IWBRrsBWH3)MlJ^< z7yAqruLu5rqu4ytlp7i$WRNx*A)KU8yvgY<-V={N-1xtEgrdk1`F|9s$1zXj|8bOB zT+7UX|I@1o{Gk(%z`l$035|U9U1)@0*rO3buo0qo1MvS_dbjkC_K)>%?VC@tJ>A`O zNoCXK9b=V&%7C)!%;6Oy!{w0`E7uN}D+9fo`ZxD6)3ipPB7(~*{^3kVj%cHhLC#Ux zDB$_OwYfXe>Xx*w3m+`eCxb+=3{D83jlv0?sP1{UQLvIyMah^k&BfMmoI+I6i(9@p zMnMLNap3>T>j?azLj>9(aN8RFeHwY_V6;&%bP{Bv0Nwu+@V~d6&{K7dI|VL>2_HTD z`5j@VA5q$j0ndtZ|6fv_D-b#R6^wuJHo+MtBs*llG78c=14i~Mqa5Q=CS<_zkW;5p z@?ZDYO0iSU!S8e6|G55d2Qk3SgOlfd(TX9m_n$io5%hiI7|aMQhjW>;W!2PQR> z180p0Se{Z_i3H-0T@lbuBBRJGI|(b>w(5RsUDdS-npRB7-K)U}0Zq%AYZTx}0efM- zKz~V}qfgT(=%e<5@Q#cKSZtmDG5p#F=l?2MPLy?Y7aTmh8;{aIppj3Xj-A5{IycN1 zG_FtYS*^ccBlpit7HY-2ZaZARLL(0@PgcD=KNPhHZd${_Y_?}sH$7$h_~_U~WeEPV zHOjqa-Rj{DWw=yczYY$)6Mc)cY|or-I$RAqxMj35m}v|Q*UZo+Pw(r^)U)}a%8=H` z=Ak9t4*#F>TR(U0J<1xQWy8O0Qx!ACmW|?{$s}pM)(y05$RyjOl?5#uvP#slZn&^) z{Na_~|BkJ`h?Wg|VVahWe?`-VJwnpnnUPU))`&(`Q>dn@%u^Jqs1!WV|38Boy0qfM zf>{Uz(9oT%dSJ7CoZdt4qPNhUbi~RGkK7SJWr;ha0u!_bI{x7m`Xa@S4uQyb%qp1u zzhm+kfCB>f@!|ktm`Ma*ek07%Ii?-#`DZV7N+LH;kTj5z53 znkDoZdM`bTUPBkc52+kJU-*1U)gb*AMm}C${Byr`No+ji)`=Bu;wpx`+Ji`EMddt{ zQCv_Y_2RJhm{TxP?;$hR1~hURQEyP*L4O7(V%*+y4OJswIT@`74DXQH4RE~scMlkf zM(*7z0C33e-j6Rbs77u+Pe67FVy}SQU+g~4fCuv4Q31$7c3)u4FRJ;6iRngVAfgKo z0r^OCcy;xha!^&F_~it>LGe}Qx&2@SkqF55Dl6XSr~XU*M2bxuGyuj%RH-j08UQ^s zfvD_%vpkehTu?Lsio@DtPC>PL_t_O62)vLG5_$J)2a9s zyC$i^(C{41r+rX3aa@eg8 z#10NDuq^_?^ncdQD7~7%AG!z-*tf&bH1gGr0)~6yFfZ)rYHH!d2Vo5G*PAZlPw@z# zoj^S1EjhZe6HqhO@&wrlijTAaffr(d0NM#;6cgGBct`~{9YyB?0kjji04dQyc<}$v z5eh2-p_3PZeXETO*a;H0W2j%eL!L058aqMpYry}%wzO^@r1NcP%6<@!|ag5hi@kOP#hH&w(I6{p{aX_F> z@qG*xUk-qBNg|O-FBfDm5&j6E;>#b?WTqHQ|7YzC=l@36GGP917ta5+@W*~Vv12ZZ zj|2bz9`tD9=n$(3rtLUop{T8McajQyKut#3jHs@;g=s_Is;>tV#oTI~DH+vdRa>GA zmh4q?nG7u13v2csqGfu(ncaKS=K5-HpIYthgXjN=CTUxycq@mz0?C9;xuC9nfA>Mg4A>#ISHKu-$nI}%JI%;zHZD;{~f|E6m~SX_;|-AC5n9Jmf}-M!PZ+nA~U(f+T21H(yTX}!wwyfK7+7P z!1QeqKvR`1G!fqLZmO~|Q$<*ZAXx{a?Ll&Gid+19)c;ZcZ)z0yvmODC`|(Wa|J6w_ zv!J&wy6#r9j>UhduWItodD*dGCyjP)CRx-UyBF$EWpS=?2K(aPiN1x|Y|pH2ddl|k z(Xolj5d39pfohZDhbGK9@k0=Hk(TY5(@lq~VPUp>WiZniIEoqcH37*;^%~*kw(v?r zXFVaXc`sYNz+O;b|NFF~xTBnzf7`V767o<*+-W+z)xg}&Q^1QHQ6zM4iu|EX^MAA3cit&)($HIW2DpP;M~O_38Mr`DL!uw;~90Mr@TNE0; zF3rGHf3q>%D*XXb9#DqifG!aT>|SpaH1g#mc`0%>ps>CUFd+ZS?spikhU^B#WcQ=J zCm1s|@<2sEcCqWp@uEh8=$?lEe@=8I(YRsr@Zx1>1YWl6>CVAC-j%Tb{~6~h(8HhK z;T$5CcUhnCte&2xY0+(0LUuFby4F|%AKcH}4s955XySy;=FyQ{gc!6Ag=K|-WtE-E zbcEAQY3_YTbV)eOeidD0%&!dsfnV9S3AD+K^CcdGh>Opn{*RrToEv5Wl1q*L|F6!% zLj520f9DqB_AcuG3@OzA-L@A`;ZXng1Q!Oj5U^F>1K+T6;D6+y_gkeZ{+o3c_$Z%o zGjNsSmw=3uT^NcDGgDw*3heG=Zu7U$)zHED;kfvTmwSne&v8#uh6Gzpow$1(N4c=A zA|rA>YvFSS4{UW8bY{*}fm??8cb;@P6&FuZg#h+0q)OZYDjSRouy#htIAMR`yF0El ziW>PQ!I4`GYagG37|y|Om>E~$Hqkx&#v1b+$}Y-Z{4tFG`wtfZ6BNV^E}W{1_7F}$ z21y3(Ax@?fc>e#h>3$HfF|Mo#pgkm1$wXueVcFKz>*~7mPN!9S2n)6S{B0F;9BkJd zEtjKH`~TGXy>o1z5UOce^Qb5pGiJcmN~TKZLkXUWizlf;AnEpy5BQcO2mVj5B=Cn$ zI0E~|jS}qsc^=wB81z0q1!xZm)Mkr60sa5K*%Z0jWOX#p1j5rpxnD^PXD|Nzw)2f{*y8id#8jzX zUY^fWV}^h)?oZ+W7oHJnjF1|<&`#1Q_|Seak`RH5r=8@)fJha88889<(LLBo=2dgI zXoPjlXJH{7O0yd5uaucyQ)f<3PtSD6rP=3MUGYcFFivB|ZtelKt_PdK!XGD0F?s~h zpb@=L4eKUC5PSmKs32alq;<9 zP2q#cJVl|3O2GsD|9Odu=%pyVUIIrHHh@a`OG+Q7_t3lOEp#UxiKzUE$ku~8X?-26 z#T9GEnmVa9sgs~h#$TN*{$C=5oS;geN-3i-8`a556k}y&gaykK3Ia**?+OL9R3;j{ z|BuqE3H+gp0D*lwj9D-Ocq4YbG4Qb~iM~vKLw`)464Mlm{|o&8*JASGo(uAS?vN%k zLFE5VaxMPG=`P+Aj{x$2@tAkcQ7r%0T&;@OxzrdUo(LfSkEh(kmpVBASIBD^|9?$O z+4rtD=4j+ABDRrC;~pfyz5XBY|Jlg@t(J%UUoiiF0ove;TDE6SHyy6-lst%g;aIIP z&POzk#94YG%U*nmpn*gr;Fwns1kgAV1idihqJe}Xy2$@If*Da#j=Sn|D^oE35BmS_ zQCH+9jASQ-dSU|QTYNczm8w?Br>;1Mt4l1p0V@`Gdp(y41T3Z%U95IXu=~#fK9$FK zs{e0GrK}>ZbTIv&H8e{8hOoa_yE|TI9ITN?PQ!t;OpMr(CblCjrjJhXcfkMu*w?FM zd%C;nvdX5-JH{%5l|i*})26}RE&ZeYWBptE=2J7|l4{6-%7D@s64wv**b>n8;t{a4 z1`o;h0?+?`Et80e%xP^Ia@HGdFLKJoEY-B>g#DcU6~-AS7-X@(WIWfWGa~`mUo?~L z0$;1kz)cU*OtPpy2BRnIYK5m>5eUy5#8Ou14~Q}h9=e1eu=^Ziu13DRwDYTHs=|I> zJ%p6VZATkD8hH@c4>r+^jqL?=|385EXbip{vB4B=DN}D0;U~$or9k(57p(tAUkYhK zxKcX18bh+Dpe;rCW1svCecDoz4@~4W6l;~hN#T(TJhB4RnE>3gx)~_?`xw7r?23dqzH(zG?XN*zl_BaYiBSK zNaqLu8HF#rOlW5i4msxxdGP%EdufVk#gyi4YLQ$|b6D42mL{mm?>SL7Qk_ zL>>bZk(al}7OyrVz=Qu^N$8c$>EiG35!g3w90tAr=OHI&SYz+M*xrBO{;z`ngmum& z#j*fPvpKja%fiy}vF+z?tISf>TyFX7YK-M`tH+F@QmSeiRr6G-Y7}fDDgXX{G%bJ# zOgUUSwrgzM^cLhYIdGONrjC}3YR7ywL&0ep2rvVu`MjbW651@%HtPzPx*eKXn_HQ% zT${Yoc?tQyYq_(bCS=~uqg_Yv9}xM!f9%o~6ZwC--VkigoGvPD6%>Xh)Di3XWxnw4>ayWKB2S@bs|4G!>=O&(a~CLg0O| z2q6D=jW_at*HB?VQ3xRa7lkzD!-xN`A#@F583=*fUuPVyk+0$Y<0gt|M~H0>Wk=i(VzP@2_KIf#k?>}(hDmNv=!Mkoy!Z3uO@-9a!*cjZ&QIW7q5xoCT zA=?Q(7`!muoP&zA|yO~M$)1pXXRz<1D7y(q)JqT}BRL(;g#Raw282-a66!#bw2fLe` zf-3cH@-V}&HlUFA67>e~M7e9`8b@m6y2aSN#t_Gz5$StI+-mLS0~GAp-F=*KghuWi z74U2T_df#uk9vwoA^b!ay5LNk`bCHv zo61bGs6Pf)K31#R*YLQ?rp-IXDvK+NbF0oAUNJIU9$B$+?QprWxObv&VK&<{tDBy( zeSCCmqA~=3*;=4A>sAkMD8r@l`gL%Cu#2>8&zx>LTn#%Im8I{lW>+V{+NrgAcjzlZ z=V^{+D6BKhl)pABLbnzTuf!bzQ`A-^y6B_q6y6-KnEF4xiqPl5Lnj)6$pyxIjeK%l zhxh;V+n@N}loK?)-kTNUbsG5`?g47bIqk#?TEqhQ?~8$EkakfaMHBsI4k$9IL4jUeC)2+y*W(&Phjzn-!d05*(%bu0S_u6A_3qnBppe+mB5P>4nS7v@+Z36Xf=Lb4MzzmJ#fO~uH9%Ht&v+#5|CXmb56VV%Kch0sVm5N z5rYZ^5Y?!_bSqxlTOIc&HwFp1)y2%J1pC^zL!&gs48MG0G z6yNOw+i98w+W!Iz2plGLC$N(bzx(E6khJgq zRR<1S%qq6MY*vq>$2~#2vf=mN4jH^I7=gHc|2x2hA9VbncW5H9y&cL2J&gB&6T-pt zf7bs;)mIVtLx%{Y8G(;&H;&QBO=qR3%d@lu`T$RWbvC3O_T#QW+HO4IF1j?KqS$w$ z&u{Hv?06boVm6&H_ke)s|BWGS29d_bA+pZlK7R>XSN6iNrNRdPk$F3h4wz3Ao0+mA z&#so++V@t?Y4DCyH6^3vVU;M>5O9&GDnzmH*}7+2`X|iEslAFhWMNr#aQ9$kP;DIC zJqRJErm;?sMslhrZjkDPjx_h`mk4YqRCQlf>ypX;*`~K0#CqpyqhBN6nwcVUWI@#C zh(=MqMp1XI>N;x~wEDIk_vJ4e7p{c$Db1BD&G&L&Z>Ik3JyaRe8sFXl-}9jRzXASF z!tuW`9{*cz^LoNd(jpL`%fXytWa9tX+&tpZv$aQ_qG ze>snW$2yGwq$~jOiZx{X3(tdd!L}xp0y$E1892+s7AJ>jnI3SLj_n$&?zlU){rqhe z^XCFJlLKch*<^KpO&x39VoB#*r4{^TnT8aRcgZN_qSn(x&1c;7y5?xP9G!Zk=T?iH zGkdr-Eo&YXC1b{#en)84SlBNvql9HD6B1~dq~X6THdb{Gm;IN?ZOovSg3>CtIYki; zRr4rNZ^{!@^Cm!&^s}@&NwqQSf~vWUB1P3)MyVvVOsJZ3lkAuX$E~z}65^of+a%$q zG~VI_)Bo9HLdkas`-`Q!;~3*ujXZL;fc_F3Cn@_l$prNT3V9eyE201IO+vDgITJK8 zNFW^^Mh0_qB=-M#l4j}6o`PfG8Uko!kg+MCkwHeOB(+RvWJrc&ZOA)^%i-e_oc}9i zJ)uW|7u@YxWejNK{uzm4}LyC@yF7s!2jP8AYW_>NofiJ z8bK1Grq={iS}T?O&+1Y*G{^tK z;y>_*4iP{EqDEkM&KQLCe+~+X?OWBGNfz}(-``u||4i$eb(D{zSS3r*5&21qgdJs7 zOK;o`e9S!hRY$;IQaNq zN?;pM_;c;1*}`zzs2tNq zOK*p^c{bYE(8d&wK6BH7SMd1qbfK&2lC~`ul27?*rM(0d}j? zg1$muq%Xi8$j{NI=@ax(4oNpBafT4roNHo!Z|vY$MLPsxw-bYhV?_ceXl>G!@j>G^ z%TvbMwGo13mpVLZE=pUYDSt8*G(e+Or~>x?^QMyWchXVqscyf%w7UQLEZCgAWzY4D zqEf1A8ddXDVIP+h=?I}O!H4B>dJnye-a>c61rBZ@q;YCxp7ds74pnVQg0&nnZ|Bi1 zH@scgf8fAXZeoZqjo{29H;Q&hB2D>vB{k z>{0|!soE4R*^fZ7Yu84cTrRbFwCXQ;$s<5x1^u5X+mryCm?jinG7ld1jth-9XyhBX zf2Rp0c6SII7>C^*rFR4W9}WHxw@U%hZHJ2MYiLzzg=+cS>NPc|QD!evkpH)WBv z%xjE5;gSCbf-i27ksin)v3hn6X5Q*$(vXBR2WE9Qt?0`u}jxzc!FZzkK* z-A$KO-{M1+A+7N(KGeIVf1-b^e`{Z_QXg`#GN?9&9E6agX2|)}4C(M?__Ke!{Ra^& zav=)WH0ERTRWPBzuY#Z!Ve?hEXxG^If}UC#a+w@BOC;=~b#A?$tYbcFzNX+UrRFkl znuk}^AzG#f-1I^jW82T)Rxy7rP^&4|UUE~Z)<$klrP}!Ni{!;8NF11rO9XJ0JC{H; z1`B5YV;^9Ze4Qve=|VWf$xY^sWg7XUhyg$_O5&0mml!8$3coUD;s z=b_=ALFA+NLqa1vaQ_N>{uQbbdMS7*bswE!EZ4~7TmfwxAiwOxdE*p~d|X7oC0cf* zwCoJaH7Xig3APgHU;WF=WhmoJ_|MgqwF}P8@0K;Nt?nL|Q_DzEpBOBr@fiIzeS|(s z?}n`@o~*x@vh&o;=V`ZxNo^+$Ym8&(=??adW1;=6l-{YI4(szg9moai|1>Efrzb;n{-krCil40+5*UugEPkQI3T^FKsIT)lr zP#x@2uEbP{sjCm3wjdx!&wfj>(sjXRNd6d`lG`{H*D@wq{q@!{*fd-xv`bey-Nk$2 z5wL8|XlE9Wy?u_jpRqkQc!xIv%r4tSA0_k^`XYS+HbQ@nK24v13+NDm1_U_pe?=ki zhc1-}+;)MnN+S<#KuZS`e|jt(2VkMY()-~*s-1rm`m`b8mO!vk6YeP*?{eL%h0%R} zOCOX#UTH4^Qhpg*K6EDR$IYZev&@ z4<3bf4u-0Pb`IeFA2R3vlD{PEFQ)FAHyWpEB)HXe_Dk=O%2Q% z8E}MlCRx-Ua8keOn1QF8$!q)#o7FXq#&LKkr`Mh~&1%!OwMaI&bJp>R!^1rzqfBk{ zr)sd$pQyo?#EYoSn6~8a zGMt|WW=$mXcGgys^PTwq0|&0Egfm0wcg-)C8qFZ=oZBOJXHZ(yg;Z9NkW&h|LTUC2x|n#P*o_ZFR1iZ9K*s zTZXXmJ{qQCZwO(YG+0?U~h0 zPuV^`ItCkS1l?Q1n@j|R-ZENVzpl0^m;H{~ulvkvIFzL{$srL;qCEmU)V*6Mr$t8F z7cu!)W25Tj6;ss{I~lliL-JcdylNN^r8Qod1}`nDV!<)Q6x<@f`ekwbFSlr=Ih^y@ zfKK***3Kxsn!q2r2oTt}!#E8l18?MIJh7<)hfzj0DRaFX$8Me-o5w1HG419l8PNZC zGglE}V)Y0h|F1_QqI2Z`PQaHw;dB@8iAMnWzj(|$=jf6DA3-Tql#Ch6oR4n~&C%v) zxg52|9b3cs)tm;QVR&x5x?(zGh9UeSfc)Pta%qc){6EeT2mb#SHb>#mNh#&dClMqUKobKX1@dzOQ=YsjwTvC}zq#gfPEe3BL zb0(A5v}_Lf{}gg~;vE6x|K2f6XN=(dUn4`%|4+Ngr{JWs+kKF+9;Sfz3h1&1c5>J5 zg~mF_PQ?CHklh`-k2T&3*=-h6yW4>OuSNcEH9F+~g8Bcg(B${w{NF93mBCDHjrKL` zRu6B0xfkx{V2rF-$+nemvugU-roqaN%H~0zO9YfF$Mxd;U+cx-bgV97(*;vv=}WLt z>f`htdKbk>6HbuT-z(i-|Eu9VZiW+_BikUpRQ*7siLByoHJr#=()gEaDXRk74&pAz zV4U7t?Mru}{*U^BeHXw?4$iKFyM+vuqO+d_jk^m{{njRWAGNW6*S)9hycU7f@WsmdaJ0a!ae(7!xfrAItdU`0XhY%dcn559lp`19LAvlN|Z5&J4=2pAQ!3z?H z6av^_+f*;vk3h0(*G8ONF135M>aKaoBS2%V?f^O5@3jg zDIK5NH^(?#BM&bUkX;Pyo-R!zJhv3_I(uZu$Ii<=-Q9G0pJJspf2C$_8GzX%pXg(% zlLo7a*i0)beHt3e=TU+@`v0PlU>Gl~xLa=GOfdzRYnC^fYfATo(T1!v(PU#G5zk|s zpQU&r9(k#e(M2u-vjBB`u;nzm5~j}>*8+ay1uvoq#?`&#E3(mE=-)=_1v+a0c#}Qn0 zFP^xc;>;~#b#S!I+zM-TV;Bllx*r-&fZ1CIrd_OCAgczMxASO^m8k#pv#9$I9JtC& z60LKQ*~YMQt5L1v^ma0AgIIaDlkKyuF@26cO`o8T+6KTIEeJFj1O5DLNi(q*0+>JB zV8TPMN}n~m4UhpZ`Dyb_aRQbgCeZ^lf3W_uN|wHY`akOb5;S+z|D)0W9|YN_OaDhz z-~Z!|s=j~hT4OfpEPj5rCYsbM0d$=cmR0adUglGTy0?`;SXHD=mF%->|VkBVR@SZ8lNy z{Cmjjdfxrb>v`|kEa6sXrLP13|F+x59$~LvJHah#7*09_(A-idlG1nTeh5BIsmVn! z%9tGw1kl{V1H~}XK$A-tsA8I}2*l6a!l-d;JqW3cmAAtBADck`|I2pw{ar(bfDFN3 z%aJTriWoxaG0CuRC=N1&1~~AC#0VfmkX1Oy5M-51(#jPVhG6Octh@?&n5ZX!7bCZC zhj9*ch;2-I*PlC)Any{(yGq~Pv)DLWBlqoycl#^Bx@@Jta@WQ%ln(^l^TMGe#MVpUU8&P933-ftXDGReus=!M zHQSAIHFEt~_G1aP(XoljV4DTy8?~;_1=6}; z*}f^)HFf6hr1AR?E#q&!)!`|qF)SAfnxm&W6!>k5CEN0&tzV9-;cL}N8u%PCgj~Mi z=FIA*r&OPVtrjp~i)wcGv&DK?t(I`aQE;CjF0@^yy%ANjxc z#+B9>Qu2RF-b>h@F!zz1u^A=+9mMO6Z&UEjq|zp$*vsNyv?6P@rzXGHG~ZA!yVRka zZEs!&204HFxAb?OTg`1SsT**cKmBH$>i7QzLeC>FxJe}TVRp|jwrb?wxdJ}#piMmU z;d#cGMm~O$fb8%!p48X4L*uDEk2B5V^t8abNr8^c2Exi17}ma1k;|O|@VYO4r9ycApH(wCaLZ>`Yhf*AHg&9B z=T*n}q$9^eLF?Y-GGSL1RhSMBg@|HY5u$S{f8*L-N1wl~G9#@x*oa7MYy|Spxqt?^fu?e__U#hwW!216vd5EyT7`Z!^80Tx`k#UEf z5!NL#-628fQ-yHQq@O{PXX2nqIzs46^q2H;dJnye-a>cM=*$A8e+T~m)A&F4>8b%Q zJ!T|bum!Ab!~Vb9DqVB5T#im@D7Aj|>HU8-7zm{(88g=O;3usb%c9t|SZa=ih9P_z zEl=|b+o6ZVX7pY_STTBA1ejjdMIR;f75XB50X`Sc(WmJXZ~+}6(11WN-frsu^q&a) zp-Tz^Hy>tf*U0CVV(%!EsLQ#*0hciNDw_@FcJ7!x4KjDgV5O#qKflA(4jD((t*gzyAt(Jt228uY>#OR^vigiRW}t-<8tO^|u=r zXyo=qqH@gAETPZPd+Ay98oCgENagTLCf_ENQZ*2-g(>~48UvgCsxxD$z}X4hX6UQq z<@RZv)8eYr_|THo9xvfngMI(O{{KtiMaB#RA%LtY5PUu(BWv;r97gkj0NVe3fR@TA z!M^{jovGwGu>aGoa7dineTgv+`&Vs?(tuFE%IlcOSnb)waK>EFc8YDlJpx|z zH20~B35j1jF*tk6Mcyx6yEVc~zooV94F@Z(1{|Xf>#aF>4vkN>XUGIZkoTz;Po0c2#vYpv~6fQ`@St-A4J^u0evoVdzCy0%RVIt@qQ7Kiw=*+!&+%uMf7r z-0muJk9MfYd@cC*pOP~P`{Uz2ve0;sM)VE%ZDn}+`?lg6xno=OI*Q3>f2JI7WG6I& zJ^!Es{JuH$klXB~qm{u-qterHv)v90COGuLvu`M!_oG+SEL&P(Nj2m^Wk9KwU}VM0 zwZoG3!8Z#Af7c;!aNW7xY13#syI^guf1%Aaxi0ZpMirj_mwj*9*gL&KYtz1BdBxlb z681w-b2O8OtsoVJnHtiztXUwVvETLN$$n`hh3L2mLse zv^P$LO=?-yxKu2d{?9(jRM}794;>6s8Ed53d8fo$AWNI)S4boe<`7uYRlRh6Fd7&bnms ze*!Y?Al5rq8<%S2TQk$jlq|fe$8dW{m)7m9#cN4htQ))Ssx&sy|S_uYON`O#P<% zuzH{RMfGlVuX?kps~=TAsJ>s_rCzLFppL5VQa7k)s%zC#m1mTvmA_N|T6t7?M0rrT zSGh;|v~q{CTe(rWPPs<8TDe@QDC5dDWwWwTIZHWRIZauuoUELn3@ZJ~QA$}kRGF<5 zlrBY~e}Elteno#y|C9ch{)qkqeUg5cew%)cK0v=jKSw`B_rZMbN&0d6A$ld9pqJ1c zbgQ~tU8*it7pcAKk?K74V6~*qfbEp_E5B2It^88?sq&oqNqQbVn~upRJ#9iaw+)Vo_r(t-@|bpPpO8T>z)d@cAN zm^>W(OD10f{>77rfWKpMF8G@#d%%D9Bq)X5=T6Q7f5T)q_-~&qg1>&U0RHMpz^i*; zvJ3pzPr^u??!HNQ4!e(>1Q@#yH?9Q#P~!vOA8bI+UU#=~1^5Nyec->^xD5Q6#xC$R z0}w79FaX=qE5;?@zhnTyrT=FD!lnN;0Nc|47=UW&zm4tS|EB?{mYy@t2mhZ9Xtbpt z8l&LwRU@P9FR8u694fYx%*!IS5~`4z@W@ZV=Z%PH+LmV^IZ16odLr?CwD ztp>E2(q`ig;BPRXwUkDTA@EN(2Ekur41hmuK$|I@Y%BtQsnHMq@dj%-AU{GPd<~)b zkqJNs_dCZzp!v}e9zi#`n;*MbPiIKub$nP2xkV8qkJM(fFw~mQfYf8Njt|=ZLTw9} zxF-bA{^tpeXuhQwWgE&oa-wyYph>yPrQTv7=*_8=xqe zJBE#lM!r!HkX`CmLq_wXLMSE6%VlVuVCWz|W! zc>Z&nHiHRns4}EAPKgWLi(HBMG&>wsI5lJ~qo|a^Y%Z$isX39Wi;fWb68$B8oZdt4 zf*zTjaG}mYXM{f&u35ofnYhHV)_ZnwY|SskZE3riUJeerfPy&e66d=&tvjZZK%F$k zUud2K^PvBgIcu!2n$y7Y4}IDhEf14vnRzs3b7`SlGvy8qb182CX7%e$U=4UQ8s-{q zh54h~e3$Ub0o4Fh130xMSNt^z+%?LI0{?&27!q|(O*UXMIQ}LefLx-xAm~<**8D;w z>MS$vB%LMNX!cv&JJGi=o9&s^O;6cAJ~}p08G=8zE7D=-QEEDmrW#Id<=PMzacdpB z9&FHP3W&N(n(=CQ{;9f@z#lq901{%fXL#9RvQx<`54Z}HYLXYP5H{t<}~cQA#lZN zcVuUv(z^+U#=_{tE~RH|`}x}{xm@jJMpnsL{f09#)9288NHtYu9!#@^5gp*M6jC|< zFCGHk+{a$f8hwgwX#E?Q5d9Prm{`ZPe<(=Nn^wGbmDJ6yLdg>-_|xpYF4(ZTGCknT zx2Wk|I<{+U-1HXYGC6S8>vZa94bP|@^I3Dfb6D({ZNY7>2nda{~$8Z^ANTp5HF?4n?k&x! zWpsO-Q}h?MGYdEs$Zs-EDxTjolOHc^_LG9CHpy=!v8f@WGhOsiLSLaT=8F4g?SJk5 zW9SobL7Y2StP@wU1m|SU=jDG4AGBcoe!2jp*NQrM6$p87`=_@tl|Gr?0TcmE-0nUp<{_h1X>BA!b zmtI7PEFg?9t{Z5K3TGmPEPbUCqG+wSVAKmO|O9rt#cEhNj?s6=P z&b`nH`4n)+MQDO(a}WwQ%dGnd;aPgl5N!^gA(J@*+8kt-PIAkJHizWO)?dvMqVxsh z{|cE$=rQ0mxjk1*!iK%~UyhyZ08IDmZeL+srID{^5f0W)(B_Z;n?v_&p<&NQX-2xf z9($V5aY7&=A9PM=xJjmaftygC!=NR{Gh|7RfL5HuNf<3T&LX9}=C3h(Hy5s{CzffP z$Q7pg#J*GiL&kHY8Zt^HF=b*q=*)uM8*iS>j5cM4YxnoR3 z01;?GU{CiXg$+VwUO%k+DB%Ccw3NKVg`_Z_4%L+VHnJYMV0LuDcU6&u+2Pmte?((xN z>$>Y>`P~(E0RhQ>ZdF%Lb$3}cIInxI_}@U)@s&t~|F3rv z0v}=Fvwby1Bi|WDOIZd|)Oe!CQ`pe*kr9WV-Xff^Q9PP6PwdCok2$-F&}ba}*k5@l zzp}%tc#QpD=X>P;JHseNF_8aH5wftV9Uy@Ge+K~JYbOYZ=liW3ok|n?EIj|8CvPI^ zT;*-_3A&#A2>!SQ&}jC^uF*Vk`qElKBX`TOYq@y*^m(;BRA+6>vJl|wj+^eO!5g=|v z5ZqAEMNmK>sxSG;2L%Lvpw$|;xVZI6$p1+R2vUFk*UKRRA1FEU|AD}UiKK)8^8Zqz zMfOTr+`9PR=vy9+{|EYiNu=DA7yzK|5m^f{J;`4#UBFrt-|P=0NybLjA|UjUwa6DV zN~xmcj01@;p4c(5&Db@k&D9D83Y-3x8lYW%kO^Vch^}f%PV1$;3gaz_V!py_cS0cR zyv35XgNwTp&w^X+lc#Xho)~#7uL!Q0nO*TM!Zj#j>WMTz()?n2lD}L8()6B%iJr1e{S zmVL;!z6|)3Jq7L}*$BBPhTSvl|k2KQt2 zS5W%u$!kYfjEz>tR;)Z@v{D`FUq85EfXz`Fo-`J^2T77aR=A1ca!CLhv>NCMGbrTv z(pd`}Uu-F2WtLY(|NoKoFJxFF18o{I?o$8%Apc*P0zC(E4X7VT!z|LVj`DF0#gjW$ zI*So_xCW|f8dZC#Vu}~X2z{PDO&_9n(L3lax}A=R0E|Um`}!57{dQ@9FYPx-p`3N- zE}4sa?6NA<3z$`1+&?+6FrV)$7wJh`wvA7ODp}OXB_-%Ko$&`ieU3281s3e8P##I4 zFZ@CN2_6CHg2RUFtQCio)e-pQ>jJjZR<9ae*L)zXmhYQe-2W|x@5$=$#_{TKt~oM1 ztDL#IQXTH!I5V%wtXT3{{7eX1E3u zt&TSJ4mkPC&`}zjf{e?8LaqS8Qd2g5=a?A>DSd8Pt0<;;XYMhv$}Rq&g{9RHX?>0c97 zR}WY2rN1_#<27>-0PkG0GvS@DuL8Gb>pHKY4I~B`IBduOcYNyf%GxY&;MNmQ zaii1gYQ0e0;&_T%0WCZQ`Tqb^Lh~{-0<;9z(q>W}#v<6Zv^6h+s5NX1-)L?uhAW!f zU2+x0MF?R%jXDQdEgKW@;ZLaD#AR6;H=h_s8=S1ZG?Wt>uCTBVcyf3U35Z#1ma zjXmWvK=vf&j|t&3sKqMgw>Z)@XzCT~fVR6R@To76rQ& zCuUMuR-&q_nK8@*Ifs4^$vU2V-DFMGDiNx0_UR!E4zuz~gKeLco4I$Z95DWbfSV5r zJiJ0TYpSBqYN6oM)rTn`et;~bFVW}d??6cW6n%_7OdoJ7Hsezwj0<_kN%HOcf>%VenN#SomFc=<@^l_xEY5X{w1T8o#AO1f74vW<;{P&{uR&QipCMi zfw}W!+&WIj2QgJX&vfjj%5RkrYpb z0*wDTOv|aL6fSJRRLFINyudCAhUq1>*ML=L9H+;E#BpSa=6^&_wnBC|VRViA9l17Z9e!wE+O~$g zH;^dw4bMmtcp^zqiJ2t~(?x>_!e&C*{66Ax*ZBz+xx8?66Wm?YpiqauLzoJIsqkt zXP!tBP#4wXoliy+Kn!e8-h=)mv6PUYW8Fzzgjsf#9BOgAu- z#rOILu_v#BnjZfEHB#XIKRgFGVAsK9CInCpfIT4q1YFg3p!wx2rDdiWUgkl4EZQv%a~*qOkn<~5bt9F5$(s=0b2 zovLTYrVLA`Bgp+f6g@fqT)jFuh7Il=G0^FJ z6Mln#n5Q$v@g1riVmvwITwL$)P~;Hal&VeZb1*LjICIC#%TS-&|uz> z0ie%EC1OcLZy>UVq$IBdse*P0Eo^_(Jx_R?_nXkL9o=dS6aJ%Hn_O2fP|X8j=d|Q% znNHT9_bSGLuyAa+TA;aJI1yGcJS+jp6HOS1CR@xkJrD>d|7Y?)RoPC|w<}M=4+exl zln|Kit@VMIw*y0vu)HiGNVhgkA6YvPidz#;aU1m`YI8O6`O{-4PK?j4;<*5&aWQ#C z*=@CS@esv{M&-KdCJ+x{KnQt=uIeZfG&c1|TSx%ID5?M_ zwrPER)Hrm_xb)1`Iw)|sUOUy*ZrUi>5wmrY{HspY#%KHx2*=9vm(vupcplRKiTeNL zR-OUcBGVx>b%{*;k%OTe>Q0~Q)EnN$J<)&}2-$WG=B0RhvL%y*@lQuF=^FG6rGsW)$^ z5kZTn7IJXg3u?sX!*3H;PF}Hp|AkvB&eae8RCtELt74{1R=;ZYuSOgCB9YV;&uupWKyytZYVmXSJZG6s)qe{GjZ&&< z=mNkMANYa?0+yWoWjF#@GC4U<^)XHY5a3eE1d0@WW5Ov7*l3~TTZDbm6>cA{9i)-_ zH_IgFO%8%CV$6ow5tkTq$z=%|8>K^fbXeV) z$58+J!3_h9TF}7xY4&^1A^hFKUrfWLl)oe#vCjz~I7-Ptl<@1nM#hQq-}HaTFX1MF zFulF@dN`10Lqd{z5OIEF_a(J?8o75zLRH8|0M(#b7OU4?SbLpDJ~`ffz$jjPy;eI! zBcGbxeQkH@FU1czJvE;pO%OXx5Y0+jM=`Gd?tMMYZ^EtrusD9$XnmmJeq6qO4p!ac zWJ*{7%NIwtu>fiA=G=AXR2uH%vTHfa@Z*xMni4=EO2LP*v38tzkIjt8w*D+;UWRB|+1T7ZL2LVfwLNjhinY@vM zfsgti$3e)~JG&@Ww+zH|qx8}UgBN5%)Blq)NvEKt$ce-*c<}09e%^^BOmRK*1Nq=_ ziZ7w}N(yy{(;7}|(1CDT3pI)|oYObRa*J=H0Zn|lN+J^@4H3A-S+pLoqVz_4z)E}|PpYKiWl5DRuw2~u z69kw%M`;Af*GhwqKP*V#Z}brGrk|rPA4)hd-VjThvR(++Hl9F{OvqgcX`_T;IQpLr z8cOaZ?30pk`&(*60^8dAjz(-8D9%TBtS`O2s9Y~JEgLr#03)gf%cOIy1Sa*EM5il|8?Eb?Fk7)k;F73#Yl^RPsT$}38zwwGC z!&8@=fQNs4LO=rZDxWouB6>Ra|1;cC`f36n44>XuJ6t1wb~>sqSzqu=8D9@4z*I-j zBXo+!QSn-!|8LwlZXEk;9K1ZxpUd|Zi*#9a{f4a*)sgCmR(J7TKQ?Csj%S`Uj%V&y z>@kO{!)kNPKnFQ@#Zf#d>LJ0aDvsNV#O-yfXOZ9yl`tjJ{}Li4vsFU+pP@Fr^uI!u z5#>_2_zgD>*XC>`>|Xo-aPf;+7TN0!Zz$Z3H2VJ{crF)0G zV}$G8TRRHQhh3U!!mK!T{ifQH8u|2^OgEEzXhqGv0I{jxP^c}?$gUDXoS`LZh>ur? zbIr$d4mV5s0VTJvigb*K1OfvShAGMLw{V&8RPiZI(6E!sbIr8X1J<@o(7w5I6!X?o+_7QEUAg zxp@}Sf~*_jyy{1H5OUz+_@9ygndAQ_guo{=Vdqh`0gc?a7Uvd*Qk+{_<`x|P&EsDo za0JkQvP-<-b6V|<8u{+*7=|f`I(F?W))vC7aAXX{tzpw@p5_UCobID%)17o7{E;f) ztRP@kNI(4#1LHH<>a7oN*)~1_hUgO5qKleoTn>=24nCf!g7I~@$wl<8JW(xoY!#)w zy^3t!SbWS6nFD(vfi`S&+KSSTexS$vERn{u(&(M!Z?Z&XYj^Rm=Wbiyb-%7 zUOPb$wDC;OWvd}g{X-`(wQ;FUK)f`SykI9rW_av zQdQHa+Di@6C;@L6ok>YJjNv(>kv(wLj63tfbBay6miQsDOZ@(CndAT%hIBF(5ukW| z+J+jxw=+Ff?%wLRU7h1k8Bu_O>l`&ujN)FOdwn|($VNRp2PAT}4LGrzG;y`aq&1rY+aDhZP|RNvSS{Qs?EqZOyk{rA=-);4zlxXGUj)!h>*{$&}Nwf5d6j#*=Qdopax zAp$aNOyJ%@a>XDiF2q01g4MkQ1=5mpC5oEFf{-_B>P3X)hFMe+39`9s=K>S2M zGS}_+Z(rZq`!qX&1~c_6A7@vL~RxSL~X^COIw9*s4cvR|1JKp z_&g=c5eaD-5Rz>|+F|Ju4RooAXx7;H$5}8CBO%S;=0ghYW7j~&3F!n3V1xB>uT*XN zzdH$?OYZbalI*+bf!fg;*>`s5f!nC3f0l+2rg8*^=nJ>KtF}lZ-yV*kINW;~k?FB0 z+-2HIwRi_~_dBr<#@q*AoltyMjo0|QbAbI5vZO!!aK&)g2 z#{ZvMGEh1i=WdV{E6*6M0Dd zh5M;*j=_?MILl7B%jJp~|2XriR;2WgS#Vc!42EYs@+eWxr!UbH;U?W-`iR;HC<;%H zxVzL9h5N1>sts#oYEulwiB{4S|9tw4+K@)>o)<&qfy(^yUZr*nYys?vp*Yd7ieOCm zFusUv3m{>H;*;-$B-+nOuznZLnKR@kCUEFpS zX=W2xU%fS5~U|7{k}*1wJAV@ZAH|I9poiQTmLH zs)a)RW>#J)Sex8t$e$jz1>v;St47zsW~`0l zhFdISE5bm3Uon?2QlF>8WK@FU7kOdhKkt!2h~eRoYw_z24`X}Osgu75^CTW!85=sV zpr8~S7Bw zdMDjQAL&+jq^;dC%AL{%npD*{h-nI6n&`n0PHw<@utI7?Js&O-gxgN3EdkeC2ZZ2p zc$7pL5dk1~Bte(uszUJ_yOr9p8o5WR{SU>jf&K3{xf+n=NU7!BvV;`m+mgX%@mtB1 zoAy$Xcasr=XsRzGR#0ZPA|Ri z36q9P&wj-ov-6qR)WP}ZjPK7xY+<9vpJNFewy=)rWP8}re6+8R88t55Cc(*T3juhi zROj)CkDS14n;o29r|KDN3z@h5D4&(KA0ft)zOsM+6+BslCfcwE@qjr^aXJ{-@w|3# zuHSy`o|6P`!maILHs-2#){fK2b&F7D&mib+(e(2h9{yP{v%MI7v&*vK zed?^*n>F%ie{->xhXJ2{Vtj2~Uw%s+gtznqn z^fbCZz0qYYUCzm98e#y0jgCI*yv@~~xmuw>Eyn=XZ=s-3N;NHS{IXgpO3p|*v%Tyv z&;4bZlGA$O$Z#eBPt#5_R$UC@Ab`?Oaj*=YQ+WEH(r**^U`Q7PK6PyEEgJdaHl&Uj z-jMB@Fomf6OE=K|-+}J~?%lq7sn9Fy;#_yw1b8Eroe>jviwHsGP`Y5 z3)Kq3&hc3bUujp*lEj>y`nIpB{IXK0kd4ZdO`qqKYM~Fp_euTz%6_RfUKgZ|4Rs6DK8fF ze=;C2y#7xiKO)NK;F5`O!^+x;8u^S=ewLC0Y?^f_AfI}8&l$C48u@x0hm@!O7%acq z6@c&Gu%2nx(0~*8{*8m<#`gXB)Y!i7xhX&SoieeEEl~nb^Nc-Pm90a77Y(Mq`&Fuo z`(3v-4jgl`A+4@dM<$Ik21Xz*ik)mdA*tKq_me8wvs|epL!LFw@JkUwA>`|g))re;t#UZIFw4sh)e%c zDU?Xbh{tr)$&yOF{1SbR{*FGKqSNSN1Mo9u;4E(WIxoPt57$o8$o-o|vF0woZ?Tz5fi2QUKKtUS)nj@P89#b^ZyDtl=1&?X$`x3YAfK(vN`hc z*u}?y|6h*$zlAZIolkoB|ExU1s1Oa4K>z<^x-8H6*jr>4T6%Yy z|Au82G}UfxTn1C*HVfmNq8gjbsoG1OJrYVounWdy@t*`|h}j8%021t-fru1L3ycC# zFf0eoWG#h7@V8Bsfdsn^%Glj)z+ktW{Wd_fmVzSq+t$_j33j2iVe5=SK2KB~E>ec8 zKUjmUqc^-~hI6@KeYG+IwWgFTuT-GYv*BB?RbGH^M9J-ZhpX#1fcA{FnaK9 z#jC2!5048k4ji~bVPhn_C<+A*1TNFFYb!OfFAj$X!2ADdbgFDn7-FQYL2WvJh7D92#7>qcJoHBgi1Dwg3@;3bPCi0aNz;0HNs7C^Rgi%iz)o zgIBG&HHohLze=to%F*q8R(q>P z?z=p_Z4lYRo2C3wiA3%D-Gqunf%ktBzW*i?B(18C)By#BA!56OOKvC(aRE%6k3kp$ z5RExI%Bq+FI&I$lerqsnDf~Zi11+`CSeHj|9t4+jP)XCybjTj z|L*`Gd@T?H$o~rjW@K4K$o^mIRq1g2Kdk@%;g!4XUCOzg0EB&|%BgO(K?!fAhd}(i zhs-WEi@!_`VW^Ew4)!T488xvfLs)#(MQ$uUSYt^p5b#O{4h|^wX%-%;c_~dSNWl#^{&hecZwI>n-o=9(Lof@@CD}NZrB|EdkBG#Tw&*i+LG#~fM+XAHETFU9pDfZ3&MjW+57=KxQDDtfb%7IlZ32UkmL#Ty-7LD z4FW1mgAnis0p4*RAfCU92#KBWR3W4d>CYtG{$GYeIQft$m(cIPPxpoEhH7gyGPNm% zY)0|9>yECy11i5Eb(Jsv@6<>a3+fcAeTlGd1+CekKDWgGT<)U`X5;fvNZZP4vr5_3~m~jPYpx5`d&vqv+>9Pj2R;Y00KUS{}T?! z4FV1D0vuBmynoY25e=z^fK=NG7rKM;NcUG6coTFN5Fz2*aKiZiy_JKdGidzQ9ewsH zhJ#NPjyx&QTrZ`)io$3=ID$8tFc3|)G3B~Erg9Q32Dic{3VxTu{d>Y;8Bs;a87U2~ zzs4>>ZLU@*(AJ4TEohWdFeAumy)X%|J`mX)!1Bf*H3X3VmjOLK7yt+QpW#p;j}YYu zxTHMnIk`5bk+07}kupQ15CII3hcE3tt#+11{^CFct1z(o+RPc*#t%U5^YDFHj@qCU zBIVO>sOqB>A{6*SBrg7;IdM{wh*oC9ltSDzBi}$NL^Gni|1I}^jc>CE0p$O)h*eqJ zg#5n@m?p7>Bx9ZVSOALnr9oIw0c^68EK$=^M$Baj1g= z)t8Mvfj0;Ngn%0a{IhF8Rke(AK~=3A9#Z{09Q|+T|CFKNJ$NurHJJAY9%0!Ko_|pkmw_igz?Se z=K}YJ`M{@RRFn@pf+aH#5x+8^GCciH$s}Q)IKwqs?Okv}z-*+-7}T4W!yn%8@C(h3 z@)q|`4lK;)Gp~(_vj=9REFZ()Y5yOa!zuX%VV|sqod?y{Y2?PmIM*-?A71ETr-5`j zjifK!X(ZodhgSwXu(j25Ijc22^tW4w)#h2za9P*7G5fHIDvR$J_;zfkY)7k)3BbYr z-w{rdKWtU`zDg|=TCE3j3V1bw9g9@$rN(B(9y&(o^Ym%@5WS1uL3h#Z@BjlsAngzc zH~!7_|0jgNCo|#ZH`Ly(ky}^dg3nNz{RKah>v|lcu>`KpOTBTFgk^|>0Mb9=V9B3T ze8w8Mubv+(S&fOZ^{ir6bi2aS{|eni=uhB+AtDG|Gg*7DMsBIbz>okz_o`35uJ#^{ zd~s-{TjLFloTylr30oH*WRa*eOqIwG%V|{ zzG_YF9F1HzKZfGuUlR83SNAbJ<}uav8@76wjE2->j&{~#vN2N~sg7vP+Q|{vmpW-^ zC;Jt{ZS*p;rr)pf=rR2aM8)CIKg);bteoO`{vY(K*C4X%>wi+nW*yjb{rA%wB#SH8 zu25pSlVOf)drhadKdpPURhU~_wiR|h@YCX4{b;-izk?PPm1TQ!{DUsNh5tm&?>>nm04y33PQu|V%0V`3506(?= zuWbPi?xdQkvWucn*dPxVrs-11Ylw0ST*$2#)Xvq&H{XvIW&jp>R2PPY8^49wFqegy zgsO{D-=6o?J^)8Jo`@YVh7Jg}e`WX{RG(V#M>qspcj~I>sYE!8J7$Oy1y2x_4)%PF zFJp%QiUeW@IY)tACKBL)NOwj-i9mPaUDj6fO9Y(wf1v+g7iG(kiAMXsDEk*j-bnv@ z0;x35^EJMV9Rf)I#}0Ci0+Igb08$r3LHfT7kes3>hNJ%t{U7~%qP`6-7*Y&@Jr~qA zfa(l&w+x4Ivz@?39||sP)~C&d%^^_nH>|5vhc}K_&Rh+@;Iw31=;>&XU+WPK>9_Zl zb()Bk)s+^%7=P>&II~;Hs&gb3VK6$JabD zF}P`<*;SL1AfwC79?&v;DUX0Nc~%+u3B%Ah&}&k7c$w*QEcME3#3G z(&0&0Mym4T=$q$lu1;)$%f%BrCblh5a|H;k2bft79F6DbuTH8y!dIEJ(Ems9H77(Y zr2j(z&qyjcJrcHg!qX%D&jC^!`GfR-GrS}pZ%F^=4e!0+yH_pb;I_9{Q4ZE}eGm+y zYQo@-kp6G()ieJZ^gq-8spNJ-AE2*>AIZXWPi+Dm?9YjTlmbOaKWK2q)26{$aO=X_ zMvZ)9T?{bd=7SUKMse%?Qm#5H!N&j6kx^nRwFu!mra{6@v{7O+m3gB?#}jR(qdZ^Z z%h(|xIr9-aJme@4?SJLKL(;WC``@H7faTjE5YGM==>GxP**Z|+9!`uS)RI5!Ep}Ht zc2qatGtrGEzi-s$N=x?dId{9bBx)+kM#ztaP-$TjEzL}sVTkpmnSp|A4T+9eCn_En zCL6Y6t53gkNo*zV0pI-eCHfrw9etWUMIWONqqBZzXl3TAAH{8o6sx48_SU!37x`3k&;-#kM`5qm{80E6*6MM7ReO_q4kX+|nCi zTpXQ>-m^cN-gEx=#3b{6P#w;lymoZO*l6Xn)vHERZr0_BZ+ww71d@>Od$+lCjQ9JD zzD)rGh@4zT`<~xsb~twIrv`y1d?G-OK%oX^@OuP7Byi6VDU*oKo<6t zwI5m3qvn@HG0)FDIE*=Txzx=8vEMl8zK9c zF-9Z`FQgS-+?Q;KcEaY!y>vWBq*O#nMt+hC(0Eib^|BL>wspZP}(fyucxS1S}~>sgOzAlF@8iKDf+ zagYN@7zH2@ZsQ>9XOyld@WBuT1a5m(?SmTm)*+}Yi&j~Nep~|d-qH!c|E~y;kUI(T z$K0TbE+X>B(ZLpT77u|~`D65TA|8R5V|)+@PyZ{VM99b4g$3}Ec|m+$GEd&My|z^& zU)g~4G1AA$xD_$GeOF#f%Ypu1)z$ugkZQA-qe;Oc(Q=U|P89rDxDNMP1Al4@Wo{_CI7NVV~r}uJdc#Knbu8l>n#&KqY|aap-QjTsj5h|EK#e z&pk)T3pok@0Od)6^gj=jB94Rff5ZTmI(xqd00(aj(*MC>*Ig+^(EtBH2z;^-c2#QI zHS*NBOiY4MbatxuNi1dGG5QfhH>HqLBOm7Z?>3 zx0l3Qa{=@}RS0~#G<Oa z192B=`M$YDIy#t^-6#>XT}aO|fjzu&ygHnlfi~;f4C3(I0QqqL#=&tyjMJPIQX}+6 zxJVH6t+k6a^2g^00fl>eBy_c3ddF24)-KY>b>rRF_7+6d=NIs+AHg8&-U-HO{Db^& zZ42}Xi4^|M^HW>h2KsY(b|k?vbAbtV@_Sp$qIrNqp=jWm$y{Y{|F3pu#$?NyY6wOk*B8P}|MbX}CaG_Jg5SY6|4t65IC@o&igl=TEY7!U&DA#g*v zR@KO^g(%dBQfeBAsRrKvEMxqW+X(we7j}N2_F;|Ov=aM{bbSYD#x3B^Uj~{n-1-l5 zz`I;DF@ffkfc;{{$}>hmIl+_?gA;?B2If;k_;;)+{2QtcDb3oYq5k!Q8w}+|x2bHU zo1`VEP}j*{djtZ#v`%1VzOq{CD|Ut=NAAyQd4_-`OH;yFuuoX$BjWi#vY<0~J-}*L z3!a)YCCdLf0oC=DlmoZ#T3RWgNaIwzMb6){d5lWE?R5&yiOX zE>g~sOm{{Z$BXnq`V76FK0)uKyXYfzG=x9nI2n9OQfgpfge3Lns0Omx96$;cg^3~K z4e6iHOrnN9GA2GC91oY^qe7vgqLaH&;LA*6w1415Ww`Or;H;1p zgzRIN0Ac#b+DAbJye0;nEa)mW+`OuGiAHXl9Yb-b7H#n%6OE4sl+k#My81>|j~Jm| zmCl7RwGlfycJ%gcWD0@F%k6J6_N2>&mL+flMl6A)^_#LC^C+}T?U?kx7hQPKA&WtA95(<_uEq_jL?VV`YVT`Dj5<+ zfF#9>RWhV<{G0OsC4|l;OZc&J-C4DdY2=gHbm~;veA5SNmuX}#`W;H#5EO|O{z2&# zbGh@&(kAEUUQe-4kZkxIa_JK$?z@5(6t(`Roc>4spQrv0*C4Oufd8HAe1pR38c?BX=)}2XtGnUZKNSxFH`yaq>}U1Fb!y-yA-EIzQKWfPTHuUTB<0 z801;rl&nv$FN92Q>uNK^2EepT#XiX!sUa(%a`c!GnJ6)a zPjJ@r4$;9ZH{1-sW^qa$AncRQaPzRPXyn$--6e)Q-UV3!WYD}~xO$1Ra`mH_PFuao z*b)3ReTd#g?*QkX+v%7~wR}C6l2`K8f!u6R}8((GE*irTpd=MYwGXNuupfm{c1f2 zE?f?cfr5hKs@J|<*EFKXRNTeamvmJlpX!gHb@C|Eu5|0fcKQ&I@gWv3Wz|M<#SOX6 z&-MQ#{U6MK%CicP^99mOU@q` z#jXrS!LHyL$4*@$#m}TtN*i!2?MN{=gI7JG^OWR0ODQ<0FlE9J@b4qZ<|3)ty}x@) zmfK#bwtKt{0RdE!hX7tylk(8>X50PH@j;dmc)~#| zV2poSB=Et&AaL~u^&Z&O`<`x@i}Idmuk&3Vo8mo_yS`lR`X;Iuo>Q)Cq4WHPOTEH- zyf$l~HV8;NGdgJ#8ULRn<3xE-nM1E9KZaZ3p*EtwS|gu3KL(Z> z$eC;Oqx9Jt`TW`#iW4VIEL}alLw^-`FS{`5YL`B-d!9Z^Blnz;bWQj=V(E%K{d%uP zzBZPQ`tr5PBbG1+XE0bUh3}OfW%0feRwtB2@Pa&B@uXceXTY3ESp+W1gutNVP3UQc$eW40 z@dS>ox*fBtQC?Ueq=j85UB%f_8P%7ly5vNjq|rpW4RdZ{T85!>?aikVQqin{zP^hm zc1)N?AcjS}@pplmD-^5^AYQfedKY2My=vWN&TpCZTW0>fN)FtuF#~_KKy$s6_9}*z zKS{y~C#*!Co1eS@OpyNf1Wy7l1=1*DYwtq;?+jWB$5^S;4C4KEY@3gMJA&d3)A@&h z|3MA2dJp(ReU-?)@W6Z;+0V1e-`lv?4-;7lGD1&O_ zjFyo}!v)F+xcpzF<@@Fq>FAb-`RfO72j8vjs;wZTpetGt~34rz)@?Qr>$LchW=WO+%gZ* zz=nztG(<*zEw#Lk$vdiDYliHZD`*7000(!9>DrFc+X;LyNC$zd-mf2^k?WS@Y|BuC zv#rPuIy3$?av)Joq=%7v;Km5Md-OT519Xmj{jQ`>&(h0qTGc@@)C~xvn?G@|Ued@_ zOJXQ4X+4bJ@kJ*8=tRA!k!wg704FY@JYH%LT2;Cw*?#AE=uhiJSMQo0e(3zTPFiA< zb8?*jvw-Wk(!f43FJapvzFD_Zjp0WoRilCYv@0H{vv0w3T03#f|Gh-2-~FXonH-G& znqODfF}K4{aleQ0<0rmTT(PWY4h)TZ!Mgb1U?&4X*OJm^*$Hq-JiF4hP$xwoWp?0} zEqI}z8AopCjbBB{87XE=;kCJ74n!^JTd7ndHki`pv|g|pXXe+57>(Q8ZP|d^pCxi{ zry%Kz^g+r@-JYO#!rAa>>LwH;SGwlbMg86t2I+Zm-sbA8yi%}cmsz=)duMZf;Y}+| z3C|KqdL-$EcdA%3OfyOElbkPoGFHg?E(}R}-yjQ-Anm+(h^AxGCJ0EuR3Jmqgp&yW zTN^O00S!Mgn9vYSuvn2`XZ8@ zQLXk>teZ%FBgoy+LJKO-?Ee)~A@t{PaR@go(GS$fuEbBJaHyKdM^dSCMK-K7ed{cJ zu13BQhrML7hGd&~;3n3P%)VjPG$aGBKP)I?qm|QEuNqxfsSa-(H@4Rf!wK-w8j|@x zy|eTwv$}29`e}ehod+id1)j>$R+PvGc>JhHXwKxtdNrN*k8H891@^axK0xS8^f~%F z`ZRrtK1Lsg2N+_6K)C(CVE?x#$!R;Y3vXKwz$vv2Bu)={ogQZMnWbT~S<3wfTFPY; z*Fsu_%dikIMv_U`WjK;bbQjX=73e7abhXBBXW1J1$fh~#8T2I9FBh*Fw%7!Zu~R) zAN~Kxit!uI)(_Um?qgyg29d9cqZ8Emn#D{PD1lzBbel2$$$Y{-ZsD4B`XS)+Z!z{l zHwf`Qmy5fWr5Ex-PaIixC0CK@pgu*c{|^)TFc(NLlDrVOYDj;bMy}nI;c1#{W4VbT z`_8e6>f-9+!pUpxr^PM?Z}$uH`Mz?Ip0s5fGu|12Pre?hZoA{?jElo#R5FG>mk;%? zAKc)hgPyd-u>Ygv-GqIFhHH+{=V|2T)3G-)uy$>4+&jQ1ObyOw04?{k^vSRXHMDjo zw?4bv_QG`oBa35g$no+9WXns=TOU@9_69V@|4#{lPj%WcJvB8DZ*ME&XMwI83Yn6lHCIey5kbam(zJ`pjfy)4sIv9q0`E#0H(a3jaw-Vef zQ<(^pDk$!Y)2sA1Xyopgiu=NKAJY%j$R{t4p>;A7h^0RU*xxC04eQfUfKHqZX-?E6 zY|C&)$|TVGmuAYO^rwNE>?2Wd>BI%=tCbPhpWH+}i&%1!n)3WZZOG(sLkqC`t)pFa zL)Z~I>y#K7}m^VIGyonY;pFL6OOGzz;D8f!&gxx}0 zA^mS38r=7(rvLBaZf3xUNdE@`oM4ehwDdol$m*QJaCKO1<`mk!$b6Wck08@IWI+&= zP#V!pPwCGDG=!7!fs!l=%wlw`U%%9qYPwaeyH9Q83gJv) z`j{QFMR*kjf%d&lqH@N3d_bU?yYrC{qoxP~%~(brJ~-;Uc=+JCg8uI-s3~)TUk5r1 zIb|oHb$pg)PPt>_LPbc5OD=uYwc1JhyK${p^9$sZ#n{$2LpA;XI?Ui+dgN#tFDsYK zTI+UH2&x66=?j=^PzWGP5fpN*>7rsOTFVjrUlL0Nua0O5BwZBEpj>{4-bL>Kcdy&& zm}vNPQ+^(6>VW^Fw|LG{33)shZ1}LG({?;1L~9%VKj`}id@zWHz)gMn;TqX99D)#S zu|aXHVM1L8>cT|n+<~9L-T&QP*Q9Gl{;TRx7*d*5pT>@S!CRoY0p2-c>CZv_cTXJW zl59t9Z)bF5AqEmf!LcZ8_nik(w4j+Ng7JUv@_A;JEwaS=t*hko@t;W=9E6xMjSy&8 z$kD9i{H0nVw;h*HdiYYs5Pxvtg%|qD5YxmoB$LV zJ~NRq<3z=uCdL?g^19D_EfXMeY(#kfe=7MfQ7$6CfS-86^sDs+8rgSf416)rH{aOv zQGLEfzCIa4aj|ZtupeK-k2t~F(gABpu?YXrZ@|3?5+ z%rYDVkpB+`KYspS(G&`@e0EV3s;Cq$K>vR;MyBMOAZ1yGV8%QnFZtjTc~PD4kh)HL%XO2H%L`ZHH(WF zlvG$xb)E@a!b#4ToQhsdRE;^xfDP>5Tdxc+M%LE@BwrsY9d&ff6YgF5Bl{;YIA(*Jd5m`+M7 zr2pN!4!)5W0*2wkybGVV*U(`J0s8+haT&1#DUtiOWyF1bFxLV~6{T)wHR03D3hDnK zD3+Q2AKWwmKA3%po$AxW?-?juPfe2Q+g1>KKZPPkS>t zurQzR3$Vqi-mhlCdE-tdmd5#jfwowk3#SMszQwASYuM0d>67$PuBbDSyt6iS!TkIG zz}1$+{y##Z??HC0^-Sx0+;QrMgLKY`$*Q;0nn?ElZ5kMyPYsi;<|$$c%*K?G<&_FR zM-l>BHO$T}7q>pJ<{Wi$aH7p%ZOHr3&^uZ~d(P490BJAB>4|c%mg|FXF*C)qjQZ!8 zF`es0yhp8JmeVMSc}0T&<{mG>&#atMXt>aG8PScT9dAtk-{%l|PRFPi!6yW+uIO(B zB4AbX2p?%3;a=y^$YbK;#1gwc^9iW*ME587WJ9*+)k-g%@Iarp9r++Zdzr)^sxfMe ze*z-Zj#AWX*6M>AxuqX_vjpf9Qw4v$xtA)Yj}G~Ivlwthor^0G8+E}B`CH>3?En5A zUc1iZPA?p?%f_Sb8V@|Qg-E=blg9&uzC@p+zk}uQDf$?F*raX4m4inpg@9k_VV1ZX zh2B!zVC5rCZ-srMU zEa&Xd6N!N^M8TV@g@V#&44+x~83|!0X(1!Z6mkwxhv6bP+;qCWNF#gW*vb^W3d4yJ za(yNkkn&{L^&C>^`@5IwZ_>y;nK(_N^mj3It&H=1nUIIZ&<(H%Ipu#og@3JUUT3u8 z__tt`f(`suRek)%v4;4lj<~2iJ(9 z^qeiaCRrY6?XVInC-Lku-Y-G-_XAcv?^uD}wzsQ_Nm~ zYz^bRm6eFd9;BNwVy^#xLkN6Q9BzJ-evC$LeSap#k*^t78l)jr5DFDM(>Q+tTwMs( z|9@cPU!fZb{SjO+L;-`z-(wE8QaGUR7|?Cp&C-k|^KUlI6V zNFM~QTBeV{Vt+X<_JF&tTkKm_iP-`6807$N+vz5_mS0p~RR2f)t@YeHy^;7E2>b2@8)XUTz>V@k0>bUxTb)C9aJwrW3d0cr+`GNAc z$^**%%6-Z{q2*XUR27wPBetw7z>==Jm} zdO4k>7tyVBle%18sxDR+sr~BV>OA#8^#FAi>~?-dc|mzbd0P1o6;{;8wj`pVP-xc*^kK3rd(Is&dQO&t!`7pD$`>yuNknY;YN6zBlU zKbwL*f90P{0r1N|oB|P3`ERCRlWqCCQw$IH>zBjz&-IVN_0M$hs9pY3eG;yJtbYWq zpVfE3b+7(mxPC^j!u6B-#c;h*zX+~Z=oiBEQhh62KcasSt{3R%!*!#69$eq8kHd9L zUk}%}=^udW3jMuseY3s}uE*%_gzJ&|S#UjEUjx_I>1V>VPk%dHXX$6aRn<=g9^+;G z6u7>iuY&7y`pIzpZ+#_P|3hC6*QfMlaD75Q9=s{@2ff1|$YB0J{=%j`V$=>T>8BJdbr-9&x7md^w+`lv-%-W=NG2l0N3ZI4u$J;QxK>8zf%yW z{JSak_P0}gaD95}K)C+r)Lgj!W(v0MmVZ4}hU>4UN^t$Rq1*iQk5>(Ayw(4 zI`o9nB|7wk(nWe6t{3VGTtBD-O;b9*b_HC|tFb=t`>6`tPt-1j>-yS9;ri|x^oPRdlr8TvS;d*B6LvUSPyAZB#t8IttskLozU0J&Tt|!%?Ka`HEL4PQ{skRxe z^J^1O7100vH({S{2s>x%i#2lNyeur3FN8*zt3^uPA>`uzz&<}>cdKyx;JD#fpzc=T z*tm~XzBIz%g=lY20zCG=l>CISPiDf-qx558kgrYuAb*}8C$OA2hYo{$X?>7KaJEKp z$37cmaO~p@&bFt|wLJ;^AbwGWx&CKw{4c@rZ}q|s?HbeKqhE7))?j!9czom9sPe=Ju(YpEk-io<2=EHtug-TrwDv7NCJVY zHtTNz8ek0PC58|g=Ox37@z@HXG=RX)*FM!aObBLqZ2T+aCbs^=CE+lAtbRP4eHxRK z?tg~$e<`m27S6k6oYlv!ap2WZ|N6lV18fXv;G3Ji7|2Pt1;7r!?SryI0{7RQ#Dor` zz5S7ued)=F?f+tsVLQmM1Tumy#Ay_ZfIOY^;~#e;KeT<(o=pBFP=f~yK0LW!$a(5b zm9Agbu8jy#zZW^v%*?}wff8hKb#b9C&Y0239u@E$29SBQSEBSU?ax}CV100-1GAUOOMhw;+`f!40xsQE0o>!G_C!SWz|hTcz~pzJhQFoN<5 z_Jbv?u?5yjMkugxqroto@ya)gXnovH`QTs?P0984vYNRJT%(*gF9*a~7?x!~fRWPd zxQakNezz?s!yC*U{0rD(%01bvPh5VAx^Wc)*Fuhe@rjff7QLBNW<-cA%S3d!c z0$J2LrQ7FZfPM<77v$#bJepzQl&IOE)0k}+HMFz;AGZ>gehzlV5H`^w8K9lL2g)h%sCV`w#2Iad|7s|KXKafTeZc#VO61 z1*L!U2Sy%htFK_uYR%ME2H9NL)su<93}Qy$6U2BXb^ru+GtbS?0ynGmf+$KRhBkIE zHwr{}H$Wl7%?s92BtvBa*5Pd~=`0Dt%fe3yaw)L$DTKgfobH4F;pH%!e4&!-TH|d z`O_sa6c<4C#otS15J!LI?r(o<9qd1fWE)Z#aWo+M7x4X68Zc1EGcJWoA+W;O+-1nJ z-n!OM)||F_)u@yhK+cPQC}$%km-0YS4STqFln13>X9Kc6TOsJcW1po8j7}e?`{>zp zr-a(um?!IgX7+3B@$C+WBLX`SX4MG-@=e&CYMh4mc7;+5_02K|9~OM2R<2(V&lK|_ zP{BnYY)`=SP7uiY0#JI|snrrbLyFx2De0W7kz#j1B|Z`Zfviv1VxZ(V7dyp%-sWmu z1#HVD3ra~_b8NTS<{nDFMd7#&*?5~A1aRg~0QRN-YA+N??RJi-v zC@KixgdGKByMok4`+q@QC!GDivHzc*LzJ(=1%prs>^V_isgbV}G@@f*ZTPj~*wgJ~ z!UdLUzXOP_K!{qMQ~*T(A3*gP^Z!@m{`(L`uJS%miI-)gC@gw~k z2PX~pX8nq>0jC~wxH^oBL6|O;wX}g20;JrH#cW1|&g z!(w+D$)W!rKcfZWhL`_SWix>f282Ll5cp(|ezHdHoP)X$2I8=idodDwkp2HpWC$0O zaYhJBSkq^YZ)vzLwyC*7foldx>1Wn({rA}w1g!t$uL=94GTc0(uhPh^=i|b{&?m>j zf&!(K45bpB=1_W(osN#46HG6>-F{C}J#wQOf zy<}$5@YHXelLWtT=z$T8gTeStTY4e~r!ArXe-E_C`6`V6e^XwG9vI}rtbkfMYox8? z+3LTALh}KFIU|*E1e>u4Xr|X-YkH}tQjJt9p10rwO`XGIV-cO&PchX(-5sxJJDsl)Q zJr+5L{T6`AD!&j56<_Yns-c<|U1H15Mf`7cb+&R2#~>K~zsM1U{Fq%F!|r+dsc>%Q z3F%PPl(pLr*59g;`|<2b1Dk#vKY4Y8$ls}vmk_3aD`7IJr{|I-rN_3poc9Np z-d;sHSj+W6n6d3M4E&70-6mG)q~`Jm+~i`1QFFy!Yh?4|1v$byUU+vX4Mi#)03`Oc z+#;25{6EnDJ&`eM4LZ5#hfaQyK1&}Ji$TmSW(Z`AMvfVJf{No)sg~;$tdp4=tB6mv zD(?RiguR%v2}A$m{=b-!6?bt+|Hln+&+?G|_XLmVmszI&nf^~B8)5$+eUz?-8}VWH zyYw?Oa_?|D^oQ>4@2CnX7pE`K-=>kf-=9cRft7pB?z#HupsQV!NCg&BUQu%SRj~i> zG~EAZb+%-bw9sJ+@SSbd!sEAN-}gv6^D3EUqIhEl19&F{0$CDolo<(-*1#v?V68*( zMj#xcded^pj_!>Db)YmPLh*)FSV}~^A&O&amJy<1Uob$xJNz#`Gg3%m0VdOpCA=JkWX+xhYvo+OkFNH z#ar^u{D>~%i;GLQsPX7<|f5j=+WS$|}7$@BQ$`wV# zcWECVsmc-~nd$<X^Exk=SnLBU^`2)f2GkK8`% z%uxQy_>LKl{x|G@$)6MUNkO=MnZ5?j_P!hyMGRSSDT+|Smx7@Yq>AM?0RKO~QXT2v zI5=szsq9ybQ_`1J*KgQ5Q5~)ht7tME1hN@Tg94g35$i})h@bYpq3{SS5Eu+A{}kFoloR37#bM9k`a3o9wNueTs?(GCVV4 z55xYw@qzxFeed2#bwq34yVttQ4>0&9_zufdCzM5W@g(fk^vua3DqgLP@m+buUt!V8 zBTyDWP!@r*2!BJeyJJfsi=fZZ-_fV(Q}i+VFnu6Fgve_Fi2Q#f-69I&pbP2dpxr@WLqLq355%MOJJ+(5NQL}3C76YTvVllLf0kP58{ z2@}wyT2LpM>^*Eg-?aVIj~Rq;ps(MVy|G zY%VW1t072a|3nTwheV9mNU~3UJ1XjbBSEZ)Op$aJ0YzbXBt$w3t3S&K<^O`f8BYFh z+W(C)`@gG*pxqXG=IQSRvp75h%D}L zW|KvOYZ$)sG*9T`bRRvN?xYLhkD$P>J}R#S`@eUi{htMR?>_!>LmEB^)O@5tlRPxZ^U+<>85L=GsqoevG?Ptr%dpoH(Fhd>7Sk@D%%Lz$z3$d7OUDNGdPN01*0(|=Nt z7Wt9DXzC8$AuxEH63QU|XZBzk`5sZvRgR%M;U<;gy2bhjG%~d{ofdTEwYv}0-w(bJ zkCDCpp97ekCnsjhr$Qayj`}|fpZF^|1Tw&H%Ld`{ z>L4|eo!{PxCz1z2tN1i%!zUi5naR<{Z{K&(JYy3}fi{eO4>H?XC}@VQZ{GM-l$?=j z#?Dups}&%Xb!^o4jvx$f10W&R8c8hfc{_8xig{G zulXcp^0C$R?C6@I>X6bLbEtp);D!N1$^yzh)cSSqYbl74DK4b^ zjub%LrHaUfxBy1fW7PVg)=yMlk~SaYLZm`X7jPjFYXeA|tB03ga^!mG*{zsIO23(Y zM@ql7hjhh%z5#k;p$-hYpG_WDEONncY{kkmMo|eU7gDe`Z4l_HLD|;&XdW=hltTWP zC_jOVoZ-eJ_4OK=Uc-leqYWu{kL862Z<7<8#X+F`&g^ydss)-qF*HBueXnmOT-{*8l^hR&;BvBw;)4y(;Ek!OyoQ>js9EF|A6 z!8KbwBd+n8|HCV9V@Rhan>-qu?%VIzrA^Iut%w;@%h?YprZeOA)_hg zOv2dd#avZFY#N&_=WVX`m=<7l%P*@VqurP=ydb=Vfl@?9U7#T&E*dKl;Pab@n0?n`v3BKy#_tn1E6fftAB`lhq4WEu=JBt`5Zs7 z3F+W#ANhZO;FKjc^8Y3#aNn3ik3|080Vv5mLjFHi*k_sl2m1g0gX3~4|0=O!S^C0| zK$adwt`(G3`3Ds)e*i9)&ZM!69+iKtxU{{%?QvtHHgLpqi^OO=aJEV@;e9UXS&b9* z_?4}P9d=kB&6J;xD=nBL`-}8{tnd#=|Hsr>!s-8D{a8F*QLb9g}jU@$J%TW#fRpJ8ycqzDXl@YcXIDiW}d1us#7DW=Raitzq3a zPxFL6PWOr4wU~L+H$c|8@SQ*?ZXB-;=jw)jr>$N!x~@_k-Z)<2Kft_o*imB}CBO9K z_pycWPD(9~GKWk)TM?oQ!kByy1|P=%CQGt!i0YHE-$N!pY&QyHzgKab^A-l!5bi<+ z2YHN4e%LM%NqS`R4X`4U@7%kP$#;fJ$fx0$e9ywmn@wUBMXH`)>c*F->XQKL(Q*Mm z|8JStF|o}s?J+LM1xSGOpj8mh1q5*m6@=V(NrPNK(5?_^I^+Tj@FvRzIAR#}e~w`B ze&{m!2zcyWu86l`S%dNiy=oDK666OrJp4lQuKLCOlLHI$`Dk2Z$hy7B3+!F^4!1WY zgY@!Nf92x-|0Z~$ksxjXYU&VK{L^LRzU(N({Xel{NM4qTfgv3IZ`%J|O4K#Vo5-cH zf_3kq`uSidwjAxm7}y(zg~ma`i>r$ZasRa;i z17D1rQ{;>Be5mvGj4yS~QUV7X(P3*_1EzmjLtVvCM*`hwdWuMfxCphTcz~pm)OAn~!9^;ZiryqUc#AeLMCG=G70*8OPuO0UuQT zZjWqad?lfsqz^DDLW7TjxuS;C|H1nIVWj`L0F9B5{+FN+2&eydApI`^S~FV(r2l0^ zZ36T^lK6V)=pG(??zu$HV8 zR4;{qweO^2*-Ia}`L1bZ69{nh;gUu4AQQmlfeIf40{qYPJ5O2xPu2uJ75 zgz_Kle!IR+BljLEL1kvD72u97=?M4Xk9$UOdWn)J zloy!&0_6p;m2o>Aa~dTnc~<^}1QkVjfdojvDsVvn_bYNx3Mn(GDcK#CzKlwLs2CO^*r@(v7v zAb?b_4QyB2?vuR@OY*YX8*_vbM$xgY5Ej> zj6MtxFr*3sF2=h89!C#`aQ43-|G%b95frM@$POSo5UK-ZE3xG40F3`@TNiz6@wc8M zJCLm|8K^Z#|J%Tpar$3tNCce3-r1!8UjbszhGD*2r2qNgBzr6YguY7_(YHJ_{eS&w zt5=P#t5kArynK(<3oB+0n+y>EmkO>^?d1{GYUL2Qi;Ejp# zY!Epc9z~Qt zf(r&W2<$mkzeporpTlX0#j^1<#BwQTHd!>dhM^=68*}L6bRRuC+sYXbKi{-xi~b>i z?b!%h)+=J%TLZwq4!$>6sw4fA1B8XuCJO}wF5?v+3xEI$ z2m}BzcoyYbf~Uol?hrr$fekh&Ag}=gZ<`^20)l3E;6LdgAV3n}l11pIhU5Q%{?|iS zL5d9IA|s^$N&J<-ecbWGJY_g$x68WAiWBV{$gbG8Ag%ON5_h8BfI=5;Q!NhREt|&5TQgND-wnBH1Pkoxpw=QUmzPEGr*mSLpIzADj9xOzCG2ALpEGS z^dTEA6;?9Lf-^WXi_Y{O!=WSm(^&mTYfW(nZ`$yW&bNFQ!LN#CK7zf_P7 zXQ)CpJS%K?Vgs*yEAan!Bv!m61*6Mle zx)yTrnc?Csls5l950g~$llFh*KLP&#OYP5PdcxBVnd%#~E-1eU3ORx4x=?;mzDpqd zFspbWfbxrY;mubX$}jlf6k{xuU&IJ(EQ%Kb0^}D0_<#Cm1U?w#hQO^W^h-4IO+3HA zKoiO@1jsMSUj+XDD{%bx#=*(KiNQ?+{Yt*CSftCU>o;tjs18?$)%p?OV=GpkF9V-EFC3~uO_vldWBLCErh%;__ysFbRjM%7+w=-7Mc7@^P8 zr|CoVE_w&uMYqEP41pmaR7L^g|Eq;u4h$l|BH~~z*9YO^i5(N$j5E}Xi}81Xnky9g z3d`r1)wYn`_^m(hRUj)szZg4vB zNZ04{LP3KOt!a7VS5b0C%9%MrGgGxp45|@Z)s&pp3&vKg51_3T1A<5BCK-hX82r2v zz(2F%`1SdIWBO@Ku(;v*e~tWtC}+~A=vi=+!7$yge@r9$#$qtv2XgAZ=}Yv>G;;Tj z7>ZlNY?tyhPw3-xA3dAyqzmECOeo(w-K$>;Z9g!E%0S!q?R~xeQH|VpVhqJ~YWoZn z0^AwvRe*HONhFt10K&cu-@6f#8^^1|xw`x!@zW|#ughA7`qvL`AY_2N8c(Zi9#>)i z9Tql&5b5PI^O%6~f6o?R0D>_2npWRT5ds`OlA>1C2e5=jMGI-6;7lwt2j+#<#o=*~ zN8*}AQOY0$m>C+kw+IbFpc^QYaNK&JB0D51f2~7=POrOySE~N#XSe>CQ%70{*sK9J z9Vt@yo%&RY-%Cc|cOvdd`RfhUt)<2@Y`9E?8(RcJD zN=O+o->}_jF~{>F+wvVPUdB0GR+; zFoE@GhCph1=GvCf+ziKmS2{jT<3ldhQ#u+Jgc;yV6Mg%`u?&pqrSz8sJ{YnKfm?I> z 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