/ Check-in [e400909f]
Login

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

Overview
Comment:Fix an FTS5 problem that could cause a crash when certain queries were interrupted using sqlite3_interrupt().
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: e400909f313c317b7b67be6eb867ed61df7383dc
User & Date: dan 2017-02-21 17:52:58
Context
2017-02-21
21:24
In sqlite3VdbeHalt(), return as soon as possible if Vdbe.magic!=VDBE_MAGIC_RUN. This makes sqlite3_reset() slightly faster in some cases. check-in: 80adc0cb user: dan tags: trunk
17:52
Fix an FTS5 problem that could cause a crash when certain queries were interrupted using sqlite3_interrupt(). check-in: e400909f user: dan tags: trunk
15:27
Very small enhancement to dispatch speed for SQL functions. check-in: 3c3228ed user: drh tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to ext/fts5/fts5_expr.c.

1106
1107
1108
1109
1110
1111
1112
1113



1114
1115
1116
1117
1118
1119
1120
....
1137
1138
1139
1140
1141
1142
1143
1144



1145
1146
1147
1148
1149
1150
1151
....
1176
1177
1178
1179
1180
1181
1182


1183
1184
1185
1186
1187
1188
1189
....
1218
1219
1220
1221
1222
1223
1224



1225
1226
1227
1228
1229
1230
1231
    Fts5ExprNode *p1 = pNode->apChild[i];
    assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    if( p1->bEof==0 ){
      if( (p1->iRowid==iLast) 
       || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
      ){
        int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
        if( rc!=SQLITE_OK ) return rc;



      }
    }
  }

  fts5ExprNodeTest_OR(pExpr, pNode);
  return SQLITE_OK;
}
................................................................................
    bMatch = 1;
    for(iChild=0; iChild<pAnd->nChild; iChild++){
      Fts5ExprNode *pChild = pAnd->apChild[iChild];
      int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
      if( cmp>0 ){
        /* Advance pChild until it points to iLast or laster */
        rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
        if( rc!=SQLITE_OK ) return rc;



      }

      /* If the child node is now at EOF, so is the parent AND node. Otherwise,
      ** the child node is guaranteed to have advanced at least as far as
      ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the
      ** new lastest rowid seen so far.  */
      assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 );
................................................................................
  Fts5ExprNode *pNode,
  int bFromValid,
  i64 iFrom
){
  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
  if( rc==SQLITE_OK ){
    rc = fts5ExprNodeTest_AND(pExpr, pNode);


  }
  return rc;
}

static int fts5ExprNodeTest_NOT(
  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
  Fts5ExprNode *pNode             /* FTS5_NOT node to advance */
................................................................................
  int bFromValid,
  i64 iFrom
){
  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
  if( rc==SQLITE_OK ){
    rc = fts5ExprNodeTest_NOT(pExpr, pNode);
  }



  return rc;
}

/*
** If pNode currently points to a match, this function returns SQLITE_OK
** without modifying it. Otherwise, pNode is advanced until it does point
** to a match or EOF is reached.







|
>
>
>







 







|
>
>
>







 







>
>







 







>
>
>







1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
....
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
....
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
....
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
    Fts5ExprNode *p1 = pNode->apChild[i];
    assert( p1->bEof || fts5RowidCmp(pExpr, p1->iRowid, iLast)>=0 );
    if( p1->bEof==0 ){
      if( (p1->iRowid==iLast) 
       || (bFromValid && fts5RowidCmp(pExpr, p1->iRowid, iFrom)<0)
      ){
        int rc = fts5ExprNodeNext(pExpr, p1, bFromValid, iFrom);
        if( rc!=SQLITE_OK ){
          pNode->bNomatch = 0;
          return rc;
        }
      }
    }
  }

  fts5ExprNodeTest_OR(pExpr, pNode);
  return SQLITE_OK;
}
................................................................................
    bMatch = 1;
    for(iChild=0; iChild<pAnd->nChild; iChild++){
      Fts5ExprNode *pChild = pAnd->apChild[iChild];
      int cmp = fts5RowidCmp(pExpr, iLast, pChild->iRowid);
      if( cmp>0 ){
        /* Advance pChild until it points to iLast or laster */
        rc = fts5ExprNodeNext(pExpr, pChild, 1, iLast);
        if( rc!=SQLITE_OK ){
          pAnd->bNomatch = 0;
          return rc;
        }
      }

      /* If the child node is now at EOF, so is the parent AND node. Otherwise,
      ** the child node is guaranteed to have advanced at least as far as
      ** rowid iLast. So if it is not at exactly iLast, pChild->iRowid is the
      ** new lastest rowid seen so far.  */
      assert( pChild->bEof || fts5RowidCmp(pExpr, iLast, pChild->iRowid)<=0 );
................................................................................
  Fts5ExprNode *pNode,
  int bFromValid,
  i64 iFrom
){
  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
  if( rc==SQLITE_OK ){
    rc = fts5ExprNodeTest_AND(pExpr, pNode);
  }else{
    pNode->bNomatch = 0;
  }
  return rc;
}

static int fts5ExprNodeTest_NOT(
  Fts5Expr *pExpr,                /* Expression pPhrase belongs to */
  Fts5ExprNode *pNode             /* FTS5_NOT node to advance */
................................................................................
  int bFromValid,
  i64 iFrom
){
  int rc = fts5ExprNodeNext(pExpr, pNode->apChild[0], bFromValid, iFrom);
  if( rc==SQLITE_OK ){
    rc = fts5ExprNodeTest_NOT(pExpr, pNode);
  }
  if( rc!=SQLITE_OK ){
    pNode->bNomatch = 0;
  }
  return rc;
}

/*
** If pNode currently points to a match, this function returns SQLITE_OK
** without modifying it. Otherwise, pNode is advanced until it does point
** to a match or EOF is reached.

Added ext/fts5/test/fts5faultD.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
# 2016 February 2
#
# 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 is focused on OOM errors.
#

source [file join [file dirname [info script]] fts5_common.tcl]
source $testdir/malloc_common.tcl
set testprefix fts5faultA

# If SQLITE_ENABLE_FTS3 is defined, omit this file.
ifcapable !fts5 {
  finish_test
  return
}

foreach_detail_mode $testprefix {
  if {"%DETAIL%"=="none"} continue

  do_execsql_test 1.0 {
    CREATE VIRTUAL TABLE o1 USING fts5(a, b, c, detail=%DETAIL%);
    INSERT INTO o1(o1, rank) VALUES('pgsz', 32);

    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
    INSERT INTO o1 SELECT 'A', 'B', 'C' FROM s;

    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
    INSERT INTO o1 SELECT 'C', 'A', 'B' FROM s;

    WITH s(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<60 )
    INSERT INTO o1 SELECT 'B', 'C', 'A' FROM s;
  }
  
  do_faultsim_test 1 -faults int* -prep {
    sqlite3 db test.db
  } -body {
    execsql { SELECT count(*) FROM o1('a') }
  } -test {
    faultsim_test_result {0 180} {1 {vtable constructor failed: o1}}
  }

  do_faultsim_test 2 -faults int* -prep {
    sqlite3 db test.db
  } -body {
    execsql { SELECT * FROM o1('a:a AND {b c}:b') ORDER BY rank }
    expr 1
  } -test {
    faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
  }

  do_faultsim_test 3 -faults int* -prep {
    sqlite3 db test.db
  } -body {
    execsql { SELECT * FROM o1('{b c}:b NOT a:a') ORDER BY rank }
    expr 1
  } -test {
    faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
  }

  do_faultsim_test 4 -faults int* -prep {
    sqlite3 db test.db
  } -body {
    execsql { SELECT * FROM o1('b:b OR a:a') }
    expr 1
  } -test {
    faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
  }

  do_faultsim_test 5 -faults int* -prep {
    sqlite3 db test.db
  } -body {
    execsql { SELECT count(*) FROM o1('c:b') }
    expr 1
  } -test {
    faultsim_test_result {0 1} {1 {vtable constructor failed: o1}}
  }
}

finish_test