SQLite

Check-in [0741812d7f]
Login

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

Overview
Comment:Fix a problem with the fts5 auxiliary function API causing a crash when a query contained a phrase of zero terms.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 0741812d7fcd558479e4849fbb3ba8d03738d018
User & Date: dan 2016-09-21 19:43:34.002
Context
2016-09-21
23:58
Fix speedtest1.c so that it works with SQLITE_OMIT_DEPRECATED. Add the --lean and --cachesize options to speed-check.sh. (check-in: 7785b3a257 user: drh tags: trunk)
19:43
Fix a problem with the fts5 auxiliary function API causing a crash when a query contained a phrase of zero terms. (check-in: 0741812d7f user: dan tags: trunk)
19:00
Do not run vacuummem.test if ENABLE_MEMORY_MANAGEMENT is defined. (check-in: 4a613d8564 user: dan tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to ext/fts5/fts5_expr.c.
750
751
752
753
754
755
756

757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787

788
789
790
791
792
793
794
795
796
797
static int fts5ExprNearInitAll(
  Fts5Expr *pExpr,
  Fts5ExprNode *pNode
){
  Fts5ExprNearset *pNear = pNode->pNear;
  int i, j;
  int rc = SQLITE_OK;


  assert( pNode->bNomatch==0 );
  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    for(j=0; j<pPhrase->nTerm; j++){
      Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
      Fts5ExprTerm *p;
      int bEof = 1;

      for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
        if( p->pIter ){
          sqlite3Fts5IterClose(p->pIter);
          p->pIter = 0;
        }
        rc = sqlite3Fts5IndexQuery(
            pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
            (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
            (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
            pNear->pColset,
            &p->pIter
        );
        assert( rc==SQLITE_OK || p->pIter==0 );
        if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
          bEof = 0;
        }
      }

      if( bEof ){
        pNode->bEof = 1;
        return rc;
      }

    }
  }

  return rc;
}

/*
** If pExpr is an ASC iterator, this function returns a value with the
** same sign as:
**







>







<



















|
<
<
|
>
|
|
|







750
751
752
753
754
755
756
757
758
759
760
761
762
763
764

765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784


785
786
787
788
789
790
791
792
793
794
795
796
static int fts5ExprNearInitAll(
  Fts5Expr *pExpr,
  Fts5ExprNode *pNode
){
  Fts5ExprNearset *pNear = pNode->pNear;
  int i, j;
  int rc = SQLITE_OK;
  int bEof = 1;

  assert( pNode->bNomatch==0 );
  for(i=0; rc==SQLITE_OK && i<pNear->nPhrase; i++){
    Fts5ExprPhrase *pPhrase = pNear->apPhrase[i];
    for(j=0; j<pPhrase->nTerm; j++){
      Fts5ExprTerm *pTerm = &pPhrase->aTerm[j];
      Fts5ExprTerm *p;


      for(p=pTerm; p && rc==SQLITE_OK; p=p->pSynonym){
        if( p->pIter ){
          sqlite3Fts5IterClose(p->pIter);
          p->pIter = 0;
        }
        rc = sqlite3Fts5IndexQuery(
            pExpr->pIndex, p->zTerm, (int)strlen(p->zTerm),
            (pTerm->bPrefix ? FTS5INDEX_QUERY_PREFIX : 0) |
            (pExpr->bDesc ? FTS5INDEX_QUERY_DESC : 0),
            pNear->pColset,
            &p->pIter
        );
        assert( rc==SQLITE_OK || p->pIter==0 );
        if( p->pIter && 0==sqlite3Fts5IterEof(p->pIter) ){
          bEof = 0;
        }
      }

      if( bEof ) break;


    }
    if( bEof ) break;
  }

  pNode->bEof = bEof;
  return rc;
}

/*
** If pExpr is an ASC iterator, this function returns a value with the
** same sign as:
**
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
int sqlite3Fts5ExprClonePhrase(
  Fts5Expr *pExpr, 
  int iPhrase, 
  Fts5Expr **ppNew
){
  int rc = SQLITE_OK;             /* Return code */
  Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */
  int i;                          /* Used to iterate through phrase terms */
  Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
  TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */

  pOrig = pExpr->apExprPhrase[iPhrase];
  pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
  if( rc==SQLITE_OK ){
    pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 







<







1633
1634
1635
1636
1637
1638
1639

1640
1641
1642
1643
1644
1645
1646
int sqlite3Fts5ExprClonePhrase(
  Fts5Expr *pExpr, 
  int iPhrase, 
  Fts5Expr **ppNew
){
  int rc = SQLITE_OK;             /* Return code */
  Fts5ExprPhrase *pOrig;          /* The phrase extracted from pExpr */

  Fts5Expr *pNew = 0;             /* Expression to return via *ppNew */
  TokenCtx sCtx = {0,0};          /* Context object for fts5ParseTokenize */

  pOrig = pExpr->apExprPhrase[iPhrase];
  pNew = (Fts5Expr*)sqlite3Fts5MallocZero(&rc, sizeof(Fts5Expr));
  if( rc==SQLITE_OK ){
    pNew->apExprPhrase = (Fts5ExprPhrase**)sqlite3Fts5MallocZero(&rc, 
1664
1665
1666
1667
1668
1669
1670


1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682





1683
1684
1685
1686
1687
1688
1689
      if( pColset ){ 
        memcpy(pColset, pColsetOrig, nByte);
      }
      pNew->pRoot->pNear->pColset = pColset;
    }
  }



  for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
    int tflags = 0;
    Fts5ExprTerm *p;
    for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
      const char *zTerm = p->zTerm;
      rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
          0, 0);
      tflags = FTS5_TOKEN_COLOCATED;
    }
    if( rc==SQLITE_OK ){
      sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
    }





  }

  if( rc==SQLITE_OK ){
    /* All the allocations succeeded. Put the expression object together. */
    pNew->pIndex = pExpr->pIndex;
    pNew->pConfig = pExpr->pConfig;
    pNew->nPhrase = 1;







>
>
|
|
|
|
|
|
|
|
|
|
|
|
>
>
>
>
>







1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
      if( pColset ){ 
        memcpy(pColset, pColsetOrig, nByte);
      }
      pNew->pRoot->pNear->pColset = pColset;
    }
  }

  if( pOrig->nTerm ){
    int i;                          /* Used to iterate through phrase terms */
    for(i=0; rc==SQLITE_OK && i<pOrig->nTerm; i++){
      int tflags = 0;
      Fts5ExprTerm *p;
      for(p=&pOrig->aTerm[i]; p && rc==SQLITE_OK; p=p->pSynonym){
        const char *zTerm = p->zTerm;
        rc = fts5ParseTokenize((void*)&sCtx, tflags, zTerm, (int)strlen(zTerm),
            0, 0);
        tflags = FTS5_TOKEN_COLOCATED;
      }
      if( rc==SQLITE_OK ){
        sCtx.pPhrase->aTerm[i].bPrefix = pOrig->aTerm[i].bPrefix;
      }
    }
  }else{
    /* This happens when parsing a token or quoted phrase that contains
    ** no token characters at all. (e.g ... MATCH '""'). */
    sCtx.pPhrase = sqlite3Fts5MallocZero(&rc, sizeof(Fts5ExprPhrase));
  }

  if( rc==SQLITE_OK ){
    /* All the allocations succeeded. Put the expression object together. */
    pNew->pIndex = pExpr->pIndex;
    pNew->pConfig = pExpr->pConfig;
    pNew->nPhrase = 1;
Changes to ext/fts5/test/fts5eb.test.
58
59
60
61
62
63
64

















65
66
67
68
69
do_catchsql_test 2.1 {
  SELECT fts5_expr()
} {1 {wrong number of arguments to function fts5_expr}}

do_catchsql_test 2.1 {
  SELECT fts5_expr_tcl()
} {1 {wrong number of arguments to function fts5_expr_tcl}}


















finish_test










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





58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
do_catchsql_test 2.1 {
  SELECT fts5_expr()
} {1 {wrong number of arguments to function fts5_expr}}

do_catchsql_test 2.1 {
  SELECT fts5_expr_tcl()
} {1 {wrong number of arguments to function fts5_expr_tcl}}


do_execsql_test 3.0 {
  CREATE VIRTUAL TABLE e1 USING fts5(text, tokenize = 'porter unicode61');
  INSERT INTO e1 VALUES ("just a few words with a / inside");
}
do_execsql_test 3.1 {
  SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"just"' ORDER BY rank;
} {1 -1e-06}
do_execsql_test 3.2 {
  SELECT rowid FROM e1 WHERE e1 MATCH '"/" OR "just"'
} 1
do_execsql_test 3.3 {
  SELECT rowid, bm25(e1) FROM e1 WHERE e1 MATCH '"/" OR "just"' ORDER BY rank;
} {1 -1e-06}



finish_test