]> git.ipfire.org Git - thirdparty/sqlite.git/commitdiff
Add code to enforce the MAX_EXPR_DEPTH limit. (CVS 3968)
authordanielk1977 <danielk1977@noemail.net>
Thu, 10 May 2007 10:46:56 +0000 (10:46 +0000)
committerdanielk1977 <danielk1977@noemail.net>
Thu, 10 May 2007 10:46:56 +0000 (10:46 +0000)
FossilOrigin-Name: 2c9c94a24d52a1c9f5d1b32cbdff794a2dd74126

manifest
manifest.uuid
src/expr.c
src/limits.h
src/parse.y
src/select.c
src/sqliteInt.h
src/test_config.c
test/sqllimits1.test

index 18de4667ec24fb964c02388fd965e4a769cc9c31..ff853243ceafa211960e1806b067900e0dd5e237 100644 (file)
--- a/manifest
+++ b/manifest
@@ -1,5 +1,5 @@
-C Make\ssure\scompound\squeries\sinside\sa\ssubquery\sonly\sreturn\sa\ssingle\sresult\ncolumn.\s\sTicket\s#2347.\s(CVS\s3967)
-D 2007-05-09T22:56:39
+C Add\scode\sto\senforce\sthe\sMAX_EXPR_DEPTH\slimit.\s(CVS\s3968)
+D 2007-05-10T10:46:56
 F Makefile.in 87b200ad9970907f76df734d29dff3d294c10935
 F Makefile.linux-gcc 2d8574d1ba75f129aba2019f0b959db380a90935
 F README 9c4e2d6706bdcc3efdd773ce752a8cdab4f90028
@@ -70,13 +70,13 @@ F src/complete.c 7d1a44be8f37de125fcafd3d3a018690b3799675
 F src/date.c 6049db7d5a8fdf2c677ff7d58fa31d4f6593c988
 F src/delete.c 5c0d89b3ef7d48fe1f5124bfe8341f982747fe29
 F src/experimental.c 1b2d1a6cd62ecc39610e97670332ca073c50792b
-F src/expr.c 1f3c365fc5aa2a03395cf470346f3646382469c2
+F src/expr.c 65b8a3dff2cdf1b21292996508688d5a1b93200f
 F src/func.c 6282d2025d8e0db80b43783a4778cbb04e98f2f6
 F src/hash.c 67b23e14f0257b69a3e8aa663e4eeadc1a2b6fd5
 F src/hash.h 1b3f7e2609141fd571f62199fc38687d262e9564
 F src/insert.c e595ca26805dfb3a9ebaabc28e7947c479f3b14d
 F src/legacy.c 388c71ad7fbcd898ba1bcbfc98a3ac954bfa5d01
-F src/limits.h 6226e6157ee798b3f19c3fc969a0ae4832393476
+F src/limits.h cf772eb244aae5859fa1554394866c27d3f3639c
 F src/loadext.c afe4f4755dc49c36ef505748bbdddecb9f1d02a2
 F src/main.c 797dc983716c1480f6af78a36be3add8806211a1
 F src/malloc.c b89e31258a85158d15795bf87ae3ba007e56329b
@@ -94,17 +94,17 @@ F src/os_win.c 3b6169038101d06c54b4f04662bfd44b6cf2f289
 F src/os_win.h 41a946bea10f61c158ce8645e7646b29d44f122b
 F src/pager.c acfa86f50b71b7e289508b213bb88e68273d42a0
 F src/pager.h 94110a5570dca30d54a883e880a3633b2e4c05ae
-F src/parse.y fe7efcbf0ef1727cb2c08c1a10869b4ac9d5e71d
+F src/parse.y 39b25cc7f9e1a1a999f367545192c35db644610d
 F src/pragma.c 0703152b9edd6601eea95e1d474b3bc2962d7920
 F src/prepare.c 87c23644986b5e41a58bc76f05abebd899e00089
 F src/printf.c 67de0dcb40ef3297f4a047b434b81585c0f7062d
 F src/random.c 6119474a6f6917f708c1dee25b9a8e519a620e88
-F src/select.c 87bcf7406ab55baec791c49f8926def7bb1c07e2
+F src/select.c d43bbdedb843a91b728531c831f3ed04846b920d
 F src/server.c 087b92a39d883e3fa113cae259d64e4c7438bc96
 F src/shell.c d07ae326b3815d80f71c69b3c7584382e47f6447
 F src/sqlite.h.in 664b8702c27dc742584788823c548491ac8935d6
 F src/sqlite3ext.h 7d0d363ea7327e817ef0dfe1b7eee1f171b72890
-F src/sqliteInt.h 2a4ec9eb67f7d1c634a5bfad9915549f9d3ac919
+F src/sqliteInt.h 7e7faee79b811ff54796d71bf8aa3dc76b1b1a95
 F src/table.c a8de75bcedf84d4060d804264b067ab3b1a3561d
 F src/tclsqlite.c f425c7583665ef78dd8397b2de0b8e0028e80ce2
 F src/test1.c 16938b7e76469abf957745743dd0287d5dee476d
@@ -119,7 +119,7 @@ F src/test9.c c0f38f7795cc51d37db6c63874d90f40f10d0f0e
 F src/test_async.c 9d326ceda4306bcab252b8f7e8e480ed45d7ccb6
 F src/test_autoext.c 855157d97aa28cf84233847548bfacda21807436
 F src/test_btree.c 882d59acad48bab3b1fe3daf3645059b590cfc79
-F src/test_config.c 4c1db31befcbf6206766bbbb429d0e6a1254cdc7
+F src/test_config.c 14080fbd60d334c17bf9610c8ac31814a7ad3832
 F src/test_hexio.c 32204b5ce281ebc85f789c69c4ec725129e7e7f5
 F src/test_loadext.c 22065d601a18878e5542191001f0eaa5d77c0ed8
 F src/test_md5.c 6c42bc0a3c0b54be34623ff77a0eec32b2fa96e3
@@ -340,7 +340,7 @@ F test/shared_err.test cc528f6e78665787e93d9ce3a782a2ce5179d821
 F test/sort.test 0e4456e729e5a92a625907c63dcdedfbe72c5dc5
 F test/speed1.test 22e1b27af0683ed44dcd2f93ed817a9c3e65084a
 F test/speed2.test 53177056baf6556dcbdcf032bbdfc41c1aa74ded
-F test/sqllimits1.test d5d0047bd2d3f5a50c596cf0800cee223fe32ff9
+F test/sqllimits1.test 674866819ff42075a1cefbc4bd147f24a81e45e3
 F test/subquery.test ae324ee928c5fb463a3ce08a8860d6e7f1ca5797
 F test/subselect.test 974e87f8fc91c5f00dd565316d396a5a6c3106c4
 F test/sync.test d05397b8f89f423dd6dba528692019ab036bc1c3
@@ -486,7 +486,7 @@ F www/tclsqlite.tcl bb0d1357328a42b1993d78573e587c6dcbc964b9
 F www/vdbe.tcl 87a31ace769f20d3627a64fa1fade7fed47b90d0
 F www/version3.tcl 890248cf7b70e60c383b0e84d77d5132b3ead42b
 F www/whentouse.tcl fc46eae081251c3c181bd79c5faef8195d7991a5
-P c0dbac46301039246afd4bebb71dd8184fc5c0c7
-R ce1d9a31f5642fc3adec7a89c841905a
-U drh
-Z f08cc8911b7b4f7d10aa7482cf6b823e
+P 66954bdd81dabfb60306de8480b5477a4acb1d9e
+R 22592093c0c06bde534ff11e74de00ec
+U danielk1977
+Z 44dafc85e209c0119e527fcc4f0a9e17
index 3f940d3352a077ac4c7aaaaa418c1250fc4a5c98..24dc883fbe0dd572720b133864e82fcb7533b68d 100644 (file)
@@ -1 +1 @@
-66954bdd81dabfb60306de8480b5477a4acb1d9e
\ No newline at end of file
+2c9c94a24d52a1c9f5d1b32cbdff794a2dd74126
\ No newline at end of file
index 828cf6050851aca90950c20169efdc4ac035f7f4..e7358b554059fa47d901456f2574f1105512b7fc 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains routines used for analyzing expressions and
 ** for generating VDBE code that evaluates expressions in SQLite.
 **
-** $Id: expr.c,v 1.288 2007/05/09 11:37:23 danielk1977 Exp $
+** $Id: expr.c,v 1.289 2007/05/10 10:46:56 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include <ctype.h>
@@ -247,6 +247,8 @@ Expr *sqlite3Expr(int op, Expr *pLeft, Expr *pRight, const Token *pToken){
       pNew->pColl = pLeft->pColl;
     }
   }
+
+  sqlite3ExprSetHeight(pNew);
   return pNew;
 }
 
@@ -343,6 +345,8 @@ Expr *sqlite3ExprFunction(ExprList *pList, Token *pToken){
   assert( pToken->dyn==0 );
   pNew->token = *pToken;
   pNew->span = pNew->token;
+
+  sqlite3ExprSetHeight(pNew);
   return pNew;
 }
 
@@ -478,6 +482,9 @@ Expr *sqlite3ExprDup(Expr *p){
   pNew->pList = sqlite3ExprListDup(p->pList);
   pNew->pSelect = sqlite3SelectDup(p->pSelect);
   pNew->pTab = p->pTab;
+#if SQLITE_MAX_EXPR_DEPTH>0
+  pNew->nHeight = p->nHeight;
+#endif
   return pNew;
 }
 void sqlite3TokenCopy(Token *pTo, Token *pFrom){
@@ -671,6 +678,72 @@ void sqlite3ExprListCheckLength(
   }
 }
 
+
+#if SQLITE_MAX_EXPR_DEPTH>0
+/* The following three functions, heightOfExpr(), heightOfExprList()
+** and heightOfSelect(), are used to determine the maximum height
+** of any expression tree referenced by the structure passed as the
+** first argument.
+**
+** If this maximum height is greater than the current value pointed
+** to by pnHeight, the second parameter, then set *pnHeight to that
+** value.
+*/
+static void heightOfExpr(Expr *p, int *pnHeight){
+  if( p ){
+    if( p->nHeight>*pnHeight ){
+      *pnHeight = p->nHeight;
+    }
+  }
+}
+static void heightOfExprList(ExprList *p, int *pnHeight){
+  if( p ){
+    int i;
+    for(i=0; i<p->nExpr; i++){
+      heightOfExpr(p->a[i].pExpr, pnHeight);
+    }
+  }
+}
+static void heightOfSelect(Select *p, int *pnHeight){
+  if( p ){
+    heightOfExpr(p->pWhere, pnHeight);
+    heightOfExpr(p->pHaving, pnHeight);
+    heightOfExpr(p->pLimit, pnHeight);
+    heightOfExpr(p->pOffset, pnHeight);
+    heightOfExprList(p->pEList, pnHeight);
+    heightOfExprList(p->pGroupBy, pnHeight);
+    heightOfExprList(p->pOrderBy, pnHeight);
+    heightOfSelect(p->pPrior, pnHeight);
+  }
+}
+
+/*
+** Set the Expr.nHeight variable in the structure passed as an 
+** argument. An expression with no children, Expr.pList or 
+** Expr.pSelect member has a height of 1. Any other expression
+** has a height equal to the maximum height of any other 
+** referenced Expr plus one.
+*/
+void sqlite3ExprSetHeight(Expr *p){
+  int nHeight = 0;
+  heightOfExpr(p->pLeft, &nHeight);
+  heightOfExpr(p->pRight, &nHeight);
+  heightOfExprList(p->pList, &nHeight);
+  heightOfSelect(p->pSelect, &nHeight);
+  p->nHeight = nHeight + 1;
+}
+
+/*
+** Return the maximum height of any expression tree referenced
+** by the select statement passed as an argument.
+*/
+int sqlite3SelectExprHeight(Select *p){
+  int nHeight = 0;
+  heightOfSelect(p, &nHeight);
+  return nHeight;
+}
+#endif
+
 /*
 ** Delete an entire expression list.
 */
@@ -1335,15 +1408,28 @@ static int nameResolverStep(void *pArg, Expr *pExpr){
 ** If the expression contains aggregate functions then set the EP_Agg
 ** property on the expression.
 */
-int sqlite3ExprResolveNames(
+int sqlite3ExprResolveNames( 
   NameContext *pNC,       /* Namespace to resolve expressions in. */
   Expr *pExpr             /* The expression to be analyzed. */
 ){
   int savedHasAgg;
   if( pExpr==0 ) return 0;
+#if SQLITE_MAX_EXPR_DEPTH>0
+  if( (pExpr->nHeight+pNC->pParse->nHeight)>SQLITE_MAX_EXPR_DEPTH ){
+    sqlite3ErrorMsg(pNC->pParse, 
+       "Expression tree is too large (maximum depth %d)",
+       SQLITE_MAX_EXPR_DEPTH
+    );
+    return 1;
+  }
+  pNC->pParse->nHeight += pExpr->nHeight;
+#endif
   savedHasAgg = pNC->hasAgg;
   pNC->hasAgg = 0;
   walkExprTree(pExpr, nameResolverStep, pNC);
+#if SQLITE_MAX_EXPR_DEPTH>0
+  pNC->pParse->nHeight -= pExpr->nHeight;
+#endif
   if( pNC->nErr>0 ){
     ExprSetProperty(pExpr, EP_Error);
   }
@@ -1384,6 +1470,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
   Vdbe *v = sqlite3GetVdbe(pParse);
   if( v==0 ) return;
 
+
   /* This code must be run in its entirety every time it is encountered
   ** if any of the following is true:
   **
@@ -1521,6 +1608,7 @@ void sqlite3CodeSubselect(Parse *pParse, Expr *pExpr){
   if( testAddr ){
     sqlite3VdbeJumpHere(v, testAddr);
   }
+
   return;
 }
 #endif /* SQLITE_OMIT_SUBQUERY */
index ff7bdfde097b66c8b353c59fbe4b6e19ed8d724c..21c36680bcca427efaab8ed6b44dde75e4bb6387 100644 (file)
@@ -12,7 +12,7 @@
 ** 
 ** This file defines various limits of what SQLite can process.
 **
-** @(#) $Id: limits.h,v 1.5 2007/05/08 15:34:48 drh Exp $
+** @(#) $Id: limits.h,v 1.6 2007/05/10 10:46:56 danielk1977 Exp $
 */
 
 /*
 #endif
 
 /*
-** The maximum number of terms in an expression.
-** This is limited to some extent by SQLITE_MAX_SQL_LENGTH.
-** But sometime you might want to place more severe limits
-** on the complexity of an expression.
+** The maximum depth of an expression tree. This is limited to 
+** some extent by SQLITE_MAX_SQL_LENGTH. But sometime you might 
+** want to place more severe limits on the complexity of an 
+** expression. A value of 0 (the default) means do not enforce
+** any limitation on expression tree depth.
 */
-#ifndef SQLITE_MAX_EXPR_LENGTH
-# define SQLITE_MAX_EXPR_LENGTH 5000
+#ifndef SQLITE_MAX_EXPR_DEPTH
+# define SQLITE_MAX_EXPR_DEPTH 0
 #endif
 
 /*
index a7e07b9a758196c139c3f4b9c792450624babbac..991a9326931c2e0ed552e5fad6ed31ced7531b6f 100644 (file)
@@ -14,7 +14,7 @@
 ** the parser.  Lemon will also generate a header file containing
 ** numeric codes for all of the tokens.
 **
-** @(#) $Id: parse.y,v 1.224 2007/05/08 17:54:44 danielk1977 Exp $
+** @(#) $Id: parse.y,v 1.225 2007/05/10 10:46:57 danielk1977 Exp $
 */
 
 // All token codes are small integers with #defines that begin with "TK_"
@@ -766,6 +766,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A = sqlite3Expr(TK_IN, X, 0, 0);
     if( A ){
       A->pList = Y;
+      sqlite3ExprSetHeight(A);
     }else{
       sqlite3ExprListDelete(Y);
     }
@@ -776,6 +777,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A = sqlite3Expr(TK_SELECT, 0, 0, 0);
     if( A ){
       A->pSelect = X;
+      sqlite3ExprSetHeight(A);
     }else{
       sqlite3SelectDelete(X);
     }
@@ -785,6 +787,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A = sqlite3Expr(TK_IN, X, 0, 0);
     if( A ){
       A->pSelect = Y;
+      sqlite3ExprSetHeight(A);
     }else{
       sqlite3SelectDelete(Y);
     }
@@ -796,6 +799,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     A = sqlite3Expr(TK_IN, X, 0, 0);
     if( A ){
       A->pSelect = sqlite3SelectNew(0,pSrc,0,0,0,0,0,0,0);
+      sqlite3ExprSetHeight(A);
     }else{
       sqlite3SrcListDelete(pSrc);
     }
@@ -807,6 +811,7 @@ expr(A) ::= expr(W) between_op(N) expr(X) AND expr(Y). [BETWEEN] {
     if( p ){
       p->pSelect = Y;
       sqlite3ExprSpan(p,&B,&E);
+      sqlite3ExprSetHeight(A);
     }else{
       sqlite3SelectDelete(Y);
     }
@@ -818,6 +823,7 @@ expr(A) ::= CASE(C) case_operand(X) case_exprlist(Y) case_else(Z) END(E). {
   A = sqlite3Expr(TK_CASE, X, Z, 0);
   if( A ){
     A->pList = Y;
+    sqlite3ExprSetHeight(A);
   }else{
     sqlite3ExprListDelete(Y);
   }
index 83c9d6b67a1a2ffc6b95dbec658607a8895d1397..dd8b81d82a03c5437fadaed9791d5555c02f023f 100644 (file)
@@ -12,7 +12,7 @@
 ** This file contains C code routines that are called by the parser
 ** to handle SELECT statements in SQLite.
 **
-** $Id: select.c,v 1.343 2007/05/09 22:56:39 drh Exp $
+** $Id: select.c,v 1.344 2007/05/10 10:46:57 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 
@@ -2940,8 +2940,21 @@ int sqlite3Select(
     }else{
       needRestoreContext = 0;
     }
+#if SQLITE_MAX_EXPR_DEPTH>0
+    /* Increment Parse.nHeight by the height of the largest expression
+    ** tree refered to by this, the parent select. The child select
+    ** may contain expression trees of at most
+    ** (SQLITE_MAX_EXPR_DEPTH-Parse.nHeight) height. This is a bit
+    ** more conservative than necessary, but much easier than enforcing
+    ** an exact limit.
+    */
+    pParse->nHeight += sqlite3SelectExprHeight(p);
+#endif
     sqlite3Select(pParse, pItem->pSelect, SRT_EphemTab, 
                  pItem->iCursor, p, i, &isAgg, 0);
+#if SQLITE_MAX_EXPR_DEPTH>0
+    pParse->nHeight -= sqlite3SelectExprHeight(p);
+#endif
     if( needRestoreContext ){
       pParse->zAuthContext = zSavedAuthContext;
     }
index 8daf349bae41198186b275ff5fcd5b68bbde726c..fc2525f8fcd6d996bc8cd508a78d33e638116063 100644 (file)
@@ -11,7 +11,7 @@
 *************************************************************************
 ** Internal interface definitions for SQLite.
 **
-** @(#) $Id: sqliteInt.h,v 1.562 2007/05/08 21:45:28 drh Exp $
+** @(#) $Id: sqliteInt.h,v 1.563 2007/05/10 10:46:57 danielk1977 Exp $
 */
 #ifndef _SQLITEINT_H_
 #define _SQLITEINT_H_
@@ -998,6 +998,9 @@ struct Expr {
                          ** right side of "<expr> IN (<select>)" */
   Table *pTab;           /* Table for OP_Column expressions. */
   Schema *pSchema;
+#if SQLITE_MAX_EXPR_DEPTH>0
+  int nHeight;           /* Height of the tree headed by this node */
+#endif
 };
 
 /*
@@ -1343,6 +1346,9 @@ struct Parse {
   u8 declareVtab;            /* True if inside sqlite3_declare_vtab() */
   Table *pVirtualLock;       /* Require virtual table lock on this table */
 #endif
+#if SQLITE_MAX_EXPR_DEPTH>0
+  int nHeight;            /* Expression tree height of current sub-select */
+#endif
 };
 
 #ifdef SQLITE_OMIT_VIRTUALTABLE
@@ -1878,6 +1884,13 @@ void sqlite3InvalidFunction(sqlite3_context*,int,sqlite3_value**);
 int sqlite3Reprepare(Vdbe*);
 void sqlite3ExprListCheckLength(Parse*, ExprList*, int, const char*);
 
+#if SQLITE_MAX_EXPR_DEPTH>0
+  void sqlite3ExprSetHeight(Expr *);
+  int sqlite3SelectExprHeight(Select *);
+#else
+  #define sqlite3ExprSetHeight(x)
+#endif
+
 u32 sqlite3Get2byte(const u8*);
 u32 sqlite3Get4byte(const u8*);
 void sqlite3Put2byte(u8*, u32);
index 40c021557b03a4e7bfba9fcec9ee2744bc8ad2e6..7f4689e5179d1a50894cf9ce150449a6ebc80ef0 100644 (file)
@@ -16,7 +16,7 @@
 ** The focus of this file is providing the TCL testing layer
 ** access to compile-time constants.
 **
-** $Id: test_config.c,v 1.3 2007/05/09 11:37:23 danielk1977 Exp $
+** $Id: test_config.c,v 1.4 2007/05/10 10:46:57 danielk1977 Exp $
 */
 #include "sqliteInt.h"
 #include "tcl.h"
@@ -382,9 +382,9 @@ static void set_options(Tcl_Interp *interp){
            (char*)&sqlite_max_sql_length, TCL_LINK_INT|TCL_LINK_READ_ONLY);
   }
   {
-    static int sqlite_max_expr_length = SQLITE_MAX_EXPR_LENGTH;
-    Tcl_LinkVar(interp, "SQLITE_MAX_EXPR_LENGTH",
-           (char*)&sqlite_max_expr_length, TCL_LINK_INT|TCL_LINK_READ_ONLY);
+    static int sqlite_max_expr_depth = SQLITE_MAX_EXPR_DEPTH;
+    Tcl_LinkVar(interp, "SQLITE_MAX_EXPR_DEPTH",
+           (char*)&sqlite_max_expr_depth, TCL_LINK_INT|TCL_LINK_READ_ONLY);
   }
   {
     static int sqlite_max_vdbe_op = SQLITE_MAX_VDBE_OP;
index 0dcbaa121fac07627447fbc2fc5866c8c5eb57eb..f962679d7fe896eb2dbc988721d074417b8a346c 100644 (file)
@@ -12,7 +12,7 @@
 # This file contains tests to verify that the limits defined in
 # sqlite source file limits.h are enforced.
 #
-# $Id: sqllimits1.test,v 1.6 2007/05/09 15:56:40 danielk1977 Exp $
+# $Id: sqllimits1.test,v 1.7 2007/05/10 10:46:57 danielk1977 Exp $
 
 set testdir [file dirname $argv0]
 source $testdir/tester.tcl
@@ -33,7 +33,7 @@ source $testdir/tester.tcl
 #
 # Todo:
 #
-#     sqllimits-5.*:   SQLITE_MAX_EXPR_LENGTH           (sqlite todo)
+#     sqllimits-5.*:   SQLITE_MAX_EXPR_DEPTH            (sqlite todo)
 #     sqllimits-6.*:   SQLITE_MAX_VDBE_OP               (sqlite todo)
 #
 
@@ -237,25 +237,58 @@ do_test sqllimits-1.4.9 {
 } {1 {too many columns in result set}}
 
 #--------------------------------------------------------------------
-# These tests - sqllimits-5.* - test that the SQLITE_MAX_EXPR_LENGTH
+# These tests - sqllimits-5.* - test that the SQLITE_MAX_EXPR_DEPTH
 # limit is enforced. The limit refers to the number of terms in 
 # the expression.
 #
-# TODO
-do_test sqllimits-1.5.1 {
-  execsql {
-    PRAGMA max_page_count = 1000000;  -- 1 GB
-    CREATE TABLE v0(a);
-  }
-  db transaction {
-    for {set i 1} {$i < 2000} {incr i} {
-      set expr "([string repeat {a AND } 50]a AND a) AS a"
-      execsql [subst {
-        CREATE VIEW v${i} AS SELECT $expr FROM v0
-      }]
+if {$::SQLITE_MAX_EXPR_DEPTH != 1000} {
+  puts -nonewline stderr "WARNING: Compile with -DSQLITE_MAX_EXPR_DEPTH to run "
+  puts stderr "tests sqllimits-1.5.X"
+} else {
+  do_test sqllimits-1.5.1 {
+    set max $::SQLITE_MAX_EXPR_DEPTH
+    set expr "(1 [string repeat {AND 1 } $max])"
+    catchsql [subst {
+      SELECT $expr
+    }]
+  } "1 {Expression tree is too large (maximum depth $::SQLITE_MAX_EXPR_DEPTH)}"
+  
+  # Attempting to beat the expression depth limit using nested SELECT
+  # queries causes a parser stack overflow. 
+  do_test sqllimits-1.5.2 {
+    set max $::SQLITE_MAX_EXPR_DEPTH
+    set expr "SELECT 1"
+    for {set i 0} {$i <= $max} {incr i} {
+      set expr "SELECT ($expr)"
     }
-  }
-} {}
+    catchsql [subst {
+      SELECT $expr
+    }]
+  } "1 {parser stack overflow}"
+  
+  
+  do_test sqllimits-1.5.3 {
+    execsql {
+      PRAGMA max_page_count = 1000000;  -- 1 GB
+      CREATE TABLE v0(a);
+      INSERT INTO v0 VALUES(1);
+    }
+    db transaction {
+      for {set i 1} {$i < 200} {incr i} {
+        set expr "(a [string repeat {AND 1 } 50]) AS a"
+        execsql [subst {
+          CREATE VIEW v${i} AS SELECT $expr FROM v[expr {$i-1}]
+        }]
+      }
+    }
+  } {}
+  
+  do_test sqllimits-1.5.4 {
+    catchsql {
+      SELECT a FROM v199
+    }
+  } "1 {Expression tree is too large (maximum depth $::SQLITE_MAX_EXPR_DEPTH)}"
+}
 
 #--------------------------------------------------------------------
 # Test cases sqllimits-6.* test that the SQLITE_MAX_VDBE_OP