/ Check-in [4d3e1673]
Login

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

Overview
Comment:Have the FTS auxiliary functions correctly handle terms that appear in non-matching branches of the FTS expression. Fix for [bdc6bbbb38].
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 4d3e1673b309a3d6a6cac01d67dfd79a8007f991
User & Date: dan 2012-05-10 17:43:14
References
2012-05-10
17:58 Ticket [bdc6bbbb] Problem with FTS aux. functions when used with OR queries with enhanced query syntax enabled status still Open with 1 other change artifact: f8aa3808 user: dan
Context
2012-05-11
11:28
Fix a harmless compiler warning. check-in: 2b77301b user: drh tags: trunk
2012-05-10
17:43
Have the FTS auxiliary functions correctly handle terms that appear in non-matching branches of the FTS expression. Fix for [bdc6bbbb38]. check-in: 4d3e1673 user: dan tags: trunk
2012-05-08
11:17
Further changes to constraint parsing to support legacy syntax. check-in: 38bf90af user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3.c.

3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
....
3987
3988
3989
3990
3991
3992
3993



































3994
3995
3996
3997
3998
3999
4000
....
5143
5144
5145
5146
5147
5148
5149
5150
5151
5152
5153

5154
5155
5156
5157
5158

5159



5160
5161
5162
5163
5164
5165
5166
5167
5168




































5169
























5170
5171
5172
5173
5174
5175
5176
5177
5178
5179
5180
5181
5182
5183

5184
5185
5186
5187
5188
5189
5190
*/
void sqlite3Fts3DoclistPrev(
  int bDescIdx,                   /* True if the doclist is desc */
  char *aDoclist,                 /* Pointer to entire doclist */
  int nDoclist,                   /* Length of aDoclist in bytes */
  char **ppIter,                  /* IN/OUT: Iterator pointer */
  sqlite3_int64 *piDocid,         /* IN/OUT: Docid pointer */
  int *pnList,                    /* IN/OUT: List length pointer */
  u8 *pbEof                       /* OUT: End-of-file flag */
){
  char *p = *ppIter;

  assert( nDoclist>0 );
  assert( *pbEof==0 );
  assert( p || *piDocid==0 );
................................................................................
      char *pSave = p;
      fts3ReversePoslist(aDoclist, &p);
      *pnList = (int)(pSave - p);
    }
    *ppIter = p;
  }
}




































/*
** Attempt to move the phrase iterator to point to the next matching docid. 
** If an error occurs, return an SQLite error code. Otherwise, return 
** SQLITE_OK.
**
** If there is no "next" entry and no error occurs, then *pbEof is set to
................................................................................
** for 'X' is requested, the buffer returned may contain:
**
**     0x04 0x05 0x03 0x01   or   0x04 0x05 0x03 0x00
**
** This function works regardless of whether or not the phrase is deferred,
** incremental, or neither.
*/
char *sqlite3Fts3EvalPhrasePoslist(
  Fts3Cursor *pCsr,               /* FTS3 cursor object */
  Fts3Expr *pExpr,                /* Phrase to return doclist for */
  int iCol                        /* Column to return position list for */

){
  Fts3Phrase *pPhrase = pExpr->pPhrase;
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  char *pIter = pPhrase->doclist.pList;
  int iThis;





  assert( iCol>=0 && iCol<pTab->nColumn );
  if( !pIter 
   || pExpr->bEof 
   || pExpr->iDocid!=pCsr->iPrevId
   || (pPhrase->iColumn<pTab->nColumn && pPhrase->iColumn!=iCol) 
  ){
    return 0;
  }





































  assert( pPhrase->doclist.nList>0 );
























  if( *pIter==0x01 ){
    pIter++;
    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
  }else{
    iThis = 0;
  }
  while( iThis<iCol ){
    fts3ColumnlistCopy(0, &pIter);
    if( *pIter==0x00 ) return 0;
    pIter++;
    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
  }

  return ((iCol==iThis)?pIter:0);

}

/*
** Free all components of the Fts3Phrase structure that were allocated by
** the eval module. Specifically, this means to free:
**
**   * the contents of pPhrase->doclist, and







|







 







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







 







|


|
>



|

>

>
>
>

<
<
<
|
<
|


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













|
>







3941
3942
3943
3944
3945
3946
3947
3948
3949
3950
3951
3952
3953
3954
3955
....
3987
3988
3989
3990
3991
3992
3993
3994
3995
3996
3997
3998
3999
4000
4001
4002
4003
4004
4005
4006
4007
4008
4009
4010
4011
4012
4013
4014
4015
4016
4017
4018
4019
4020
4021
4022
4023
4024
4025
4026
4027
4028
4029
4030
4031
4032
4033
4034
4035
....
5178
5179
5180
5181
5182
5183
5184
5185
5186
5187
5188
5189
5190
5191
5192
5193
5194
5195
5196
5197
5198
5199
5200



5201

5202
5203
5204
5205
5206
5207
5208
5209
5210
5211
5212
5213
5214
5215
5216
5217
5218
5219
5220
5221
5222
5223
5224
5225
5226
5227
5228
5229
5230
5231
5232
5233
5234
5235
5236
5237
5238
5239
5240
5241
5242
5243
5244
5245
5246
5247
5248
5249
5250
5251
5252
5253
5254
5255
5256
5257
5258
5259
5260
5261
5262
5263
5264
5265
5266
5267
5268
5269
5270
5271
5272
5273
5274
5275
5276
5277
5278
5279
5280
5281
5282
5283
5284
5285
5286
5287
*/
void sqlite3Fts3DoclistPrev(
  int bDescIdx,                   /* True if the doclist is desc */
  char *aDoclist,                 /* Pointer to entire doclist */
  int nDoclist,                   /* Length of aDoclist in bytes */
  char **ppIter,                  /* IN/OUT: Iterator pointer */
  sqlite3_int64 *piDocid,         /* IN/OUT: Docid pointer */
  int *pnList,                    /* OUT: List length pointer */
  u8 *pbEof                       /* OUT: End-of-file flag */
){
  char *p = *ppIter;

  assert( nDoclist>0 );
  assert( *pbEof==0 );
  assert( p || *piDocid==0 );
................................................................................
      char *pSave = p;
      fts3ReversePoslist(aDoclist, &p);
      *pnList = (int)(pSave - p);
    }
    *ppIter = p;
  }
}

/*
** Iterate forwards through a doclist.
*/
void sqlite3Fts3DoclistNext(
  int bDescIdx,                   /* True if the doclist is desc */
  char *aDoclist,                 /* Pointer to entire doclist */
  int nDoclist,                   /* Length of aDoclist in bytes */
  char **ppIter,                  /* IN/OUT: Iterator pointer */
  sqlite3_int64 *piDocid,         /* IN/OUT: Docid pointer */
  u8 *pbEof                       /* OUT: End-of-file flag */
){
  char *p = *ppIter;

  assert( nDoclist>0 );
  assert( *pbEof==0 );
  assert( p || *piDocid==0 );
  assert( !p || (p>=aDoclist && p<=&aDoclist[nDoclist]) );

  if( p==0 ){
    p = aDoclist;
    p += sqlite3Fts3GetVarint(p, piDocid);
  }else{
    fts3PoslistCopy(0, &p);
    if( p>=&aDoclist[nDoclist] ){
      *pbEof = 1;
    }else{
      sqlite3_int64 iVar;
      p += sqlite3Fts3GetVarint(p, &iVar);
      *piDocid += ((bDescIdx ? -1 : 1) * iVar);
    }
  }

  *ppIter = p;
}

/*
** Attempt to move the phrase iterator to point to the next matching docid. 
** If an error occurs, return an SQLite error code. Otherwise, return 
** SQLITE_OK.
**
** If there is no "next" entry and no error occurs, then *pbEof is set to
................................................................................
** for 'X' is requested, the buffer returned may contain:
**
**     0x04 0x05 0x03 0x01   or   0x04 0x05 0x03 0x00
**
** This function works regardless of whether or not the phrase is deferred,
** incremental, or neither.
*/
int sqlite3Fts3EvalPhrasePoslist(
  Fts3Cursor *pCsr,               /* FTS3 cursor object */
  Fts3Expr *pExpr,                /* Phrase to return doclist for */
  int iCol,                       /* Column to return position list for */
  char **ppOut                    /* OUT: Pointer to position list */
){
  Fts3Phrase *pPhrase = pExpr->pPhrase;
  Fts3Table *pTab = (Fts3Table *)pCsr->base.pVtab;
  char *pIter;
  int iThis;
  sqlite3_int64 iDocid;

  /* If this phrase is applies specifically to some column other than 
  ** column iCol, return a NULL pointer.  */
  *ppOut = 0;
  assert( iCol>=0 && iCol<pTab->nColumn );



  if( (pPhrase->iColumn<pTab->nColumn && pPhrase->iColumn!=iCol) ){

    return SQLITE_OK;
  }

  iDocid = pExpr->iDocid;
  pIter = pPhrase->doclist.pList;
  if( iDocid!=pCsr->iPrevId || pExpr->bEof ){
    int bDescDoclist = pTab->bDescIdx;      /* For DOCID_CMP macro */
    int bOr = 0;
    u8 bEof = 0;
    Fts3Expr *p;

    /* Check if this phrase descends from an OR expression node. If not, 
    ** return NULL. Otherwise, the entry that corresponds to docid 
    ** pCsr->iPrevId may lie earlier in the doclist buffer. */
    for(p=pExpr->pParent; p; p=p->pParent){
      if( p->eType==FTSQUERY_OR ) bOr = 1;
    }
    if( bOr==0 ) return SQLITE_OK;

    /* This is the descendent of an OR node. In this case we cannot use
    ** an incremental phrase. Load the entire doclist for the phrase
    ** into memory in this case.  */
    if( pPhrase->bIncr ){
      int rc = SQLITE_OK;
      int bEofSave = pExpr->bEof;
      fts3EvalRestart(pCsr, pExpr, &rc);
      while( rc==SQLITE_OK && !pExpr->bEof ){
        fts3EvalNextRow(pCsr, pExpr, &rc);
        if( bEofSave==0 && pExpr->iDocid==iDocid ) break;
      }
      pIter = pPhrase->doclist.pList;
      assert( rc!=SQLITE_OK || pPhrase->bIncr==0 );
      if( rc!=SQLITE_OK ) return rc;
    }

    if( pExpr->bEof ){
      pIter = 0;
      iDocid = 0;
    }
    bEof = (pPhrase->doclist.nAll==0);
    assert( bDescDoclist==0 || bDescDoclist==1 );
    assert( pCsr->bDesc==0 || pCsr->bDesc==1 );

    if( pCsr->bDesc==bDescDoclist ){
      int dummy;
      while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)>0 ) && bEof==0 ){
        sqlite3Fts3DoclistPrev(
            bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, 
            &pIter, &iDocid, &dummy, &bEof
        );
      }
    }else{
      while( (pIter==0 || DOCID_CMP(iDocid, pCsr->iPrevId)<0 ) && bEof==0 ){
        sqlite3Fts3DoclistNext(
            bDescDoclist, pPhrase->doclist.aAll, pPhrase->doclist.nAll, 
            &pIter, &iDocid, &bEof
        );
      }
    }

    if( bEof || iDocid!=pCsr->iPrevId ) pIter = 0;
  }
  if( pIter==0 ) return SQLITE_OK;

  if( *pIter==0x01 ){
    pIter++;
    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
  }else{
    iThis = 0;
  }
  while( iThis<iCol ){
    fts3ColumnlistCopy(0, &pIter);
    if( *pIter==0x00 ) return 0;
    pIter++;
    pIter += sqlite3Fts3GetVarint32(pIter, &iThis);
  }

  *ppOut = ((iCol==iThis)?pIter:0);
  return SQLITE_OK;
}

/*
** Free all components of the Fts3Phrase structure that were allocated by
** the eval module. Specifically, this means to free:
**
**   * the contents of pPhrase->doclist, and

Changes to ext/fts3/fts3Int.h.

531
532
533
534
535
536
537
538
539
540
541
542
543
544
545

void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *);

int sqlite3Fts3MsrIncrStart(
    Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
int sqlite3Fts3MsrIncrNext(
    Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
char *sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol); 
int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);

int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *);

#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */







|







531
532
533
534
535
536
537
538
539
540
541
542
543
544
545

void sqlite3Fts3EvalPhraseCleanup(Fts3Phrase *);

int sqlite3Fts3MsrIncrStart(
    Fts3Table*, Fts3MultiSegReader*, int, const char*, int);
int sqlite3Fts3MsrIncrNext(
    Fts3Table *, Fts3MultiSegReader *, sqlite3_int64 *, char **, int *);
int sqlite3Fts3EvalPhrasePoslist(Fts3Cursor *, Fts3Expr *, int iCol, char **); 
int sqlite3Fts3MsrOvfl(Fts3Cursor *, Fts3MultiSegReader *, int *);
int sqlite3Fts3MsrIncrRestart(Fts3MultiSegReader *pCsr);

int sqlite3Fts3DeferredTokenList(Fts3DeferredToken *, char **, int *);

#endif /* !SQLITE_CORE || SQLITE_ENABLE_FTS3 */
#endif /* _FTSINT_H */

Changes to ext/fts3/fts3_snippet.c.

356
357
358
359
360
361
362

363
364
365
366

367
368
369
370
371
372
373
374
375
376

377

378
379
380
381
382
383
384
385
386
387
...
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
...
941
942
943
944
945
946
947

948
949

950
951
952
953
954
955
956
....
1294
1295
1296
1297
1298
1299
1300

1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
** Each invocation populates an element of the SnippetIter.aPhrase[] array.
*/
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
  SnippetIter *p = (SnippetIter *)ctx;
  SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
  char *pCsr;


  pPhrase->nToken = pExpr->pPhrase->nToken;

  pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);

  if( pCsr ){
    int iFirst = 0;
    pPhrase->pList = pCsr;
    fts3GetDeltaPosition(&pCsr, &iFirst);
    assert( iFirst>=0 );
    pPhrase->pHead = pCsr;
    pPhrase->pTail = pCsr;
    pPhrase->iHead = iFirst;
    pPhrase->iTail = iFirst;
  }else{

    assert( pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 );

  }

  return SQLITE_OK;
}

/*
** Select the fragment of text consisting of nFragment contiguous tokens 
** from column iCol that represent the "best" snippet. The best snippet
** is the snippet with the highest score, where scores are calculated
** by adding:
................................................................................
** array that are different for each row returned by the query.
*/
static int fts3ExprLocalHitsCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number */
  void *pCtx                      /* Pointer to MatchInfo structure */
){

  MatchInfo *p = (MatchInfo *)pCtx;
  int iStart = iPhrase * p->nCol * 3;
  int i;

  for(i=0; i<p->nCol; i++){
    char *pCsr;
    pCsr = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i);
    if( pCsr ){
      p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr);
    }else{
      p->aMatchinfo[iStart+i*3] = 0;
    }
  }

  return SQLITE_OK;
}

static int fts3MatchinfoCheck(
  Fts3Table *pTab, 
  char cArg,
  char **pzErr
){
................................................................................
  }

  for(iCol=0; iCol<pInfo->nCol; iCol++){
    int nLcs = 0;                 /* LCS value for this column */
    int nLive = 0;                /* Number of iterators in aIter not at EOF */

    for(i=0; i<pInfo->nPhrase; i++){

      LcsIterator *pIt = &aIter[i];
      pIt->pRead = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol);

      if( pIt->pRead ){
        pIt->iPos = pIt->iPosOffset;
        fts3LcsIteratorAdvance(&aIter[i]);
        nLive++;
      }
    }

................................................................................
*/
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
  TermOffsetCtx *p = (TermOffsetCtx *)ctx;
  int nTerm;                      /* Number of tokens in phrase */
  int iTerm;                      /* For looping through nTerm phrase terms */
  char *pList;                    /* Pointer to position list for phrase */
  int iPos = 0;                   /* First position in position-list */


  UNUSED_PARAMETER(iPhrase);
  pList = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol);
  nTerm = pExpr->pPhrase->nToken;
  if( pList ){
    fts3GetDeltaPosition(&pList, &iPos);
    assert( iPos>=0 );
  }

  for(iTerm=0; iTerm<nTerm; iTerm++){
    TermOffset *pT = &p->aTerm[p->iTerm++];
    pT->iOff = nTerm-iTerm-1;
    pT->pList = pList;
    pT->iPos = iPos;
  }

  return SQLITE_OK;
}

/*
** Implementation of offsets() function.
*/
void sqlite3Fts3Offsets(
  sqlite3_context *pCtx,          /* SQLite function call context */







>


<
|
>










>
|
>


|







 







>




|

|







|







 







>

|
>







 







>


|













|







356
357
358
359
360
361
362
363
364
365

366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
...
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
798
...
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
....
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
** This function is an fts3ExprIterate() callback used by fts3BestSnippet().
** Each invocation populates an element of the SnippetIter.aPhrase[] array.
*/
static int fts3SnippetFindPositions(Fts3Expr *pExpr, int iPhrase, void *ctx){
  SnippetIter *p = (SnippetIter *)ctx;
  SnippetPhrase *pPhrase = &p->aPhrase[iPhrase];
  char *pCsr;
  int rc;

  pPhrase->nToken = pExpr->pPhrase->nToken;

  rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pCsr);
  assert( rc==SQLITE_OK || pCsr==0 );
  if( pCsr ){
    int iFirst = 0;
    pPhrase->pList = pCsr;
    fts3GetDeltaPosition(&pCsr, &iFirst);
    assert( iFirst>=0 );
    pPhrase->pHead = pCsr;
    pPhrase->pTail = pCsr;
    pPhrase->iHead = iFirst;
    pPhrase->iTail = iFirst;
  }else{
    assert( rc!=SQLITE_OK || (
       pPhrase->pList==0 && pPhrase->pHead==0 && pPhrase->pTail==0 
    ));
  }

  return rc;
}

/*
** Select the fragment of text consisting of nFragment contiguous tokens 
** from column iCol that represent the "best" snippet. The best snippet
** is the snippet with the highest score, where scores are calculated
** by adding:
................................................................................
** array that are different for each row returned by the query.
*/
static int fts3ExprLocalHitsCb(
  Fts3Expr *pExpr,                /* Phrase expression node */
  int iPhrase,                    /* Phrase number */
  void *pCtx                      /* Pointer to MatchInfo structure */
){
  int rc = SQLITE_OK;
  MatchInfo *p = (MatchInfo *)pCtx;
  int iStart = iPhrase * p->nCol * 3;
  int i;

  for(i=0; i<p->nCol && rc==SQLITE_OK; i++){
    char *pCsr;
    rc = sqlite3Fts3EvalPhrasePoslist(p->pCursor, pExpr, i, &pCsr);
    if( pCsr ){
      p->aMatchinfo[iStart+i*3] = fts3ColumnlistCount(&pCsr);
    }else{
      p->aMatchinfo[iStart+i*3] = 0;
    }
  }

  return rc;
}

static int fts3MatchinfoCheck(
  Fts3Table *pTab, 
  char cArg,
  char **pzErr
){
................................................................................
  }

  for(iCol=0; iCol<pInfo->nCol; iCol++){
    int nLcs = 0;                 /* LCS value for this column */
    int nLive = 0;                /* Number of iterators in aIter not at EOF */

    for(i=0; i<pInfo->nPhrase; i++){
      int rc;
      LcsIterator *pIt = &aIter[i];
      rc = sqlite3Fts3EvalPhrasePoslist(pCsr, pIt->pExpr, iCol, &pIt->pRead);
      if( rc!=SQLITE_OK ) return rc;
      if( pIt->pRead ){
        pIt->iPos = pIt->iPosOffset;
        fts3LcsIteratorAdvance(&aIter[i]);
        nLive++;
      }
    }

................................................................................
*/
static int fts3ExprTermOffsetInit(Fts3Expr *pExpr, int iPhrase, void *ctx){
  TermOffsetCtx *p = (TermOffsetCtx *)ctx;
  int nTerm;                      /* Number of tokens in phrase */
  int iTerm;                      /* For looping through nTerm phrase terms */
  char *pList;                    /* Pointer to position list for phrase */
  int iPos = 0;                   /* First position in position-list */
  int rc;

  UNUSED_PARAMETER(iPhrase);
  rc = sqlite3Fts3EvalPhrasePoslist(p->pCsr, pExpr, p->iCol, &pList);
  nTerm = pExpr->pPhrase->nToken;
  if( pList ){
    fts3GetDeltaPosition(&pList, &iPos);
    assert( iPos>=0 );
  }

  for(iTerm=0; iTerm<nTerm; iTerm++){
    TermOffset *pT = &p->aTerm[p->iTerm++];
    pT->iOff = nTerm-iTerm-1;
    pT->pList = pList;
    pT->iPos = iPos;
  }

  return rc;
}

/*
** Implementation of offsets() function.
*/
void sqlite3Fts3Offsets(
  sqlite3_context *pCtx,          /* SQLite function call context */

Changes to test/backcompat.test.

247
248
249
250
251
252
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
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
336
337
338
339
340
341
342
343
344
345
346
347

348
349
350
351

352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420

421
  }
}

#-------------------------------------------------------------------------
# Test that FTS3 tables may be read/written by different versions of 
# SQLite. 
#

set contents {
  CREATE VIRTUAL TABLE t1 USING fts3(a, b);
}
foreach {num doc} {
  one "jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf"
  two "jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh"
  three "wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw"
  four "gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh"
  five "zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm"
  six "sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju"
  seven "vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj"
  eight "zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk"
  nine  "zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk"
} {
  append contents "INSERT INTO t1 VALUES('$num', '$doc');"
}
do_allbackcompat_test {
  if {[code1 {set ::sqlite_options(fts3)}]
   && [code2 {set ::sqlite_options(fts3)}]
  } {

    do_test backcompat-3.1 { sql1 $contents } {}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
    } {
      do_test backcompat-3.2 [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-3.3 { sql1 {
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
      INSERT INTO t1 SELECT * FROM t1;
    } } {}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
    } {
      do_test backcompat-3.4 [list sql1 $q] [sql2 $q]
    }

    set alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4"
    for {set i 0} {$i < 900} {incr i} {
      set term "[lindex $alphabet [expr $i/30]][lindex $alphabet [expr $i%30]] "
      sql1 "INSERT INTO t1 VALUES($i, '[string repeat $term 14]')"
    }

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"

      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
    } {
      do_test backcompat-3.5 [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-3.6 { 
      sql1 "SELECT optimize(t1) FROM t1 LIMIT 1" 
    } {{Index optimized}}

    foreach {n q} {
      1    "SELECT * FROM t1 ORDER BY a, b"
      2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
      3    "SELECT * FROM t1 WHERE a MATCH 'five'"
      4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
      5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"

      6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
      7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
      8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
    } {
      do_test backcompat-3.7 [list sql1 $q] [sql2 $q]
    }
  }
}


#-------------------------------------------------------------------------
# Test that Rtree tables may be read/written by different versions of 
# SQLite. 
#

set contents {
  CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2);
}
foreach {id x1 x2 y1 y2} {
  1    -47.64 43.87    33.86 34.42        2    -21.51 17.32    2.05 31.04
  3    -43.67 -38.33    -19.79 3.43       4    32.41 35.16    9.12 19.82
  5    33.28 34.87    14.78 28.26         6    49.31 116.59    -9.87 75.09
  7    -14.93 34.51    -17.64 64.09       8    -43.05 23.43    -1.19 69.44
  9    44.79 133.56    28.09 80.30        10    -2.66 81.47    -41.38 -10.46
  11    -42.89 -3.54    15.76 71.63       12    -3.50 84.96    -11.64 64.95
  13    -45.69 26.25    11.14 55.06       14    -44.09 11.23    17.52 44.45
  15    36.23 133.49    -19.38 53.67      16    -17.89 81.54    14.64 50.61
  17    -41.97 -24.04    -39.43 28.95     18    -5.85 7.76    -6.38 47.02
  19    18.82 27.10    42.82 100.09       20    39.17 113.45    26.14 73.47
  21    22.31 103.17    49.92 106.05      22    -43.06 40.38    -1.75 76.08
  23    2.43 57.27    -14.19 -3.83        24    -47.57 -4.35    8.93 100.06
  25    -37.47 49.14    -29.11 8.81       26    -7.86 75.72    49.34 107.42
  27    1.53 45.49    20.36 49.74         28    -48.48 32.54    28.81 54.45
  29    2.67 39.77    -4.05 13.67         30    4.11 62.88    -47.44 -5.72
  31    -21.47 51.75    37.25 116.09      32    45.59 111.37    -6.43 43.64
  33    35.23 48.29    23.54 113.33       34    16.61 68.35    -14.69 65.97
  35    13.98 16.60    48.66 102.87       36    19.74 23.84    31.15 77.27
  37    -27.61 24.43    7.96 94.91        38    -34.77 12.05    -22.60 -6.29
  39    -25.83 8.71    -13.48 -12.53      40    -17.11 -1.01    18.06 67.89
  41    14.13 71.72    -3.78 39.25        42    23.75 76.00    -16.30 8.23
  43    -39.15 28.63    38.12 125.88      44    48.62 86.09    36.49 102.95
  45    -31.39 -21.98    2.52 89.78       46    5.65 56.04    15.94 89.10
  47    18.28 95.81    46.46 143.08       48    30.93 102.82    -20.08 37.36
  49    -20.78 -3.48    -5.58 35.46       50    49.85 90.58    -24.48 46.29
} {
if {$x1 >= $x2 || $y1 >= $y2} { error "$x1 $x2 $y1 $y2" }
  append contents "INSERT INTO t1 VALUES($id, $x1, $x2, $y1, $y2);"
}
set queries {
  1    "SELECT id FROM t1 WHERE x1>10 AND x2<44"
  2    "SELECT id FROM t1 WHERE y1<100"
  3    "SELECT id FROM t1 WHERE y1<100 AND x1>0"
  4    "SELECT id FROM t1 WHERE y1>10 AND x1>0 AND x2<50 AND y2<550"
}
do_allbackcompat_test {
  if {[code1 {set ::sqlite_options(fts3)}]
   && [code2 {set ::sqlite_options(fts3)}]
  } {

    do_test backcompat-4.1 { sql1 $contents } {}

    foreach {n q} $::queries {
      do_test backcompat-4.2.$n [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-4.3 { sql1 {
      INSERT INTO t1 SELECT id+100, x1+10.0, x2+10.0, y1-10.0, y2-10.0 FROM t1;
    } } {}

    foreach {n q} $::queries {
      do_test backcompat-4.4.$n [list sql1 $q] [sql2 $q]
    }

    do_test backcompat-4.5 { sql2 {
      INSERT INTO t1 SELECT id+200, x1+20.0, x2+20.0, y1-20.0, y2-20.0 FROM t1;
    } } {}

    foreach {n q} $::queries {
      do_test backcompat-4.6.$n [list sql1 $q] [sql2 $q]
    }

  }
}


finish_test







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




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

247
248
249
250
251
252
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
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
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
  }
}

#-------------------------------------------------------------------------
# Test that FTS3 tables may be read/written by different versions of 
# SQLite. 
#
ifcapable fts3 {
  set contents {
    CREATE VIRTUAL TABLE t1 USING fts3(a, b);
  }
  foreach {num doc} {
    one "jk zm jk eczkjblu urvysbnykk sk gnl jk ttvgf hmjf"
    two "jk bnhc jjrxpjkb mjpavjuhw fibokdry igju jk zm zm xh"
    three "wxe ogttbykvt uhzq xr iaf zf urvysbnykk aayxpmve oacaxgjoo mjpavjuhw"
    four "gazrt jk ephknonq myjp uenvbm wuvajhwqz jk zm xnxhf nvfasfh"
    five "zm aayxpmve csjqxhgj xnxhf xr jk aayxpmve xnxhf zm zm"
    six "sokcyf zm ogyavjvv jk zm fibokdry zm jk igju igju"
    seven "vgsld bvgimjik xuprtlyle jk akmikrqyt jk aayxpmve hkfoudzftq ddjj"
    eight "zm uhzq ovkyevlgv zk uenvbm csjqxhgj jk vgsld pgybs jk"
    nine  "zm agmckuiu zexh fibokdry jk uhzq bu tugflixoex xnxhf sk"
  } {
    append contents "INSERT INTO t1 VALUES('$num', '$doc');"
  }
  do_allbackcompat_test {
    if {[code1 {set ::sqlite_options(fts3)}]
     && [code2 {set ::sqlite_options(fts3)}]
    } {
  
      do_test backcompat-3.1 { sql1 $contents } {}
  
      foreach {n q} {
        1    "SELECT * FROM t1 ORDER BY a, b"
        2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
        3    "SELECT * FROM t1 WHERE a MATCH 'five'"
        4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
        5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
      } {
        do_test backcompat-3.2 [list sql1 $q] [sql2 $q]
      }
  
      do_test backcompat-3.3 { sql1 {
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
        INSERT INTO t1 SELECT * FROM t1;
      } } {}
  
      foreach {n q} {
        1    "SELECT * FROM t1 ORDER BY a, b"
        2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
        3    "SELECT * FROM t1 WHERE a MATCH 'five'"
        4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
        5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
      } {
        do_test backcompat-3.4 [list sql1 $q] [sql2 $q]
      }
  
      set alphabet "a b c d e f g h i j k l m n o p q r s t u v w x y z 1 2 3 4"
      for {set i 0} {$i < 900} {incr i} {
        set term "[lindex $alphabet [expr $i/30]][lindex $alphabet [expr $i%30]] "
        sql1 "INSERT INTO t1 VALUES($i, '[string repeat $term 14]')"
      }
  
      foreach {n q} {
        1    "SELECT * FROM t1 ORDER BY a, b"
        2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
        3    "SELECT * FROM t1 WHERE a MATCH 'five'"
        4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
        5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
  
        6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
        7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
        8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
      } {
        do_test backcompat-3.5 [list sql1 $q] [sql2 $q]
      }
  
      do_test backcompat-3.6 { 
        sql1 "SELECT optimize(t1) FROM t1 LIMIT 1" 
      } {{Index optimized}}
  
      foreach {n q} {
        1    "SELECT * FROM t1 ORDER BY a, b"
        2    "SELECT rowid FROM t1 WHERE a MATCH 'five'"
        3    "SELECT * FROM t1 WHERE a MATCH 'five'"
        4    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'jk'"
        5    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'tug* OR eight'"
  
        6    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'aa'"
        7    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH '44'"
        8    "SELECT offsets(t1) FROM t1 WHERE t1 MATCH 'a*'"
      } {
        do_test backcompat-3.7 [list sql1 $q] [sql2 $q]
      }
    }
  }
}

#-------------------------------------------------------------------------
# Test that Rtree tables may be read/written by different versions of 
# SQLite. 
#
ifcapable rtree {
  set contents {
    CREATE VIRTUAL TABLE t1 USING rtree(id, x1, x2, y1, y2);
  }
  foreach {id x1 x2 y1 y2} {
    1    -47.64 43.87    33.86 34.42        2    -21.51 17.32    2.05 31.04
    3    -43.67 -38.33    -19.79 3.43       4    32.41 35.16    9.12 19.82
    5    33.28 34.87    14.78 28.26         6    49.31 116.59    -9.87 75.09
    7    -14.93 34.51    -17.64 64.09       8    -43.05 23.43    -1.19 69.44
    9    44.79 133.56    28.09 80.30        10    -2.66 81.47    -41.38 -10.46
    11    -42.89 -3.54    15.76 71.63       12    -3.50 84.96    -11.64 64.95
    13    -45.69 26.25    11.14 55.06       14    -44.09 11.23    17.52 44.45
    15    36.23 133.49    -19.38 53.67      16    -17.89 81.54    14.64 50.61
    17    -41.97 -24.04    -39.43 28.95     18    -5.85 7.76    -6.38 47.02
    19    18.82 27.10    42.82 100.09       20    39.17 113.45    26.14 73.47
    21    22.31 103.17    49.92 106.05      22    -43.06 40.38    -1.75 76.08
    23    2.43 57.27    -14.19 -3.83        24    -47.57 -4.35    8.93 100.06
    25    -37.47 49.14    -29.11 8.81       26    -7.86 75.72    49.34 107.42
    27    1.53 45.49    20.36 49.74         28    -48.48 32.54    28.81 54.45
    29    2.67 39.77    -4.05 13.67         30    4.11 62.88    -47.44 -5.72
    31    -21.47 51.75    37.25 116.09      32    45.59 111.37    -6.43 43.64
    33    35.23 48.29    23.54 113.33       34    16.61 68.35    -14.69 65.97
    35    13.98 16.60    48.66 102.87       36    19.74 23.84    31.15 77.27
    37    -27.61 24.43    7.96 94.91        38    -34.77 12.05    -22.60 -6.29
    39    -25.83 8.71    -13.48 -12.53      40    -17.11 -1.01    18.06 67.89
    41    14.13 71.72    -3.78 39.25        42    23.75 76.00    -16.30 8.23
    43    -39.15 28.63    38.12 125.88      44    48.62 86.09    36.49 102.95
    45    -31.39 -21.98    2.52 89.78       46    5.65 56.04    15.94 89.10
    47    18.28 95.81    46.46 143.08       48    30.93 102.82    -20.08 37.36
    49    -20.78 -3.48    -5.58 35.46       50    49.85 90.58    -24.48 46.29
  } {
  if {$x1 >= $x2 || $y1 >= $y2} { error "$x1 $x2 $y1 $y2" }
    append contents "INSERT INTO t1 VALUES($id, $x1, $x2, $y1, $y2);"
  }
  set queries {
    1    "SELECT id FROM t1 WHERE x1>10 AND x2<44"
    2    "SELECT id FROM t1 WHERE y1<100"
    3    "SELECT id FROM t1 WHERE y1<100 AND x1>0"
    4    "SELECT id FROM t1 WHERE y1>10 AND x1>0 AND x2<50 AND y2<550"
  }
  do_allbackcompat_test {
    if {[code1 {set ::sqlite_options(fts3)}]
     && [code2 {set ::sqlite_options(fts3)}]
    } {
  
      do_test backcompat-4.1 { sql1 $contents } {}
  
      foreach {n q} $::queries {
        do_test backcompat-4.2.$n [list sql1 $q] [sql2 $q]
      }
  
      do_test backcompat-4.3 { sql1 {
        INSERT INTO t1 SELECT id+100, x1+10.0, x2+10.0, y1-10.0, y2-10.0 FROM t1;
      } } {}
  
      foreach {n q} $::queries {
        do_test backcompat-4.4.$n [list sql1 $q] [sql2 $q]
      }
  
      do_test backcompat-4.5 { sql2 {
        INSERT INTO t1 SELECT id+200, x1+20.0, x2+20.0, y1-20.0, y2-20.0 FROM t1;
      } } {}
  
      foreach {n q} $::queries {
        do_test backcompat-4.6.$n [list sql1 $q] [sql2 $q]
      }
  
    }
  }
}

finish_test

Changes to test/fts3auto.test.

71
72
73
74
75
76
77
78

79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
...
646
647
648
649
650
651
652

653
654
655
656
657
658
659
      }
      default {
        error "bad option \"$k\": must be -deferred"
      }
    }
  }

  get_near_results $tbl $match $deferred aMatchinfo


  set matchinfo_asc [list]
  foreach docid [lsort -integer -incr [array names aMatchinfo]] {
    lappend matchinfo_asc $docid $aMatchinfo($docid)
  }
  set matchinfo_desc [list]
  foreach docid [lsort -integer -decr [array names aMatchinfo]] {
    lappend matchinfo_desc $docid $aMatchinfo($docid)
  }

  set title "(\"$match\" -> [llength [array names aMatchinfo]] rows)"

  do_execsql_test $tn$title.1 "
    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC
  " [lsort -integer -incr [array names aMatchinfo]] 

  do_execsql_test $tn$title.2 "
    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC
  " [lsort -integer -decr [array names aMatchinfo]] 

  do_execsql_test $tn$title.3 "
    SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl 
    WHERE $tbl MATCH '$match' ORDER BY docid DESC
  " $matchinfo_desc

  do_execsql_test $tn$title.4 "
................................................................................
    execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) }
  }

  do_fts3query_test 6.$tn.1 t1 {b:G}
  do_fts3query_test 6.$tn.2 t1 {b:G AND c:I}
  do_fts3query_test 6.$tn.3 t1 {b:G NEAR c:I}
  do_fts3query_test 6.$tn.4 t1 {a:C OR b:G OR c:K OR d:C}

  do_fts3query_test 6.$tn.5 t1 {a:G OR b:G}

  catchsql { COMMIT }
}

foreach {tn create} {
  1    "fts4(x)"







|
>


|



|



|



|



|







 







>







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
...
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
      }
      default {
        error "bad option \"$k\": must be -deferred"
      }
    }
  }

  get_near_results $tbl $match $deferred aHit
  get_near_results $tbl [string map {AND OR} $match] $deferred aMatchinfo

  set matchinfo_asc [list]
  foreach docid [lsort -integer -incr [array names aHit]] {
    lappend matchinfo_asc $docid $aMatchinfo($docid)
  }
  set matchinfo_desc [list]
  foreach docid [lsort -integer -decr [array names aHit]] {
    lappend matchinfo_desc $docid $aMatchinfo($docid)
  }

  set title "(\"$match\" -> [llength [array names aHit]] rows)"

  do_execsql_test $tn$title.1 "
    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid ASC
  " [lsort -integer -incr [array names aHit]] 

  do_execsql_test $tn$title.2 "
    SELECT docid FROM $tbl WHERE $tbl MATCH '$match' ORDER BY docid DESC
  " [lsort -integer -decr [array names aHit]] 

  do_execsql_test $tn$title.3 "
    SELECT docid, mit(matchinfo($tbl, 'x')) FROM $tbl 
    WHERE $tbl MATCH '$match' ORDER BY docid DESC
  " $matchinfo_desc

  do_execsql_test $tn$title.4 "
................................................................................
    execsql { INSERT INTO t1 VALUES($a, $b, $c, $d) }
  }

  do_fts3query_test 6.$tn.1 t1 {b:G}
  do_fts3query_test 6.$tn.2 t1 {b:G AND c:I}
  do_fts3query_test 6.$tn.3 t1 {b:G NEAR c:I}
  do_fts3query_test 6.$tn.4 t1 {a:C OR b:G OR c:K OR d:C}

  do_fts3query_test 6.$tn.5 t1 {a:G OR b:G}

  catchsql { COMMIT }
}

foreach {tn create} {
  1    "fts4(x)"

Added test/tkt-bdc6bbbb38.test.



















































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
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
87
88
89
# 2012 May 11
#
# The author disclaims copyright to this source code.  In place of
# a legal notice, here is a blessing:
#
#    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.
#
#***********************************************************************
# This file implements regression tests for SQLite library.
#
# This file implements tests to verify that ticket [bdc6bbbb38] has been
# fixed.  
#

set testdir [file dirname $argv0]
source $testdir/tester.tcl
set testprefix tkt-bdc6bbbb38

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts3 { finish_test ; return }
set sqlite_fts3_enable_parentheses 1

foreach {tn idxdir} {1 ASC 2 DESC} {
  execsql { DROP TABLE IF EXISTS t2 }

  do_execsql_test $tn.1.1 "CREATE VIRTUAL TABLE t2 USING fts4(x, order=$idxdir)"
  do_execsql_test $tn.1.2 { INSERT INTO t2 VALUES('a b c') }

  do_execsql_test $tn.1.3 {
    SELECT offsets(t2) FROM t2 WHERE t2 MATCH 'a AND d OR b' ORDER BY docid ASC
  } {
    {0 0 0 1 0 2 2 1}
  }
  do_execsql_test $tn.1.4 {
    SELECT snippet(t2,'[',']') FROM t2 WHERE t2 MATCH 'a AND d OR b' 
    ORDER BY docid ASC
  } {
    {[a] [b] c}
  }
  do_execsql_test $tn.1.5 { INSERT INTO t2 VALUES('a c d') }
  do_execsql_test $tn.1.6 {
    SELECT offsets(t2) FROM t2 WHERE t2 MATCH 'a AND d OR b' ORDER BY docid ASC
  } {
    {0 0 0 1 0 2 2 1}
    {0 0 0 1 0 1 4 1}
  }
  do_execsql_test $tn.1.7 {
    SELECT snippet(t2,'[',']') FROM t2 WHERE t2 MATCH 'a AND d OR b'
    ORDER BY docid ASC
  } {
    {[a] [b] c}
    {[a] c [d]}
  }

  execsql { DROP TABLE IF EXISTS t3 }
  do_execsql_test $tn.2.1 "CREATE VIRTUAL TABLE t3 USING fts4(x, order=$idxdir)"
  do_execsql_test $tn.2.2 { INSERT INTO t3 VALUES('a c d') }
  do_execsql_test $tn.2.3 {
    SELECT offsets(t3) FROM t3 WHERE t3 MATCH 'a AND d OR b' ORDER BY docid DESC
  } {
    {0 0 0 1 0 1 4 1}
  }
  do_execsql_test $tn.2.4 {
    SELECT snippet(t3,'[',']') FROM t3 WHERE t3 MATCH 'a AND d OR b'
      ORDER BY docid DESC
  } {
    {[a] c [d]}
  }
  do_execsql_test $tn.2.5 { 
    INSERT INTO t3 VALUES('a b c');
  }
  do_execsql_test $tn.2.6 {
    SELECT offsets(t3) FROM t3 WHERE t3 MATCH 'a AND d OR b' ORDER BY docid DESC
  } {
    {0 0 0 1 0 2 2 1}
    {0 0 0 1 0 1 4 1}
  }
  do_execsql_test $tn.2.7 {
    SELECT snippet(t3,'[',']') FROM t3 WHERE t3 MATCH 'a AND d OR b'
      ORDER BY docid DESC
  } {
    {[a] [b] c}
    {[a] c [d]}
  }
}

finish_test