/ Check-in [c07e493b]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix for ticket #84: If the WHERE clause is too complex, issue an error message and refuse to do the SELECT. The cutoff is a WHERE clause with 100 terms. (CVS 650)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:c07e493b62125e85eaea36b6945f1e146e2792b8
User & Date: drh 2002-06-28 01:02:38
Context
2002-06-28
12:18
Additional test cases added. The following bug fixed: A segfault was occurring if a VIEW consisted of a join with a USING clause. (CVS 651) check-in: 96515b81 user: drh tags: trunk
01:02
Fix for ticket #84: If the WHERE clause is too complex, issue an error message and refuse to do the SELECT. The cutoff is a WHERE clause with 100 terms. (CVS 650) check-in: c07e493b user: drh tags: trunk
2002-06-27
13:21
Fix for ticket #88: A typo in the documention of the "sqlite" shell command. (CVS 649) check-in: 16552a7a user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/vdbe.c.

26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
2841
2842
2843
2844
2845
2846
2847


2848
2849
2850
2851
2852
2853
2854
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.161 2002/06/26 02:45:04 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
case OP_Commit: {
  if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
    rc = sqliteBtreeCommit(pBt);
  }
  if( rc==SQLITE_OK ){
    sqliteCommitInternalChanges(db);
  }else{


    sqliteRollbackInternalChanges(db);
  }
  break;
}

/* Opcode: Rollback * * *
**







|







 







>
>







26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
....
2841
2842
2843
2844
2845
2846
2847
2848
2849
2850
2851
2852
2853
2854
2855
2856
** type to the other occurs as necessary.
** 
** Most of the code in this file is taken up by the sqliteVdbeExec()
** function which does the work of interpreting a VDBE program.
** But other routines are also provided to help in building up
** a program instruction by instruction.
**
** $Id: vdbe.c,v 1.162 2002/06/28 01:02:38 drh Exp $
*/
#include "sqliteInt.h"
#include <ctype.h>

/*
** The following global variable is incremented every time a cursor
** moves, either by the OP_MoveTo or the OP_Next opcode.  The test
................................................................................
case OP_Commit: {
  if( db->pBeTemp==0 || (rc = sqliteBtreeCommit(db->pBeTemp))==SQLITE_OK ){
    rc = sqliteBtreeCommit(pBt);
  }
  if( rc==SQLITE_OK ){
    sqliteCommitInternalChanges(db);
  }else{
    if( db->pBeTemp ) sqliteBtreeRollback(db->pBeTemp);
    sqliteBtreeRollback(pBt);
    sqliteRollbackInternalChanges(db);
  }
  break;
}

/* Opcode: Rollback * * *
**

Changes to src/where.c.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
300
301
302
303
304
305
306
307
308
309
310
311
312
















313
314
315
316
317
318
319
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.56 2002/06/25 01:09:12 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
  int nExpr;           /* Number of subexpressions in the WHERE clause */
  int loopMask;        /* One bit set for each outer loop */
  int haveKey;         /* True if KEY is on the stack */
  int aDirect[32];     /* If TRUE, then index this table using ROWID */
  int iDirectEq[32];   /* Term of the form ROWID==X for the N-th table */
  int iDirectLt[32];   /* Term of the form ROWID<X or ROWID<=X */
  int iDirectGt[32];   /* Term of the form ROWID>X or ROWID>=X */
  ExprInfo aExpr[50];  /* The WHERE clause is divided into these expressions */

  /* pushKey is only allowed if there is a single table (as in an INSERT or
  ** UPDATE statement)
  */
  assert( pushKey==0 || pTabList->nSrc==1 );
















  
  /* Allocate space for aOrder[] */
  aOrder = sqliteMalloc( sizeof(int) * pTabList->nSrc );

  /* Allocate and initialize the WhereInfo structure that will become the
  ** return value.
  */
................................................................................
  ** expression and either jump over all of the code or fall thru.
  */
  if( pWhere && sqliteExprIsConstant(pWhere) ){
    sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
    pWhere = 0;
  }

  /* Split the WHERE clause into as many as 32 separate subexpressions
  ** where each subexpression is separated by an AND operator.  Any additional
  ** subexpressions are attached in the aExpr[32] and will not enter
  ** into the query optimizer computations.  32 is chosen as the cutoff
  ** since that is the number of bits in an integer that we use for an
  ** expression-used mask.  
  */
  memset(aExpr, 0, sizeof(aExpr));
  nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);

  /* Analyze all of the subexpressions.
  */
  for(i=0; i<nExpr; i++){
    exprAnalyze(base, &aExpr[i]);

    /* If we are executing a trigger body, remove all references to
    ** new.* and old.* tables from the prerequisite masks.







|







 







|





>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>







 







<
<
<
<
<
<
<
<
<
<







9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
...
349
350
351
352
353
354
355










356
357
358
359
360
361
362
**    May you share freely, never taking more than you give.
**
*************************************************************************
** This module contains C code that generates VDBE code used to process
** the WHERE clause of SQL statements.  Also found here are subroutines
** to generate VDBE code to evaluate expressions.
**
** $Id: where.c,v 1.57 2002/06/28 01:02:38 drh Exp $
*/
#include "sqliteInt.h"

/*
** The query generator uses an array of instances of this structure to
** help it analyze the subexpressions of the WHERE clause.  Each WHERE
** clause subexpression is separated from the others by an AND operator.
................................................................................
  int nExpr;           /* Number of subexpressions in the WHERE clause */
  int loopMask;        /* One bit set for each outer loop */
  int haveKey;         /* True if KEY is on the stack */
  int aDirect[32];     /* If TRUE, then index this table using ROWID */
  int iDirectEq[32];   /* Term of the form ROWID==X for the N-th table */
  int iDirectLt[32];   /* Term of the form ROWID<X or ROWID<=X */
  int iDirectGt[32];   /* Term of the form ROWID>X or ROWID>=X */
  ExprInfo aExpr[101]; /* The WHERE clause is divided into these expressions */

  /* pushKey is only allowed if there is a single table (as in an INSERT or
  ** UPDATE statement)
  */
  assert( pushKey==0 || pTabList->nSrc==1 );

  /* Split the WHERE clause into separate subexpressions where each
  ** subexpression is separated by an AND operator.  If the aExpr[]
  ** array fills up, the last entry might point to an expression which
  ** contains additional unfactored AND operators.
  */
  memset(aExpr, 0, sizeof(aExpr));
  nExpr = exprSplit(ARRAYSIZE(aExpr), aExpr, pWhere);
  if( nExpr==ARRAYSIZE(aExpr) ){
    char zBuf[50];
    sprintf(zBuf, "%d", ARRAYSIZE(aExpr)-1);
    sqliteSetString(&pParse->zErrMsg, "WHERE clause too complex - no more "
       "than ", zBuf, " terms allowed", 0);
    pParse->nErr++;
    return 0;
  }
  
  /* Allocate space for aOrder[] */
  aOrder = sqliteMalloc( sizeof(int) * pTabList->nSrc );

  /* Allocate and initialize the WhereInfo structure that will become the
  ** return value.
  */
................................................................................
  ** expression and either jump over all of the code or fall thru.
  */
  if( pWhere && sqliteExprIsConstant(pWhere) ){
    sqliteExprIfFalse(pParse, pWhere, pWInfo->iBreak, 1);
    pWhere = 0;
  }











  /* Analyze all of the subexpressions.
  */
  for(i=0; i<nExpr; i++){
    exprAnalyze(base, &aExpr[i]);

    /* If we are executing a trigger body, remove all references to
    ** new.* and old.* tables from the prerequisite masks.

Changes to test/misc1.test.

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
253
254
255
256
257
258
259
260











































261
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc1.test,v 1.9 2002/06/21 23:01:51 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
    CREATE TABLE t1(a unique not null, b unique not null);
    INSERT INTO t1 VALUES('a',12345678901234567890);
    INSERT INTO t1 VALUES('b',12345678911234567890);
    INSERT INTO t1 VALUES('c',12345678921234567890);
    SELECT * FROM t1;
  }
} {0 {a 12345678901234567890 b 12345678911234567890 c 12345678921234567890}}












































finish_test







|







 








>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>

9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests for miscellanous features that were
# left out of other test files.
#
# $Id: misc1.test,v 1.10 2002/06/28 01:02:39 drh Exp $

set testdir [file dirname $argv0]
source $testdir/tester.tcl

# Test the creation and use of tables that have a large number
# of columns.
#
................................................................................
    CREATE TABLE t1(a unique not null, b unique not null);
    INSERT INTO t1 VALUES('a',12345678901234567890);
    INSERT INTO t1 VALUES('b',12345678911234567890);
    INSERT INTO t1 VALUES('c',12345678921234567890);
    SELECT * FROM t1;
  }
} {0 {a 12345678901234567890 b 12345678911234567890 c 12345678921234567890}}

# A WHERE clause is not allowed to contain more than 99 terms.  Check to
# make sure this limit is enforced.
#
do_test misc1-10.0 {
  execsql {SELECT count(*) FROM manycol}
} {9}
do_test misc1-10.1 {
  set ::where {WHERE x0>=0}
  for {set i 1} {$i<=99} {incr i} {
    append ::where " AND x$i<>0"
  }
  catchsql "SELECT count(*) FROM manycol $::where"
} {0 9}
do_test misc1-10.2 {
  catchsql "SELECT count(*) FROM manycol $::where AND rowid>0"
} {1 {WHERE clause too complex - no more than 100 terms allowed}}
do_test misc1-10.3 {
  regsub "x0>=0" $::where "x0=0" ::where
  catchsql "DELETE FROM manycol $::where"
} {0 {}}
do_test misc1-10.4 {
  execsql {SELECT count(*) FROM manycol}
} {8}
do_test misc1-10.5 {
  catchsql "DELETE FROM manycol $::where AND rowid>0"
} {1 {WHERE clause too complex - no more than 100 terms allowed}}
do_test misc1-10.6 {
  execsql {SELECT x1 FROM manycol WHERE x0=100}
} {101}
do_test misc1-10.7 {
  regsub "x0=0" $::where "x0=100" ::where
  catchsql "UPDATE manycol SET x1=x1+1 $::where"
} {0 {}}
do_test misc1-10.8 {
  execsql {SELECT x1 FROM manycol WHERE x0=100}
} {102}
do_test misc1-10.9 {
  catchsql "UPDATE manycol SET x1=x1+1 $::where AND rowid>0"
} {1 {WHERE clause too complex - no more than 100 terms allowed}}
do_test misc1-10.10 {
  execsql {SELECT x1 FROM manycol WHERE x0=100}
} {102}

finish_test