diff --git a/manifest b/manifest index 1d58ac437e..9550387d36 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Fix\san\sincorrect\sassert()\sin\sgenerate_series().\s\sNo\simpact\son\snon-debug\nbuilds.\n[bugs:/info/2026-10-17T09:24:09Z|Bug\s2026-10-17T09:24:09Z] -D 2026-10-17T12:03:36.275 +C Only\senforce\sthe\slimit\son\sthe\snumber\sof\sCTE\scursors\sat\nSQLITE_LIMIT_EXPR_DEPTH\sif\sSQLITE_DBCONFIG_DEFENSIVE\sis\sengaged.\nAlso\sgive\sa\sdifferent\serror\smessage\swhen\sthe\snumber\sof\sCTEs\ngrow\stoo\slarge.\nThis\sis\sa\sproposed\swork-around\sfor\sthe\sproblem\sdescribed\sat\n[forum:/info/2026-10-16T20:30:17Z|Forum\spost\s2026-10-16T20:30:17Z].\nIt\sdoes\srequire\sthe\suser\sto\sdisable\sdefensive.\s\sPerhaps\sfor\s3.55.0\nI\sshould\sadd\sa\snew\slimit\sinstead,\slike\sSQLITE_LIMIT_CTES. +D 2026-10-18T00:34:48.172 F .fossil-settings/binary-glob 61195414528fb3ea9693577e1980230d78a1f8b0a54c78cf1b9b24d0a409ed6a x F .fossil-settings/empty-dirs dbb81e8fc0401ac46a1491ab34a7f2c7c0452f2f06b54ebb845d024ca8283ef1 F .fossil-settings/ignore-glob 35175cdfcf539b2318cb04a9901442804be81cd677d8b889fcc9149c21f239ea @@ -802,9 +802,9 @@ F src/printf.c 4bd228ed9e9346d558362be562757ee5eef6f9bf483b7f02751ca42cf95174d3 F src/random.c 606b00941a1d7dd09c381d3279a058d771f406c5213c9932bbd93d5587be4b9c F src/resolve.c 0e0990f60c93db38c735d85e5d1741130e72dd0670aec204b5a39118b53c8044 F src/rowset.c 8432130e6c344b3401a8874c3cb49fefe6873fec593294de077afea2dce5ec97 -F src/select.c 23bf5cd12a116bef8458f1277a0e6a17ac244c039d41a052cd63f3d6aef714fa +F src/select.c 31beda7f253b494415d21a92108476be332e6481e3cd2106d7942b385dd4f4e3 F src/shell.c.in 3e11598ebd82077fb525874046250117502e665ac75b6e9912acf29a8514ffd7 -F src/sqlite.h.in 648fdc66f52433fc0f6cf9564ac924cde544eca9605bbac36aa22d8c944f11ed +F src/sqlite.h.in 73225c27a48b09f5373b86eac7e02cc93a824130ae1c71b43dadc11ce21cd20b F src/sqlite3.rc 015537e6ac1eec6c7050e17b616c2ffe6f70fca241835a84a4f0d5937383c479 F src/sqlite3ext.h 5e113c4c0442f2f1b3345d44cbe4b82fad45f2fc0c35f0ed4eef27fb8f1cb394 F src/sqliteInt.h 24452d1042f40a018ce8b52bab6d52802c023e434db0d45ac0d8ff09b151e231 @@ -2170,7 +2170,7 @@ F test/windowerr.tcl f5acd6fbc210d7b5546c0e879d157888455cd4a17a1d3f28f07c1c8a387 F test/windowerr.test a8b752402109c15aa1c5efe1b93ccb0ce1ef84fa964ae1cd6684dd0b3cc1819b F test/windowfault.test 15094c1529424e62f798bc679e3fe9dfab6e8ba2f7dfe8c923b6248c31660a7c F test/windowpushd.test c420e2265f0e09a0e798d0513a660d71b51602088d81b3dbd038918ee1339dcc -F test/with1.test 07494cf705cf3fecde1dbf2a519ade969291b2b1f901dad008c0bfb091cb5eb9 +F test/with1.test 7597b49b33e58f51d4ea9138f0ba6b0bec440168b934481fe63b8d2f3e2872ce F test/with2.test 08db6b31a986e4359b90e1028cb32fb165b49da7c0d6abd0752bb232494d32e8 F test/with3.test e30369ea27aa27eb1bda4c5e510c8a9f782c8afd2ab99d1a02b8a7f25a5d3e65 F test/with4.test 257be66c0c67fee1defbbac0f685c3465e2cad037f21ce65f23f86084f198205 @@ -2287,8 +2287,11 @@ F tool/warnings-clang.sh bbf6a1e685e534c92ec2bfba5b1745f34fb6f0bc2a362850723a9ee F tool/warnings.sh a554d13f6e5cf3760f041b87939e3d616ec6961859c3245e8ef701d1eafc2ca2 F tool/win/sqlite.vsix deb315d026cc8400325c5863eef847784a219a2f F tool/winmain.c 00c8fb88e365c9017db14c73d3c78af62194d9644feaf60e220ab0f411f3604c -P d43611f653bad426df8dc4ac12d0fff1662245b0715f7e66a023bd1dd129faea -R 4860e4e720900d9865bb628f2bb5e16b +P c5d67762df0507fe58e035b572623f36efb394d08d322bbdb313a2f0da49c734 +R 82c3eab1ceb5e4962ed3cd20c78bd376 +T *branch * too-many-ctes +T *sym-too-many-ctes * +T -sym-branch-3.54 * U drh -Z 1becf78a83ced1d37cf8fb84d4943e6b +Z 3c8dbcae18d8c8fdc104376a28522960 # Remove this line to create a well-formed Fossil manifest. diff --git a/manifest.tags b/manifest.tags index f791678d5f..cc0050b96b 100644 --- a/manifest.tags +++ b/manifest.tags @@ -1,2 +1,2 @@ -branch branch-3.54 -tag branch-3.54 +branch too-many-ctes +tag too-many-ctes diff --git a/manifest.uuid b/manifest.uuid index 9cc8caea85..0e8a66b5fe 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -c5d67762df0507fe58e035b572623f36efb394d08d322bbdb313a2f0da49c734 +2161aefeb89842ba1675f469770b81b0c9946ebdfdcbca130440e81732463916 diff --git a/src/select.c b/src/select.c index c1609d9dae..734261782b 100644 --- a/src/select.c +++ b/src/select.c @@ -5900,13 +5900,14 @@ static int resolveFromTermToCte( } #if SQLITE_MAX_EXPR_DEPTH>0 - if( pParse->nTab>=db->aLimit[SQLITE_LIMIT_EXPR_DEPTH] ){ - /* Bug 2026-10-04T05:35:14Z: Prevent nested CTEs from generating - ** an exponential number of cursors. The error message here will - ** be "Nested too deep", which isn't exactly correct, but it is - ** sufficient, and we don't want to use extra code space for more - ** detail on such an obscure error. */ - pParse->nNestSel = pParse->nTab; + if( (pParse->nTab >= db->aLimit[SQLITE_LIMIT_EXPR_DEPTH]) + && (db->flags & SQLITE_Defensive)!=0 + ){ + /* Bug 2026-10-04T05:35:14Z with follow-up Forum 2026-10-16T20:30:17Z: + ** Prevent nested CTEs from generating an exponential number of + ** cursors in defensive mode. */ + sqlite3ErrorMsg(pParse, "too many CTEs"); + return 2; } pParse->nNestSel++; if( checkSubqueryNestingDepth(pParse) ) return 2; diff --git a/src/sqlite.h.in b/src/sqlite.h.in index 38432a75b0..5a4280ea11 100644 --- a/src/sqlite.h.in +++ b/src/sqlite.h.in @@ -2479,15 +2479,18 @@ struct sqlite3_mem_methods { ** [[SQLITE_DBCONFIG_DEFENSIVE]]
SQLITE_DBCONFIG_DEFENSIVE
**
The SQLITE_DBCONFIG_DEFENSIVE option activates or deactivates the ** "defensive" flag for a database connection. When the defensive -** flag is enabled, language features that allow ordinary SQL to -** deliberately corrupt the database file are disabled. The disabled -** features include but are not limited to the following: +** flag is on, language features are disabled that would otherwise +** allow ordinary SQL to deliberately corrupt the database file, or +** to perform other unwholesome actions. The disabled features include +** but are not limited to the following: ** **
** @@ -4404,7 +4407,11 @@ int sqlite3_limit(sqlite3*, int id, int newVal); ** ** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(
SQLITE_LIMIT_EXPR_DEPTH
**
The maximum depth of the parse tree on any expression and -** the maximum nesting depth for subqueries and VIEWs
)^ +** the maximum nesting depth for subqueries and VIEWs. +** When [SQLITE_DBCONFIG_DEFENSIVE] is enabled, this also limits +** the number of cursors used by [common table expressions] (CTEs), +** in order to prevent maliciously nested CTEs from using a number +** of cursors that is exponential in the CTE nesting depth.)^ ** ** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(
SQLITE_LIMIT_PARSER_DEPTH
**
The maximum depth of the LALR(1) parser stack used to analyze diff --git a/test/with1.test b/test/with1.test index 15424ddb90..90902fb43d 100644 --- a/test/with1.test +++ b/test/with1.test @@ -1072,9 +1072,11 @@ do_execsql_test 21.2 { } {{}} # 2019-01-17 -# Make sure crazy nexted CTE joins terminate with an error quickly. +# Make sure crazy nexted CTE joins terminate with an error quickly in +# defensive mode. # if {$::SQLITE_MAX_EXPR_DEPTH>10} { + sqlite3_db_config db DEFENSIVE 1 do_catchsql_test 22.1 { WITH RECURSIVE c AS NOT MATERIALIZED ( WITH RECURSIVE c AS NOT MATERIALIZED ( @@ -1090,7 +1092,28 @@ if {$::SQLITE_MAX_EXPR_DEPTH>10} { SELECT 3 FROM c,c,c,c,c,c,c,c,c ) SELECT 4 FROM c,c,c,c,c,c,c,c,c; - } {1 {VIEWs and/or subqueries nested too deep}} + } {1 {too many CTEs}} + + # A different defense mechanism is used if defensive mode is turned off + # Forum thread 2026-10-16T20:30:17Z + # + sqlite3_db_config db DEFENSIVE 0 + do_catchsql_test 22.2 { + WITH RECURSIVE c AS NOT MATERIALIZED ( + WITH RECURSIVE c AS NOT MATERIALIZED ( + WITH RECURSIVE c AS NOT MATERIALIZED ( + WITH RECURSIVE c AS NOT MATERIALIZED ( + WITH c AS (VALUES(0)) + SELECT 1 FROM c LEFT JOIN c ON ltrim(1) + ) + SELECT 1 FROM c,c,c,c,c,c,c,c,c + ) + SELECT 2 FROM c,c,c,c,c,c,c,c,c + ) + SELECT 3 FROM c,c,c,c,c,c,c,c,c + ) + SELECT 4 FROM c,c,c,c,c,c,c,c,c; + } {1 {too many FROM clause terms, max: 200}} } # 2019-05-22