1
0
mirror of https://github.com/sqlite/sqlite.git synced 2026-10-23 21:49:02 +03:00

Only enforce the limit on the number of CTE cursors at

SQLITE_LIMIT_EXPR_DEPTH if SQLITE_DBCONFIG_DEFENSIVE is engaged.
Also give a different error message when the number of CTEs
grow too large.
This is a proposed work-around for the problem described at
[forum:/info/2026-10-16T20:30:17Z|Forum post 2026-10-16T20:30:17Z].
It does require the user to disable defensive.  Perhaps for 3.55.0
I should add a new limit instead, like SQLITE_LIMIT_CTES.

FossilOrigin-Name: 2161aefeb89842ba1675f469770b81b0c9946ebdfdcbca130440e81732463916
This commit is contained in:
drh
2026-10-18 00:34:48 +00:00
parent ea9d6e8419
commit 245d21fb37
6 changed files with 58 additions and 24 deletions

View File

@@ -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.

View File

@@ -1,2 +1,2 @@
branch branch-3.54
tag branch-3.54
branch too-many-ctes
tag too-many-ctes

View File

@@ -1 +1 @@
c5d67762df0507fe58e035b572623f36efb394d08d322bbdb313a2f0da49c734
2161aefeb89842ba1675f469770b81b0c9946ebdfdcbca130440e81732463916

View File

@@ -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;

View File

@@ -2479,15 +2479,18 @@ struct sqlite3_mem_methods {
** [[SQLITE_DBCONFIG_DEFENSIVE]] <dt>SQLITE_DBCONFIG_DEFENSIVE</dt>
** <dd>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:
** <ul>
** <li> The [PRAGMA writable_schema=ON] statement.
** <li> The [PRAGMA journal_mode=OFF] statement.
** <li> The [PRAGMA schema_version=N] statement.
** <li> Writes to the [sqlite_dbpage] virtual table.
** <li> Direct writes to [shadow tables].
** <li> Limit the number of cursors used by [common table expressions]
** to [SQLITE_LIMIT_EXPR_DEPTH].
** </ul>
** </dd>
**
@@ -4404,7 +4407,11 @@ int sqlite3_limit(sqlite3*, int id, int newVal);
**
** [[SQLITE_LIMIT_EXPR_DEPTH]] ^(<dt>SQLITE_LIMIT_EXPR_DEPTH</dt>
** <dd>The maximum depth of the parse tree on any expression and
** the maximum nesting depth for subqueries and VIEWs</dd>)^
** 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.</dd>)^
**
** [[SQLITE_LIMIT_PARSER_DEPTH]] ^(<dt>SQLITE_LIMIT_PARSER_DEPTH</dt>
** <dd>The maximum depth of the LALR(1) parser stack used to analyze

View File

@@ -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