/ Check-in [f0c24b5f]
Login

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

Overview
Comment:Continuing refinements of the range-scan optimizations in where.c. The range scores are changed from an integer 1..9 to 0..100.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1:f0c24b5fb86940f1a88adfb39cc4b9cbfcc66f8a
User & Date: drh 2009-08-20 18:14:43
Context
2009-08-20
20:05
Simplifications to the range-scan logic in support of structural testing. check-in: bbbee810 user: drh tags: trunk
18:14
Continuing refinements of the range-scan optimizations in where.c. The range scores are changed from an integer 1..9 to 0..100. check-in: f0c24b5f user: drh tags: trunk
16:11
Change the code that collects samples for sqlite_stat2 so that the first sample taken is the (nRow/(2*SQLITE_INDEX_SAMPLES))th entry in the index, where nRow is the total number of index entries. check-in: cbfe6e9d user: dan tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to src/where.c.

1896
1897
1898
1899
1900
1901
1902
1903

1904
1905
1906
1907
1908
1909
1910
1911
1912
....
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
....
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016





2017
2018
2019
2020
2021
2022
2023
....
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037

2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051





2052







2053
2054



2055
2056
2057

2058
2059


2060
2061
2062
2063
2064
2065
2066
2067
2068
2069




2070
2071
2072
2073
2074
2075
2076
....
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218



2219
2220
2221
2222
2223
2224
2225
....
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
....
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
** stored in Index.aSample. The domain of values stored in said column
** may be thought of as divided into (SQLITE_INDEX_SAMPLES+1) regions.
** Region 0 contains all values smaller than the first sample value. Region
** 1 contains values larger than or equal to the value of the first sample,
** but smaller than the value of the second. And so on.
**
** If successful, this function determines which of the regions value 
** pVal lies in, sets *piRegion to the region index and returns SQLITE_OK.

** Or, if an OOM occurs while converting text values between encodings,
** SQLITE_NOMEM is returned.
*/
#ifdef SQLITE_ENABLE_STAT2
static int whereRangeRegion(
  Parse *pParse,              /* Database connection */
  Index *pIdx,                /* Index to consider domain of */
  sqlite3_value *pVal,        /* Value to consider */
  int *piRegion               /* OUT: Region of domain in which value lies */
................................................................................
** example, assuming that index p is on t1(a):
**
**   ... FROM t1 WHERE a > ? AND a < ? ...
**                    |_____|   |_____|
**                       |         |
**                     pLower    pUpper
**
** If the upper or lower bound is not present, then NULL should be passed in
** place of the corresponding WhereTerm.
**
** The nEq parameter is passed the index of the index column subject to the
** range constraint. Or, equivalently, the number of equality constraints
** optimized by the proposed index scan. For example, assuming index p is
** on t1(a, b), and the SQL query is:
**
................................................................................
** then nEq should be passed the value 1 (as the range restricted column,
** b, is the second left-most column of the index). Or, if the query is:
**
**   ... FROM t1 WHERE a > ? AND a < ? ...
**
** then nEq should be passed 0.
**
** The returned value is an integer between 1 and 9, inclusive. A return
** value of 1 indicates that the proposed range scan is expected to visit
** approximately 1/9 (11%) of the rows selected by the nEq equality constraints
** (if any). A return value of 9 indicates that it is expected that the
** range scan will visit 9/9 (100%) of the rows selected by the equality
** constraints.





*/
static int whereRangeScanEst(
  Parse *pParse,       /* Parsing & code generating context */
  Index *p,            /* The index containing the range-compared column; "x" */
  int nEq,             /* index into p->aCol[] of the range-compared column */
  WhereTerm *pLower,   /* Lower bound on the range. ex: "x>123" Might be NULL */
  WhereTerm *pUpper,   /* Upper bound on the range. ex: "x<455" Might be NULL */
................................................................................
#ifdef SQLITE_ENABLE_STAT2
  sqlite3 *db = pParse->db;
  sqlite3_value *pLowerVal = 0;
  sqlite3_value *pUpperVal = 0;

  if( nEq==0 && p->aSample ){
    int iEst;
    int iUpper = SQLITE_INDEX_SAMPLES;
    int iLower = 0;
    u8 aff = p->pTable->aCol[0].affinity;

    if( pLower ){
      Expr *pExpr = pLower->pExpr->pRight;
      rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pLowerVal);
      if( !pLowerVal ) goto fallback;
    }
    if( pUpper ){
      Expr *pExpr = pUpper->pExpr->pRight;
      rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pUpperVal);
      if( !pUpperVal ){
        sqlite3ValueFree(pLowerVal);
        goto fallback;
      }
    }






    rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);







    if( rc==SQLITE_OK ){
      rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);



    }

    iEst = iUpper - iLower;

    if( iEst>=SQLITE_INDEX_SAMPLES ) iEst = SQLITE_INDEX_SAMPLES-1;
    else if( iEst<1 ) iEst = 1;



    sqlite3ValueFree(pLowerVal);
    sqlite3ValueFree(pUpperVal);
    *piEst = iEst;
    return rc;
  }
fallback:
#endif
  assert( pLower || pUpper );
  *piEst = (SQLITE_INDEX_SAMPLES-1) / ((pLower&&pUpper)?9:3);




  return rc;
}


/*
** Find the query plan for accessing a particular table.  Write the
** best query plan and its cost into the WhereCost object supplied as the
................................................................................
    **    determining nInMul.
    **
    **  bInEst:  
    **    Set to true if there was at least one "x IN (SELECT ...)" term used 
    **    in determining the value of nInMul.
    **
    **  nBound:
    **    An estimate on the amount of the table that must be searched due
    **    to a range constraint.  The value is between 1 and 9 and indicates
    **    9ths of the table.  1 means that about 1/9th of the is searched.
    **    9 indicates that the entire table is searched.



    **
    **  bSort:   
    **    Boolean. True if there is an ORDER BY clause that will require an 
    **    external sort (i.e. scanning the index being evaluated will not 
    **    correctly order records).
    **
    **  bLookup: 
................................................................................
    **
    **             SELECT a, b    FROM tbl WHERE a = 1;
    **             SELECT a, b, c FROM tbl WHERE a = 1;
    */
    int nEq;
    int bInEst = 0;
    int nInMul = 1;
    int nBound = 9;
    int bSort = 0;
    int bLookup = 0;

    /* Determine the values of nEq and nInMul */
    for(nEq=0; nEq<pProbe->nColumn; nEq++){
      WhereTerm *pTerm;           /* A single term of the WHERE clause */
      int j = pProbe->aiColumn[nEq];
................................................................................
    ** rows plus log2(table-size) times the number of binary searches.
    */
    cost = nRow + nInMul*estLog(aiRowEst[0]);

    /* Adjust the number of rows and the cost downward to reflect rows
    ** that are excluded by range constraints.
    */
    nRow = nRow * (double)nBound / (double)9;
    cost = cost * (double)nBound / (double)9;

    /* Add in the estimated cost of sorting the result
    */
    if( bSort ){
      cost += cost*estLog(cost);
    }








|
>

|







 







|







 







|

|
|
|

>
>
>
>
>







 







|
|

>



<

|


<
<
<
|
|
<
>
>
>
>
>
|
>
>
>
>
>
>
>
|
|
>
>
>



>
|
|
>
>



|


|


|
>
>
>
>







 







|
|
|
|
>
>
>







 







|







 







|
|







1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
....
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
....
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
....
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047

2048
2049
2050
2051



2052
2053

2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
....
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
....
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
....
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
** stored in Index.aSample. The domain of values stored in said column
** may be thought of as divided into (SQLITE_INDEX_SAMPLES+1) regions.
** Region 0 contains all values smaller than the first sample value. Region
** 1 contains values larger than or equal to the value of the first sample,
** but smaller than the value of the second. And so on.
**
** If successful, this function determines which of the regions value 
** pVal lies in, sets *piRegion to the region index (a value between 0
** and SQLITE_INDEX_SAMPLES+1, inclusive) and returns SQLITE_OK.
** Or, if an OOM occurs while converting text values between encodings,
** SQLITE_NOMEM is returned and *piRegion is undefined.
*/
#ifdef SQLITE_ENABLE_STAT2
static int whereRangeRegion(
  Parse *pParse,              /* Database connection */
  Index *pIdx,                /* Index to consider domain of */
  sqlite3_value *pVal,        /* Value to consider */
  int *piRegion               /* OUT: Region of domain in which value lies */
................................................................................
** example, assuming that index p is on t1(a):
**
**   ... FROM t1 WHERE a > ? AND a < ? ...
**                    |_____|   |_____|
**                       |         |
**                     pLower    pUpper
**
** If either of the upper or lower bound is not present, then NULL is passed in
** place of the corresponding WhereTerm.
**
** The nEq parameter is passed the index of the index column subject to the
** range constraint. Or, equivalently, the number of equality constraints
** optimized by the proposed index scan. For example, assuming index p is
** on t1(a, b), and the SQL query is:
**
................................................................................
** then nEq should be passed the value 1 (as the range restricted column,
** b, is the second left-most column of the index). Or, if the query is:
**
**   ... FROM t1 WHERE a > ? AND a < ? ...
**
** then nEq should be passed 0.
**
** The returned value is an integer between 1 and 100, inclusive. A return
** value of 1 indicates that the proposed range scan is expected to visit
** approximately 1/100th (1%) of the rows selected by the nEq equality
** constraints (if any). A return value of 100 indicates that it is expected
** that the range scan will visit every row (100%) selected by the equality
** constraints.
**
** In the absence of sqlite_stat2 ANALYZE data, each range inequality
** reduces the search space by 2/3rds.  Hence a single constraint (x>?)
** results in a return of 33 and a range constraint (x>? AND x<?) results
** in a return of 11.
*/
static int whereRangeScanEst(
  Parse *pParse,       /* Parsing & code generating context */
  Index *p,            /* The index containing the range-compared column; "x" */
  int nEq,             /* index into p->aCol[] of the range-compared column */
  WhereTerm *pLower,   /* Lower bound on the range. ex: "x>123" Might be NULL */
  WhereTerm *pUpper,   /* Upper bound on the range. ex: "x<455" Might be NULL */
................................................................................
#ifdef SQLITE_ENABLE_STAT2
  sqlite3 *db = pParse->db;
  sqlite3_value *pLowerVal = 0;
  sqlite3_value *pUpperVal = 0;

  if( nEq==0 && p->aSample ){
    int iEst;
    int iUpper;
    int iLower;
    u8 aff = p->pTable->aCol[0].affinity;

    if( pLower ){
      Expr *pExpr = pLower->pExpr->pRight;
      rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pLowerVal);

    }
    if( rc==SQLITE_OK && pUpper ){
      Expr *pExpr = pUpper->pExpr->pRight;
      rc = sqlite3ValueFromExpr(db, pExpr, SQLITE_UTF8, aff, &pUpperVal);



    }


    if( rc!=SQLITE_OK || (pLowerVal==0 && pUpperVal==0) ){
      sqlite3ValueFree(pLowerVal);
      sqlite3ValueFree(pUpperVal);
      goto range_est_fallback;
    }else if( pLowerVal==0 ){
      rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);
      iLower = pLower ? iUpper/2 : 0;
    }else if( pUpperVal==0 ){
      rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);
      iUpper = pUpper ? (iLower + SQLITE_INDEX_SAMPLES + 1)/2 
                      : SQLITE_INDEX_SAMPLES;
    }else{
      rc = whereRangeRegion(pParse, p, pUpperVal, &iUpper);
      if( rc==SQLITE_OK ){
        rc = whereRangeRegion(pParse, p, pLowerVal, &iLower);
      }else{
        iLower = 0;
      }
    }

    iEst = iUpper - iLower;
    if( iEst>SQLITE_INDEX_SAMPLES ){
      iEst = SQLITE_INDEX_SAMPLES;
    }else if( iEst<1 ){
      iEst = 1;
    }

    sqlite3ValueFree(pLowerVal);
    sqlite3ValueFree(pUpperVal);
    *piEst = (iEst * 100)/SQLITE_INDEX_SAMPLES;
    return rc;
  }
range_est_fallback:
#endif
  assert( pLower || pUpper );
  if( pLower && pUpper ){
    *piEst = 11;
  }else{
    *piEst = 33;
  }
  return rc;
}


/*
** Find the query plan for accessing a particular table.  Write the
** best query plan and its cost into the WhereCost object supplied as the
................................................................................
    **    determining nInMul.
    **
    **  bInEst:  
    **    Set to true if there was at least one "x IN (SELECT ...)" term used 
    **    in determining the value of nInMul.
    **
    **  nBound:
    **    An estimate on the amount of the table that must be searched.  A
    **    value of 100 means the entire table is searched.  Range constraints
    **    might reduce this to a value less than 100 to indicate that only
    **    a fraction of the table needs searching.  In the absence of
    **    sqlite_stat2 ANALYZE data, a single inequality reduces the search
    **    space to 1/3rd its original size.  So an x>? constraint reduces
    **    nBound to 33.  Two constraints (x>? AND x<?) reduce nBound to 11.
    **
    **  bSort:   
    **    Boolean. True if there is an ORDER BY clause that will require an 
    **    external sort (i.e. scanning the index being evaluated will not 
    **    correctly order records).
    **
    **  bLookup: 
................................................................................
    **
    **             SELECT a, b    FROM tbl WHERE a = 1;
    **             SELECT a, b, c FROM tbl WHERE a = 1;
    */
    int nEq;
    int bInEst = 0;
    int nInMul = 1;
    int nBound = 100;
    int bSort = 0;
    int bLookup = 0;

    /* Determine the values of nEq and nInMul */
    for(nEq=0; nEq<pProbe->nColumn; nEq++){
      WhereTerm *pTerm;           /* A single term of the WHERE clause */
      int j = pProbe->aiColumn[nEq];
................................................................................
    ** rows plus log2(table-size) times the number of binary searches.
    */
    cost = nRow + nInMul*estLog(aiRowEst[0]);

    /* Adjust the number of rows and the cost downward to reflect rows
    ** that are excluded by range constraints.
    */
    nRow = (nRow * (double)nBound) / (double)100;
    cost = (cost * (double)nBound) / (double)100;

    /* Add in the estimated cost of sorting the result
    */
    if( bSort ){
      cost += cost*estLog(cost);
    }

Changes to test/where7.test.

86
87
88
89
90
91
92

93
94
95
96

97
98
99
100
101
102
103
....
5408
5409
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
....
6850
6851
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
....
8948
8949
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
} {2 4 5 scan 0 sort 0}
do_test where7-1.9 {
  count_steps {
    SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4)
  }
} {2 4 5 scan 0 sort 0}
do_test where7-1.10 {

  count_steps {
    SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10)
  }
} {2 4 5 scan 0 sort 0}

do_test where7-1.11 {
  count_steps {
    SELECT a FROM t1 WHERE (d=5 AND b=3) OR c==100 ORDER BY a;
  }
} {2 5 scan 0 sort 1}
do_test where7-1.12 {
  count_steps {
................................................................................
         OR ((a BETWEEN 31 AND 33) AND a!=32)
         OR (d>=94.0 AND d<95.0 AND d NOT NULL)
         OR 1000000<b
         OR (f GLOB '?pqrs*' AND f GLOB 'opqr*')
         OR (g='rqponml' AND f GLOB 'lmnop*')
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
  }
} {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 99 sort 0}
do_test where7-2.235.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE ((a BETWEEN 98 AND 100) AND a!=99)
         OR ((a BETWEEN 51 AND 53) AND a!=52)
         OR a=18
         OR ((a BETWEEN 31 AND 33) AND a!=32)
         OR (d>=94.0 AND d<95.0 AND d NOT NULL)
         OR 1000000<b
         OR (f GLOB '?pqrs*' AND f GLOB 'opqr*')
         OR (g='rqponml' AND f GLOB 'lmnop*')
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
  }
} {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 99 sort 0}
do_test where7-2.236.1 {
  count_steps_sort {
     SELECT a FROM t2
      WHERE b=1001
         OR b=168
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
         OR (d>=89.0 AND d<90.0 AND d NOT NULL)
................................................................................
         OR ((a BETWEEN 37 AND 39) AND a!=38)
         OR ((a BETWEEN 56 AND 58) AND a!=57)
         OR ((a BETWEEN 18 AND 20) AND a!=19)
         OR (d>=45.0 AND d<46.0 AND d NOT NULL)
         OR (f GLOB '?ghij*' AND f GLOB 'fghi*')
         OR ((a BETWEEN 53 AND 55) AND a!=54)
  }
} {5 7 18 20 23 25 31 33 37 39 45 53 54 55 56 57 58 59 72 74 83 85 95 scan 99 sort 0}
do_test where7-2.297.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE a=95
         OR ((a BETWEEN 72 AND 74) AND a!=73)
         OR ((a BETWEEN 23 AND 25) AND a!=24)
         OR b=594
................................................................................
         OR ((a BETWEEN 32 AND 34) AND a!=33)
         OR (f GLOB '?cdef*' AND f GLOB 'bcde*')
         OR b=300
         OR ((a BETWEEN 24 AND 26) AND a!=25)
         OR (d>=21.0 AND d<22.0 AND d NOT NULL)
         OR ((a BETWEEN 93 AND 95) AND a!=94)
  }
} {1 11 13 21 22 24 26 27 32 34 39 41 53 61 74 76 79 93 95 scan 99 sort 0}
do_test where7-2.385.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE (d>=61.0 AND d<62.0 AND d NOT NULL)
         OR ((a BETWEEN 11 AND 13) AND a!=12)
         OR ((a BETWEEN 74 AND 76) AND a!=75)
         OR ((a BETWEEN 39 AND 41) AND a!=40)







>




>







 







|













|







 







|







 







|







86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
....
5410
5411
5412
5413
5414
5415
5416
5417
5418
5419
5420
5421
5422
5423
5424
5425
5426
5427
5428
5429
5430
5431
5432
5433
5434
5435
5436
5437
5438
....
6852
6853
6854
6855
6856
6857
6858
6859
6860
6861
6862
6863
6864
6865
6866
....
8950
8951
8952
8953
8954
8955
8956
8957
8958
8959
8960
8961
8962
8963
8964
} {2 4 5 scan 0 sort 0}
do_test where7-1.9 {
  count_steps {
    SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4)
  }
} {2 4 5 scan 0 sort 0}
do_test where7-1.10 {
breakpoint
  count_steps {
    SELECT a FROM t1 WHERE (b=3 OR c>=10 OR c=4 OR b>10)
  }
} {2 4 5 scan 0 sort 0}
breakpoint
do_test where7-1.11 {
  count_steps {
    SELECT a FROM t1 WHERE (d=5 AND b=3) OR c==100 ORDER BY a;
  }
} {2 5 scan 0 sort 1}
do_test where7-1.12 {
  count_steps {
................................................................................
         OR ((a BETWEEN 31 AND 33) AND a!=32)
         OR (d>=94.0 AND d<95.0 AND d NOT NULL)
         OR 1000000<b
         OR (f GLOB '?pqrs*' AND f GLOB 'opqr*')
         OR (g='rqponml' AND f GLOB 'lmnop*')
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
  }
} {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 0 sort 0}
do_test where7-2.235.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE ((a BETWEEN 98 AND 100) AND a!=99)
         OR ((a BETWEEN 51 AND 53) AND a!=52)
         OR a=18
         OR ((a BETWEEN 31 AND 33) AND a!=32)
         OR (d>=94.0 AND d<95.0 AND d NOT NULL)
         OR 1000000<b
         OR (f GLOB '?pqrs*' AND f GLOB 'opqr*')
         OR (g='rqponml' AND f GLOB 'lmnop*')
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
  }
} {7 14 18 31 33 37 40 51 53 59 66 85 92 94 98 100 scan 0 sort 0}
do_test where7-2.236.1 {
  count_steps_sort {
     SELECT a FROM t2
      WHERE b=1001
         OR b=168
         OR (f GLOB '?ijkl*' AND f GLOB 'hijk*')
         OR (d>=89.0 AND d<90.0 AND d NOT NULL)
................................................................................
         OR ((a BETWEEN 37 AND 39) AND a!=38)
         OR ((a BETWEEN 56 AND 58) AND a!=57)
         OR ((a BETWEEN 18 AND 20) AND a!=19)
         OR (d>=45.0 AND d<46.0 AND d NOT NULL)
         OR (f GLOB '?ghij*' AND f GLOB 'fghi*')
         OR ((a BETWEEN 53 AND 55) AND a!=54)
  }
} {5 7 18 20 23 25 31 33 37 39 45 53 54 55 56 57 58 59 72 74 83 85 95 scan 0 sort 0}
do_test where7-2.297.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE a=95
         OR ((a BETWEEN 72 AND 74) AND a!=73)
         OR ((a BETWEEN 23 AND 25) AND a!=24)
         OR b=594
................................................................................
         OR ((a BETWEEN 32 AND 34) AND a!=33)
         OR (f GLOB '?cdef*' AND f GLOB 'bcde*')
         OR b=300
         OR ((a BETWEEN 24 AND 26) AND a!=25)
         OR (d>=21.0 AND d<22.0 AND d NOT NULL)
         OR ((a BETWEEN 93 AND 95) AND a!=94)
  }
} {1 11 13 21 22 24 26 27 32 34 39 41 53 61 74 76 79 93 95 scan 0 sort 0}
do_test where7-2.385.2 {
  count_steps_sort {
     SELECT a FROM t3
      WHERE (d>=61.0 AND d<62.0 AND d NOT NULL)
         OR ((a BETWEEN 11 AND 13) AND a!=12)
         OR ((a BETWEEN 74 AND 76) AND a!=75)
         OR ((a BETWEEN 39 AND 41) AND a!=40)