/ Check-in [ccfe4580]
Login

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

Overview
Comment:Fix some problems in the fts3 expression parser with mismatched parenthesis. (CVS 6095)
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: ccfe4580ac7ba9add0e69c786a9a3a43d69b7753
User & Date: danielk1977 2009-01-01 14:06:13
Context
2009-01-01
15:20
Fix a (benign) valgrind error that can occur following malloc failure while executing a 'ROLLBACK TO savepoint' command. (CVS 6096) check-in: 9ff8598f user: danielk1977 tags: trunk
14:06
Fix some problems in the fts3 expression parser with mismatched parenthesis. (CVS 6095) check-in: ccfe4580 user: danielk1977 tags: trunk
12:34
Additional test cases and cleanup of FTS3 parenthesis processing. (CVS 6094) check-in: afac4293 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_expr.c.

284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
309
310
311
312
313
314
315



316
317
318
319
320
321
322
...
364
365
366
367
368
369
370



371
372
373
374
375
376
377
...
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
...
593
594
595
596
597
598
599

600
601
602
603
604
605
606
  ParseContext *pParse,                   /* fts3 query parse context */
  const char *z, int n,                   /* Input string */
  Fts3Expr **ppExpr,                      /* OUT: expression */
  int *pnConsumed                         /* OUT: Number of bytes consumed */
){
  static const struct Fts3Keyword {
    char z[4];                            /* Keyword text */
    u8 n;                                 /* Length of the keyword */
    u8 parenOnly;                         /* Only valid in paren mode */
    u8 eType;                             /* Keyword code */
  } aKeyword[] = {
    { "OR" ,  2, 0, FTSQUERY_OR   },
    { "AND",  3, 1, FTSQUERY_AND  },
    { "NOT",  3, 1, FTSQUERY_NOT  },
    { "NEAR", 4, 0, FTSQUERY_NEAR }
  };
  int ii;
................................................................................
  /* Skip over any whitespace before checking for a keyword, an open or
  ** close bracket, or a quoted string. 
  */
  while( nInput>0 && fts3isspace(*zInput) ){
    nInput--;
    zInput++;
  }




  /* See if we are dealing with a keyword. */
  for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){
    const struct Fts3Keyword *pKey = &aKeyword[ii];

    if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){
      continue;
................................................................................
  /* Check for an open bracket. */
  if( sqlite3_fts3_enable_parentheses ){
    if( *zInput=='(' ){
      int nConsumed;
      int rc;
      pParse->nNest++;
      rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);



      *pnConsumed = (zInput - z) + 1 + nConsumed;
      return rc;
    }
  
    /* Check for a close bracket. */
    if( *zInput==')' ){
      pParse->nNest--;
................................................................................
  int nIn = n;
  const char *zIn = z;
  int rc = SQLITE_OK;
  int isRequirePhrase = 1;

  while( rc==SQLITE_OK ){
    Fts3Expr *p = 0;
    int nByte;
    rc = getNextNode(pParse, zIn, nIn, &p, &nByte);
    if( rc==SQLITE_OK ){
      int isPhrase;

      if( !sqlite3_fts3_enable_parentheses 
       && p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot 
      ){
................................................................................
        }else{
          insertBinaryOperator(&pRet, pPrev, p);
        }
        isRequirePhrase = !isPhrase;
      }
      assert( nByte>0 );
    }

    nIn -= nByte;
    zIn += nByte;
    pPrev = p;
  }

  if( rc==SQLITE_DONE && pRet && isRequirePhrase ){
    rc = SQLITE_ERROR;







|
|
|







 







>
>
>







 







>
>
>







 







|







 







>







284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
...
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
...
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
...
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
  ParseContext *pParse,                   /* fts3 query parse context */
  const char *z, int n,                   /* Input string */
  Fts3Expr **ppExpr,                      /* OUT: expression */
  int *pnConsumed                         /* OUT: Number of bytes consumed */
){
  static const struct Fts3Keyword {
    char z[4];                            /* Keyword text */
    unsigned char n;                      /* Length of the keyword */
    unsigned char parenOnly;              /* Only valid in paren mode */
    unsigned char eType;                  /* Keyword code */
  } aKeyword[] = {
    { "OR" ,  2, 0, FTSQUERY_OR   },
    { "AND",  3, 1, FTSQUERY_AND  },
    { "NOT",  3, 1, FTSQUERY_NOT  },
    { "NEAR", 4, 0, FTSQUERY_NEAR }
  };
  int ii;
................................................................................
  /* Skip over any whitespace before checking for a keyword, an open or
  ** close bracket, or a quoted string. 
  */
  while( nInput>0 && fts3isspace(*zInput) ){
    nInput--;
    zInput++;
  }
  if( nInput==0 ){
    return SQLITE_DONE;
  }

  /* See if we are dealing with a keyword. */
  for(ii=0; ii<(int)(sizeof(aKeyword)/sizeof(struct Fts3Keyword)); ii++){
    const struct Fts3Keyword *pKey = &aKeyword[ii];

    if( (pKey->parenOnly & ~sqlite3_fts3_enable_parentheses)!=0 ){
      continue;
................................................................................
  /* Check for an open bracket. */
  if( sqlite3_fts3_enable_parentheses ){
    if( *zInput=='(' ){
      int nConsumed;
      int rc;
      pParse->nNest++;
      rc = fts3ExprParse(pParse, &zInput[1], nInput-1, ppExpr, &nConsumed);
      if( rc==SQLITE_OK && !*ppExpr ){
        rc = SQLITE_DONE;
      }
      *pnConsumed = (zInput - z) + 1 + nConsumed;
      return rc;
    }
  
    /* Check for a close bracket. */
    if( *zInput==')' ){
      pParse->nNest--;
................................................................................
  int nIn = n;
  const char *zIn = z;
  int rc = SQLITE_OK;
  int isRequirePhrase = 1;

  while( rc==SQLITE_OK ){
    Fts3Expr *p = 0;
    int nByte = 0;
    rc = getNextNode(pParse, zIn, nIn, &p, &nByte);
    if( rc==SQLITE_OK ){
      int isPhrase;

      if( !sqlite3_fts3_enable_parentheses 
       && p->eType==FTSQUERY_PHRASE && p->pPhrase->isNot 
      ){
................................................................................
        }else{
          insertBinaryOperator(&pRet, pPrev, p);
        }
        isRequirePhrase = !isPhrase;
      }
      assert( nByte>0 );
    }
    assert( rc!=SQLITE_OK || (nByte>0 && nByte<=nIn) );
    nIn -= nByte;
    zIn += nByte;
    pPrev = p;
  }

  if( rc==SQLITE_DONE && pRet && isRequirePhrase ){
    rc = SQLITE_ERROR;

Changes to test/fts3expr.test.

7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
333
334
335
336
337
338
339













340
341
342
343
344
345
346
#    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.  The
# focus of this script is testing the FTS3 module.
#
# $Id: fts3expr.test,v 1.5 2009/01/01 12:34:46 drh Exp $
#

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

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
................................................................................
# Mismatched parenthesis:
do_test fts3expr-4.2.1 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world))' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.2.2 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world' }
} {1 {SQL logic error or missing database}}














# Unterminated quotation marks:
do_test fts3expr-4.3.1 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR "hello world' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.3.2 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR hello world"' }







|







 







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







7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
...
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
#    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.  The
# focus of this script is testing the FTS3 module.
#
# $Id: fts3expr.test,v 1.6 2009/01/01 14:06:13 danielk1977 Exp $
#

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

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 {
................................................................................
# Mismatched parenthesis:
do_test fts3expr-4.2.1 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world))' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.2.2 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example AND (hello OR world' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.2.3 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH '(hello' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.2.4 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH '(' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.2.5 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH ')' }
} {1 {SQL logic error or missing database}}

do_test fts3expr-4.2.6 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example (hello world' }
} {1 {SQL logic error or missing database}}

# Unterminated quotation marks:
do_test fts3expr-4.3.1 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR "hello world' }
} {1 {SQL logic error or missing database}}
do_test fts3expr-4.3.2 {
  catchsql { SELECT * FROM t1 WHERE t1 MATCH 'example OR hello world"' }

Changes to test/savepoint.test.

5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
520
521
522
523
524
525
526
527
528
529
530
531
532
#
#    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.
#
#***********************************************************************
#
# $Id: savepoint.test,v 1.5 2008/12/30 06:24:58 danielk1977 Exp $

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


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
    concat $::authdata $res
  } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {} 1 {not authorized}}
  do_test savepoint-9.6 {
    set ::authdata [list]
    set res [catchsql { RELEASE sp1 }]
    concat $::authdata $res
  } {SQLITE_SAVEPOINT RELEASE sp1 {} {} 1 {not authorized}}

}


finish_test








|







 







<





5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
...
520
521
522
523
524
525
526

527
528
529
530
531
#
#    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.
#
#***********************************************************************
#
# $Id: savepoint.test,v 1.6 2009/01/01 14:06:13 danielk1977 Exp $

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


#----------------------------------------------------------------------
# The following tests - savepoint-1.* - test that the SAVEPOINT, RELEASE
................................................................................
    concat $::authdata $res
  } {SQLITE_SAVEPOINT ROLLBACK sp1 {} {} 1 {not authorized}}
  do_test savepoint-9.6 {
    set ::authdata [list]
    set res [catchsql { RELEASE sp1 }]
    concat $::authdata $res
  } {SQLITE_SAVEPOINT RELEASE sp1 {} {} 1 {not authorized}}

}


finish_test