/ Check-in [14ab536a]
Login

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

Overview
Comment:Fix a segfault in fts3 that may occur if the snippet, offsets or matchinfo functions are used in a query that does not contain a MATCH clause.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 14ab536a96f81595ab8c3dcd4b72075f1a827c8b
User & Date: dan 2010-02-10 05:33:18
Context
2010-02-12
18:18
Allow the secure-delete setting to be changed at run-time using a pragma. The SQLITE_SECURE_DELETE compile-time option determines the default setting. check-in: f72f8a87 user: drh tags: trunk
2010-02-10
05:33
Fix a segfault in fts3 that may occur if the snippet, offsets or matchinfo functions are used in a query that does not contain a MATCH clause. check-in: 14ab536a user: dan tags: trunk
2010-02-05
18:00
Make sure file descriptors are closed before unlinking in VxWorks. check-in: f64b81f1 user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts3/fts3_snippet.c.

921
922
923
924
925
926
927





928
929
930
931
932
933
934
....
1048
1049
1050
1051
1052
1053
1054





1055
1056
1057
1058
1059
1060
1061
....
1164
1165
1166
1167
1168
1169
1170





1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
  ** expression that appear in the current row. If such a fragment of text
  ** cannot be found, the second iteration of the loop attempts to locate
  ** a pair of fragments, and so on.
  */
  int nSnippet = 0;               /* Number of fragments in this snippet */
  SnippetFragment aSnippet[4];    /* Maximum of 4 fragments per snippet */
  int nFToken = -1;               /* Number of tokens in each fragment */






  for(nSnippet=1; 1; nSnippet++){

    int iSnip;                    /* Loop counter 0..nSnippet-1 */
    u64 mCovered = 0;             /* Bitmask of phrases covered by snippet */
    u64 mSeen = 0;                /* Bitmask of phrases seen by BestSnippet() */

................................................................................
  const char *ZDUMMY;             /* Dummy argument used with xNext() */
  int NDUMMY;                     /* Dummy argument used with xNext() */
  int rc;                         /* Return Code */
  int nToken;                     /* Number of tokens in query */
  int iCol;                       /* Column currently being processed */
  StrBuffer res = {0, 0, 0};      /* Result string */
  TermOffsetCtx sCtx;             /* Context for fts3ExprTermOffsetInit() */






  memset(&sCtx, 0, sizeof(sCtx));
  assert( pCsr->isRequireSeek==0 );

  /* Count the number of terms in the query */
  rc = fts3ExprLoadDoclists(pCsr, 0, &nToken);
  if( rc!=SQLITE_OK ) goto offsets_out;
................................................................................
  return;
}

/*
** Implementation of matchinfo() function.
*/
void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){





  int rc = fts3GetMatchinfo(pCsr);
  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pContext, rc);
  }else{
    Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
    int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
    if( pTab->bHasDocsize ){
      n += sizeof(u32)*(1 + 2*pTab->nColumn);
    }
    sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
  }
}

#endif







>
>
>
>
>







 







>
>
>
>
>







 







>
>
>
>
>
|













921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
....
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
....
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
  ** expression that appear in the current row. If such a fragment of text
  ** cannot be found, the second iteration of the loop attempts to locate
  ** a pair of fragments, and so on.
  */
  int nSnippet = 0;               /* Number of fragments in this snippet */
  SnippetFragment aSnippet[4];    /* Maximum of 4 fragments per snippet */
  int nFToken = -1;               /* Number of tokens in each fragment */

  if( !pCsr->pExpr ){
    sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
    return;
  }

  for(nSnippet=1; 1; nSnippet++){

    int iSnip;                    /* Loop counter 0..nSnippet-1 */
    u64 mCovered = 0;             /* Bitmask of phrases covered by snippet */
    u64 mSeen = 0;                /* Bitmask of phrases seen by BestSnippet() */

................................................................................
  const char *ZDUMMY;             /* Dummy argument used with xNext() */
  int NDUMMY;                     /* Dummy argument used with xNext() */
  int rc;                         /* Return Code */
  int nToken;                     /* Number of tokens in query */
  int iCol;                       /* Column currently being processed */
  StrBuffer res = {0, 0, 0};      /* Result string */
  TermOffsetCtx sCtx;             /* Context for fts3ExprTermOffsetInit() */

  if( !pCsr->pExpr ){
    sqlite3_result_text(pCtx, "", 0, SQLITE_STATIC);
    return;
  }

  memset(&sCtx, 0, sizeof(sCtx));
  assert( pCsr->isRequireSeek==0 );

  /* Count the number of terms in the query */
  rc = fts3ExprLoadDoclists(pCsr, 0, &nToken);
  if( rc!=SQLITE_OK ) goto offsets_out;
................................................................................
  return;
}

/*
** Implementation of matchinfo() function.
*/
void sqlite3Fts3Matchinfo(sqlite3_context *pContext, Fts3Cursor *pCsr){
  int rc;
  if( !pCsr->pExpr ){
    sqlite3_result_blob(pContext, "", 0, SQLITE_STATIC);
    return;
  }
  rc = fts3GetMatchinfo(pCsr);
  if( rc!=SQLITE_OK ){
    sqlite3_result_error_code(pContext, rc);
  }else{
    Fts3Table *pTab = (Fts3Table*)pCsr->base.pVtab;
    int n = sizeof(u32)*(2+pCsr->aMatchinfo[0]*pCsr->aMatchinfo[1]*3);
    if( pTab->bHasDocsize ){
      n += sizeof(u32)*(1 + 2*pTab->nColumn);
    }
    sqlite3_result_blob(pContext, pCsr->aMatchinfo, n, SQLITE_TRANSIENT);
  }
}

#endif

Changes to test/fts3snippet.test.

428
429
430
431
432
433
434
435



























436
437
438
    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}          
    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}
  }]
}




























set sqlite_fts3_enable_parentheses 0
finish_test







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



428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    {2 2 1 3 3 1 6 3 0 0 0 0 3 2}
    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    {2 2 1 3 3 2 6 3 0 0 0 1 3 2}
    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}          
    {2 2 1 3 3 3 6 3 0 0 0 2 3 2}
  }]

  # EVIDENCE-OF: R-56101-59725 If used within a SELECT that uses the
  # "query by rowid" or "linear scan" strategies, then the snippet and
  # offsets both return an an empty string, and the matchinfo function
  # returns a blob value zero bytes in size.
  #
  set r 1000000                   ;# A rowid that exists in table ft
  do_select_test $T.10.0 { SELECT rowid FROM ft WHERE rowid = $r } $r
  do_select_test $T.10.1 {
    SELECT length(offsets(ft)), typeof(offsets(ft)) FROM ft;
  } {0 text 0 text 0 text}
  do_select_test $T.10.2 {
    SELECT length(offsets(ft)), typeof(offsets(ft)) FROM ft WHERE rowid = $r
  } {0 text}
  do_select_test $T.10.3 {
    SELECT length(snippet(ft)), typeof(snippet(ft)) FROM ft;
  } {0 text 0 text 0 text}
  do_select_test $T.10.4 {
    SELECT length(snippet(ft)), typeof(snippet(ft)) FROM ft WHERE rowid = $r;
  } {0 text}
  do_select_test $T.10.5 {
    SELECT length(matchinfo(ft)), typeof(matchinfo(ft)) FROM ft;
  } {0 blob 0 blob 0 blob}
  do_select_test $T.10.6 {
    SELECT length(matchinfo(ft)), typeof(matchinfo(ft)) FROM ft WHERE rowid = $r
  } {0 blob}
}


set sqlite_fts3_enable_parentheses 0
finish_test