gitlab.com/CoiaPrant/sqlite3@v1.19.1/testdata/tcl/analyze9.test (about)

     1  # 2013 August 3
     2  #
     3  # The author disclaims copyright to this source code.  In place of
     4  # a legal notice, here is a blessing:
     5  #
     6  #    May you do good and not evil.
     7  #    May you find forgiveness for yourself and forgive others.
     8  #    May you share freely, never taking more than you give.
     9  #
    10  #***********************************************************************
    11  #
    12  # This file contains automated tests used to verify that the sqlite_stat4
    13  # functionality is working.
    14  #
    15  
    16  set testdir [file dirname $argv0]
    17  source $testdir/tester.tcl
    18  set testprefix analyze9
    19  
    20  ifcapable !stat4 {
    21    finish_test
    22    return
    23  }
    24  
    25  proc s {blob} {
    26    set ret ""
    27    binary scan $blob c* bytes
    28    foreach b $bytes {
    29      set t [binary format c $b]
    30      if {[string is print $t]} {
    31        append ret $t
    32      } else {
    33        append ret .
    34      }
    35    }
    36    return $ret
    37  }
    38  db function s s
    39  
    40  do_execsql_test 1.0 {
    41    CREATE TABLE t1(a TEXT, b TEXT); 
    42    INSERT INTO t1 VALUES('(0)', '(0)');
    43    INSERT INTO t1 VALUES('(1)', '(1)');
    44    INSERT INTO t1 VALUES('(2)', '(2)');
    45    INSERT INTO t1 VALUES('(3)', '(3)');
    46    INSERT INTO t1 VALUES('(4)', '(4)');
    47    CREATE INDEX i1 ON t1(a, b);
    48  } {}
    49  
    50  
    51  do_execsql_test 1.1 {
    52    ANALYZE;
    53  } {}
    54  
    55  do_execsql_test 1.2 {
    56    SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4;
    57  } {
    58    t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1}
    59    t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2}
    60    t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3}
    61    t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4}
    62    t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5}
    63  }
    64  
    65  if {[permutation] != "utf16"} {
    66    do_execsql_test 1.3 {
    67      SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4;
    68    } {
    69      t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0)
    70      t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1).
    71      t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2).
    72      t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3).
    73      t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4).
    74    }
    75  }
    76  
    77  
    78  #-------------------------------------------------------------------------
    79  # This is really just to test SQL user function "test_decode".
    80  #
    81  reset_db
    82  do_execsql_test 2.1 {
    83    CREATE TABLE t1(a, b, c);
    84    INSERT INTO t1 VALUES('some text', 14, NULL);
    85    INSERT INTO t1 VALUES(22.0, NULL, x'656667');
    86    CREATE INDEX i1 ON t1(a, b, c);
    87    ANALYZE;
    88    SELECT test_decode(sample) FROM sqlite_stat4;
    89  } {
    90    {22.0 NULL x'656667' 2} 
    91    {{some text} 14 NULL 1}
    92  }
    93  
    94  #-------------------------------------------------------------------------
    95  # 
    96  reset_db
    97  do_execsql_test 3.1 {
    98    CREATE TABLE t2(a, b);
    99    CREATE INDEX i2 ON t2(a, b);
   100    BEGIN;
   101  }
   102  
   103  do_test 3.2 {
   104    for {set i 0} {$i < 1000} {incr i} {
   105      set a [expr $i / 10]
   106      set b [expr int(rand() * 15.0)]
   107      execsql { INSERT INTO t2 VALUES($a, $b) }
   108    }
   109    execsql COMMIT
   110  } {}
   111  
   112  db func lindex lindex
   113  
   114  # Each value of "a" occurs exactly 10 times in the table.
   115  #
   116  do_execsql_test 3.3.1 {
   117    SELECT count(*) FROM t2 GROUP BY a;
   118  } [lrange [string repeat "10 " 100] 0 99]
   119  
   120  # The first element in the "nEq" list of all samples should therefore be 10.
   121  #
   122  do_execsql_test 3.3.2 {
   123    ANALYZE;
   124    SELECT lindex(nEq, 0) FROM sqlite_stat4;
   125  } [lrange [string repeat "10 " 100] 0 23]
   126  
   127  #-------------------------------------------------------------------------
   128  # 
   129  do_execsql_test 3.4 {
   130    DROP TABLE IF EXISTS t1;
   131    CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c);
   132    INSERT INTO t1 VALUES(1, 1, 'one-a');
   133    INSERT INTO t1 VALUES(11, 1, 'one-b');
   134    INSERT INTO t1 VALUES(21, 1, 'one-c');
   135    INSERT INTO t1 VALUES(31, 1, 'one-d');
   136    INSERT INTO t1 VALUES(41, 1, 'one-e');
   137    INSERT INTO t1 VALUES(51, 1, 'one-f');
   138    INSERT INTO t1 VALUES(61, 1, 'one-g');
   139    INSERT INTO t1 VALUES(71, 1, 'one-h');
   140    INSERT INTO t1 VALUES(81, 1, 'one-i');
   141    INSERT INTO t1 VALUES(91, 1, 'one-j');
   142    INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1;
   143    INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
   144    INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
   145    INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';
   146    INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*';	
   147    CREATE INDEX t1b ON t1(b);
   148    ANALYZE;
   149    SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60;
   150  } {three-d three-e three-f}
   151  
   152  
   153  #-------------------------------------------------------------------------
   154  # These tests verify that the sample selection for stat4 appears to be 
   155  # working as designed.
   156  #
   157  
   158  reset_db
   159  db func lindex lindex
   160  db func lrange lrange
   161  
   162  do_execsql_test 4.0 {
   163    DROP TABLE IF EXISTS t1;
   164    CREATE TABLE t1(a, b, c);
   165    CREATE INDEX i1 ON t1(c, b, a);
   166  }
   167  
   168  
   169  proc insert_filler_rows_n {iStart args} {
   170    set A(-ncopy) 1
   171    set A(-nval) 1
   172  
   173    foreach {k v} $args {
   174      if {[info exists A($k)]==0} { error "no such option: $k" }
   175      set A($k) $v
   176    }
   177    if {[llength $args] % 2} {
   178      error "option requires an argument: [lindex $args end]"
   179    }
   180  
   181    for {set i 0} {$i < $A(-nval)} {incr i} {
   182      set iVal [expr $iStart+$i]
   183      for {set j 0} {$j < $A(-ncopy)} {incr j} {
   184        execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) }
   185      }
   186    }
   187  }
   188  
   189  do_test 4.1 {
   190    execsql { BEGIN }
   191    insert_filler_rows_n  0  -ncopy 10 -nval 19
   192    insert_filler_rows_n 20  -ncopy  1 -nval 100
   193  
   194    execsql {
   195      INSERT INTO t1(c, b, a) VALUES(200, 1, 'a');
   196      INSERT INTO t1(c, b, a) VALUES(200, 1, 'b');
   197      INSERT INTO t1(c, b, a) VALUES(200, 1, 'c');
   198  
   199      INSERT INTO t1(c, b, a) VALUES(200, 2, 'e');
   200      INSERT INTO t1(c, b, a) VALUES(200, 2, 'f');
   201  
   202      INSERT INTO t1(c, b, a) VALUES(201, 3, 'g');
   203      INSERT INTO t1(c, b, a) VALUES(201, 4, 'h');
   204  
   205      ANALYZE;
   206      SELECT count(*) FROM sqlite_stat4;
   207      SELECT count(*) FROM t1;
   208    }
   209  } {24 297}
   210  
   211  do_execsql_test 4.2 {
   212    SELECT 
   213      neq,
   214      lrange(nlt, 0, 2),
   215      lrange(ndlt, 0, 2),
   216      lrange(test_decode(sample), 0, 2)
   217      FROM sqlite_stat4
   218    ORDER BY rowid LIMIT 16;
   219  } {
   220    {10 10 10 1} {0 0 0} {0 0 0} {0 0 0}
   221    {10 10 10 1} {10 10 10} {1 1 1} {1 1 1}
   222    {10 10 10 1} {20 20 20} {2 2 2} {2 2 2}
   223    {10 10 10 1} {30 30 30} {3 3 3} {3 3 3}
   224    {10 10 10 1} {40 40 40} {4 4 4} {4 4 4}
   225    {10 10 10 1} {50 50 50} {5 5 5} {5 5 5}
   226    {10 10 10 1} {60 60 60} {6 6 6} {6 6 6}
   227    {10 10 10 1} {70 70 70} {7 7 7} {7 7 7}
   228    {10 10 10 1} {80 80 80} {8 8 8} {8 8 8}
   229    {10 10 10 1} {90 90 90} {9 9 9} {9 9 9}
   230    {10 10 10 1} {100 100 100} {10 10 10} {10 10 10}
   231    {10 10 10 1} {110 110 110} {11 11 11} {11 11 11}
   232    {10 10 10 1} {120 120 120} {12 12 12} {12 12 12}
   233    {10 10 10 1} {130 130 130} {13 13 13} {13 13 13}
   234    {10 10 10 1} {140 140 140} {14 14 14} {14 14 14}
   235    {10 10 10 1} {150 150 150} {15 15 15} {15 15 15}
   236  }
   237  
   238  do_execsql_test 4.3 {
   239    SELECT 
   240      neq,
   241      lrange(nlt, 0, 2),
   242      lrange(ndlt, 0, 2),
   243      lrange(test_decode(sample), 0, 1)
   244      FROM sqlite_stat4
   245    ORDER BY rowid DESC LIMIT 2;
   246  } {
   247    {2 1 1 1} {295 296 296} {120 122 125} {201 4} 
   248    {5 3 1 1} {290 290 290} {119 119 119} {200 1}
   249  }
   250  
   251  do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120
   252  do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119
   253  
   254  # Check that the perioidic samples are present.
   255  do_execsql_test 4.6 {
   256    SELECT count(*) FROM sqlite_stat4
   257    WHERE lindex(test_decode(sample), 3) IN 
   258      ('34', '68', '102', '136', '170', '204', '238', '272')
   259  } {8}
   260  
   261  reset_db
   262  do_test 4.7 {
   263    execsql { 
   264      BEGIN;
   265      CREATE TABLE t1(o,t INTEGER PRIMARY KEY);
   266      CREATE INDEX i1 ON t1(o);
   267    }
   268    for {set i 0} {$i<10000} {incr i [expr (($i<1000)?1:10)]} {
   269      execsql { INSERT INTO t1 VALUES('x', $i) }
   270    }
   271    execsql {
   272      COMMIT;
   273      ANALYZE;
   274      SELECT count(*) FROM sqlite_stat4;
   275    }
   276  } {8}
   277  do_execsql_test 4.8 {
   278    SELECT test_decode(sample) FROM sqlite_stat4;
   279  } {
   280    {x 211} {x 423} {x 635} {x 847} 
   281    {x 1590} {x 3710} {x 5830} {x 7950}
   282  }
   283  
   284  
   285  #-------------------------------------------------------------------------
   286  # The following would cause a crash at one point.
   287  #
   288  reset_db
   289  do_execsql_test 5.1 {
   290    PRAGMA encoding = 'utf-16';
   291    CREATE TABLE t0(v);
   292    ANALYZE;
   293  }
   294  
   295  #-------------------------------------------------------------------------
   296  # This was also crashing (corrupt sqlite_stat4 table).
   297  #
   298  reset_db
   299  do_execsql_test 6.1 {
   300    CREATE TABLE t1(a, b);
   301    CREATE INDEX i1 ON t1(a);
   302    CREATE INDEX i2 ON t1(b);
   303    INSERT INTO t1 VALUES(1, 1);
   304    INSERT INTO t1 VALUES(2, 2);
   305    INSERT INTO t1 VALUES(3, 3);
   306    INSERT INTO t1 VALUES(4, 4);
   307    INSERT INTO t1 VALUES(5, 5);
   308    ANALYZE;
   309    PRAGMA writable_schema = 1;
   310    CREATE TEMP TABLE x1 AS
   311      SELECT tbl,idx,neq,nlt,ndlt,sample FROM sqlite_stat4
   312      ORDER BY (rowid%5), rowid;
   313    DELETE FROM sqlite_stat4;
   314    INSERT INTO sqlite_stat4 SELECT * FROM x1;
   315    PRAGMA writable_schema = 0;
   316    ANALYZE sqlite_master;
   317  }
   318  do_execsql_test 6.2 {
   319    SELECT * FROM t1 WHERE a = 'abc';
   320  }
   321  
   322  #-------------------------------------------------------------------------
   323  # The following tests experiment with adding corrupted records to the
   324  # 'sample' column of the sqlite_stat4 table.
   325  #
   326  reset_db
   327  sqlite3_db_config_lookaside db 0 0 0
   328  
   329  database_may_be_corrupt
   330  do_execsql_test 7.1 {
   331    CREATE TABLE t1(a, b);
   332    CREATE INDEX i1 ON t1(a, b);
   333    INSERT INTO t1 VALUES(1, 1);
   334    INSERT INTO t1 VALUES(2, 2);
   335    INSERT INTO t1 VALUES(3, 3);
   336    INSERT INTO t1 VALUES(4, 4);
   337    INSERT INTO t1 VALUES(5, 5);
   338    ANALYZE;
   339    UPDATE sqlite_stat4 SET sample = X'' WHERE rowid = 1;
   340    ANALYZE sqlite_master;
   341  }
   342  
   343  do_execsql_test 7.2 {
   344    UPDATE sqlite_stat4 SET sample = X'FFFF';
   345    ANALYZE sqlite_master;
   346    SELECT * FROM t1 WHERE a = 1;
   347  } {1 1}
   348  
   349  do_execsql_test 7.3 {
   350    ANALYZE;
   351    UPDATE sqlite_stat4 SET neq = '0 0 0';
   352    ANALYZE sqlite_master;
   353    SELECT * FROM t1 WHERE a = 1;
   354  } {1 1}
   355  
   356  do_execsql_test 7.4 {
   357    ANALYZE;
   358    UPDATE sqlite_stat4 SET ndlt = '0 0 0';
   359    ANALYZE sqlite_master;
   360    SELECT * FROM t1 WHERE a = 3;
   361  } {3 3}
   362  
   363  do_execsql_test 7.5 {
   364    ANALYZE;
   365    UPDATE sqlite_stat4 SET nlt = '0 0 0';
   366    ANALYZE sqlite_master;
   367    SELECT * FROM t1 WHERE a = 5;
   368  } {5 5}
   369  
   370  database_never_corrupt
   371  
   372  #-------------------------------------------------------------------------
   373  #
   374  reset_db
   375  do_execsql_test 8.1 {
   376    CREATE TABLE t1(x TEXT);
   377    CREATE INDEX i1 ON t1(x);
   378    INSERT INTO t1 VALUES('1');
   379    INSERT INTO t1 VALUES('2');
   380    INSERT INTO t1 VALUES('3');
   381    INSERT INTO t1 VALUES('4');
   382    ANALYZE;
   383  }
   384  do_execsql_test 8.2 {
   385    SELECT * FROM t1 WHERE x = 3;
   386  } {3}
   387  
   388  #-------------------------------------------------------------------------
   389  # Check that the bug fixed by [91733bc485] really is fixed.
   390  #
   391  reset_db
   392  do_execsql_test 9.1 {
   393    CREATE TABLE t1(a, b, c, d, e);
   394    CREATE INDEX i1 ON t1(a, b, c, d);
   395    CREATE INDEX i2 ON t1(e);
   396  }
   397  do_test 9.2 {
   398    execsql BEGIN;
   399    for {set i 0} {$i < 100} {incr i} {
   400      execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
   401    }
   402    for {set i 0} {$i < 21} {incr i} {
   403      execsql "INSERT INTO t1 VALUES('x', 'y', 'z', 101, $i)"
   404    }
   405    for {set i 102} {$i < 200} {incr i} {
   406      execsql "INSERT INTO t1 VALUES('x', 'y', 'z', $i, [expr $i/2])"
   407    }
   408    execsql COMMIT
   409    execsql ANALYZE
   410  } {}
   411  
   412  do_eqp_test 9.3.1 {
   413    SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=101 AND e=5;
   414  } {/t1 USING INDEX i2/}
   415  do_eqp_test 9.3.2 {
   416    SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=99 AND e=5;
   417  } {/t1 USING INDEX i1/}
   418  
   419  set value_d [expr 101]
   420  do_eqp_test 9.4.1 {
   421    SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
   422  } {/t1 USING INDEX i2/}
   423  set value_d [expr 99]
   424  do_eqp_test 9.4.2 {
   425    SELECT * FROM t1 WHERE a='x' AND b='y' AND c='z' AND d=$value_d AND e=5
   426  } {/t1 USING INDEX i1/}
   427  
   428  #-------------------------------------------------------------------------
   429  # Check that the planner takes stat4 data into account when considering
   430  # "IS NULL" and "IS NOT NULL" constraints.
   431  #
   432  do_execsql_test 10.1.1 {
   433    DROP TABLE IF EXISTS t3;
   434    CREATE TABLE t3(a, b);
   435    CREATE INDEX t3a ON t3(a);
   436    CREATE INDEX t3b ON t3(b);
   437  }
   438  do_test 10.1.2 {
   439    for {set i 1} {$i < 100} {incr i} {
   440      if {$i>90} { set a $i } else { set a NULL }
   441      set b [expr $i % 5]
   442      execsql "INSERT INTO t3 VALUES($a, $b)"
   443    }
   444    execsql ANALYZE
   445  } {}
   446  do_eqp_test 10.1.3 {
   447    SELECT * FROM t3 WHERE a IS NULL AND b = 2
   448  } {/t3 USING INDEX t3b/}
   449  do_eqp_test 10.1.4 {
   450    SELECT * FROM t3 WHERE a IS NOT NULL AND b = 2
   451  } {/t3 USING INDEX t3a/}
   452  
   453  do_execsql_test 10.2.1 {
   454    DROP TABLE IF EXISTS t3;
   455    CREATE TABLE t3(x, a, b);
   456    CREATE INDEX t3a ON t3(x, a);
   457    CREATE INDEX t3b ON t3(x, b);
   458  }
   459  do_test 10.2.2 {
   460    for {set i 1} {$i < 100} {incr i} {
   461      if {$i>90} { set a $i } else { set a NULL }
   462      set b [expr $i % 5]
   463      execsql "INSERT INTO t3 VALUES('xyz', $a, $b)"
   464    }
   465    execsql ANALYZE
   466  } {}
   467  do_eqp_test 10.2.3 {
   468    SELECT * FROM t3 WHERE x = 'xyz' AND a IS NULL AND b = 2
   469  } {/t3 USING INDEX t3b/}
   470  do_eqp_test 10.2.4 {
   471    SELECT * FROM t3 WHERE x = 'xyz' AND a IS NOT NULL AND b = 2
   472  } {/t3 USING INDEX t3a/}
   473  
   474  #-------------------------------------------------------------------------
   475  # Check that stat4 data is used correctly with non-default collation
   476  # sequences.
   477  #
   478  foreach {tn schema} {
   479    1 {
   480      CREATE TABLE t4(a COLLATE nocase, b);
   481      CREATE INDEX t4a ON t4(a);
   482      CREATE INDEX t4b ON t4(b);
   483    }
   484    2 {
   485      CREATE TABLE t4(a, b);
   486      CREATE INDEX t4a ON t4(a COLLATE nocase);
   487      CREATE INDEX t4b ON t4(b);
   488    }
   489  } {
   490    drop_all_tables
   491    do_test 11.$tn.1 { execsql $schema } {}
   492  
   493    do_test 11.$tn.2 {
   494      for {set i 0} {$i < 100} {incr i} {
   495        if { ($i % 10)==0 } { set a ABC } else { set a DEF }
   496        set b [expr $i % 5]
   497          execsql { INSERT INTO t4 VALUES($a, $b) }
   498      }
   499      execsql ANALYZE
   500    } {}
   501  
   502    do_eqp_test 11.$tn.3 {
   503      SELECT * FROM t4 WHERE a = 'def' AND b = 3;
   504    } {/t4 USING INDEX t4b/}
   505  
   506    if {$tn==1} {
   507      set sql "SELECT * FROM t4 WHERE a = 'abc' AND b = 3;"
   508      do_eqp_test 11.$tn.4 $sql {/t4 USING INDEX t4a/}
   509    } else {
   510  
   511      set sql "SELECT * FROM t4 WHERE a = 'abc' COLLATE nocase AND b = 3;"
   512      do_eqp_test 11.$tn.5 $sql {/t4 USING INDEX t4a/}
   513  
   514      set sql "SELECT * FROM t4 WHERE a COLLATE nocase = 'abc' AND b = 3;"
   515      do_eqp_test 11.$tn.6 $sql {/t4 USING INDEX t4a/}
   516    }
   517  }
   518  
   519  foreach {tn schema} {
   520    1 {
   521      CREATE TABLE t4(x, a COLLATE nocase, b);
   522      CREATE INDEX t4a ON t4(x, a);
   523      CREATE INDEX t4b ON t4(x, b);
   524    }
   525    2 {
   526      CREATE TABLE t4(x, a, b);
   527      CREATE INDEX t4a ON t4(x, a COLLATE nocase);
   528      CREATE INDEX t4b ON t4(x, b);
   529    }
   530  } {
   531    drop_all_tables
   532    do_test 12.$tn.1 { execsql $schema } {}
   533  
   534    do_test 12.$tn.2 {
   535      for {set i 0} {$i < 100} {incr i} {
   536        if { ($i % 10)==0 } { set a ABC } else { set a DEF }
   537        set b [expr $i % 5]
   538          execsql { INSERT INTO t4 VALUES(X'abcdef', $a, $b) }
   539      }
   540      execsql ANALYZE
   541    } {}
   542  
   543    do_eqp_test 12.$tn.3 {
   544      SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'def' AND b = 3;
   545    } {/t4 USING INDEX t4b/}
   546  
   547    if {$tn==1} {
   548      set sql "SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' AND b = 3;"
   549      do_eqp_test 12.$tn.4 $sql {/t4 USING INDEX t4a/}
   550    } else {
   551      set sql {
   552        SELECT * FROM t4 WHERE x=X'abcdef' AND a = 'abc' COLLATE nocase AND b = 3
   553      }
   554      do_eqp_test 12.$tn.5 $sql {/t4 USING INDEX t4a/}
   555      set sql {
   556        SELECT * FROM t4 WHERE x=X'abcdef' AND a COLLATE nocase = 'abc' AND b = 3
   557      }
   558      do_eqp_test 12.$tn.6 $sql {/t4 USING INDEX t4a/}
   559    }
   560  }
   561  
   562  #-------------------------------------------------------------------------
   563  # Check that affinities are taken into account when using stat4 data to
   564  # estimate the number of rows scanned by a rowid constraint.
   565  #
   566  drop_all_tables
   567  do_test 13.1 {
   568    execsql {
   569      CREATE TABLE t1(a, b, c, d);
   570      CREATE INDEX i1 ON t1(a);
   571      CREATE INDEX i2 ON t1(b, c);
   572    }
   573    for {set i 0} {$i<100} {incr i} {
   574      if {$i %2} {set a abc} else {set a def}
   575      execsql { INSERT INTO t1(rowid, a, b, c) VALUES($i, $a, $i, $i) }
   576    }
   577    execsql ANALYZE
   578  } {}
   579  do_eqp_test 13.2.1 {
   580    SELECT * FROM t1 WHERE a='abc' AND rowid<15 AND b<12
   581  } {/SEARCH t1 USING INDEX i1/}
   582  do_eqp_test 13.2.2 {
   583    SELECT * FROM t1 WHERE a='abc' AND rowid<'15' AND b<12
   584  } {/SEARCH t1 USING INDEX i1/}
   585  do_eqp_test 13.3.1 {
   586    SELECT * FROM t1 WHERE a='abc' AND rowid<100 AND b<12
   587  } {/SEARCH t1 USING INDEX i2/}
   588  do_eqp_test 13.3.2 {
   589    SELECT * FROM t1 WHERE a='abc' AND rowid<'100' AND b<12
   590  } {/SEARCH t1 USING INDEX i2/}
   591  
   592  #-------------------------------------------------------------------------
   593  # Check also that affinities are taken into account when using stat4 data 
   594  # to estimate the number of rows scanned by any other constraint on a 
   595  # column other than the leftmost.
   596  #
   597  drop_all_tables
   598  do_test 14.1 {
   599    execsql { CREATE TABLE t1(a, b INTEGER, c) }
   600    for {set i 0} {$i<100} {incr i} {
   601      set c [expr $i % 3]
   602      execsql { INSERT INTO t1 VALUES('ott', $i, $c) }
   603    }
   604    execsql {
   605      CREATE INDEX i1 ON t1(a, b);
   606      CREATE INDEX i2 ON t1(c);
   607      ANALYZE;
   608    }
   609  } {}
   610  do_eqp_test 13.2.1 {
   611    SELECT * FROM t1 WHERE a='ott' AND b<10 AND c=1
   612  } {/SEARCH t1 USING INDEX i1/}
   613  do_eqp_test 13.2.2 {
   614    SELECT * FROM t1 WHERE a='ott' AND b<'10' AND c=1
   615  } {/SEARCH t1 USING INDEX i1/}
   616  
   617  #-------------------------------------------------------------------------
   618  # By default, 16 non-periodic samples are collected for the stat4 table.
   619  # The following tests attempt to verify that the most common keys are
   620  # being collected.
   621  #
   622  proc check_stat4 {tn} {
   623    db eval ANALYZE
   624    db eval {SELECT a, b, c, d FROM t1} {
   625      incr k($a)
   626      incr k([list $a $b])
   627      incr k([list $a $b $c])
   628      if { [info exists k([list $a $b $c $d])]==0 } { incr nRow }
   629      incr k([list $a $b $c $d])
   630    }
   631  
   632    set L [list]
   633    foreach key [array names k] {
   634      lappend L [list $k($key) $key]
   635    }
   636  
   637    set nSample $nRow
   638    if {$nSample>16} {set nSample 16}
   639  
   640    set nThreshold [lindex [lsort -decr -integer -index 0 $L] [expr $nSample-1] 0]
   641    foreach key [array names k] {
   642      if {$k($key)>$nThreshold} {
   643        set expect($key) 1
   644      }
   645      if {$k($key)==$nThreshold} {
   646        set possible($key) 1
   647      }
   648    }
   649  
   650  
   651    set nPossible [expr $nSample - [llength [array names expect]]]
   652  
   653    #puts "EXPECT: [array names expect]"
   654    #puts "POSSIBLE($nPossible/[array size possible]): [array names possible]"
   655    #puts "HAVE: [db eval {SELECT test_decode(sample) FROM sqlite_stat4 WHERE idx='i1'}]"
   656  
   657    db eval {SELECT test_decode(sample) AS s FROM sqlite_stat4 WHERE idx='i1'} {
   658      set seen 0
   659      for {set i 0} {$i<4} {incr i} {
   660        unset -nocomplain expect([lrange $s 0 $i])
   661        if {[info exists possible([lrange $s 0 $i])]} {
   662          set seen 1
   663          unset -nocomplain possible([lrange $s 0 $i])
   664        }
   665      }
   666      if {$seen} {incr nPossible -1}
   667    }
   668    if {$nPossible<0} {set nPossible 0}
   669  
   670    set res [list [llength [array names expect]] $nPossible]
   671    uplevel [list do_test $tn [list set {} $res] {0 0}]
   672  }
   673  
   674  drop_all_tables
   675  do_test 14.1.1 {
   676    execsql {
   677      CREATE TABLE t1(a,b,c,d);
   678      CREATE INDEX i1 ON t1(a,b,c,d);
   679    }
   680    for {set i 0} {$i < 160} {incr i} {
   681      execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) }
   682      if {($i % 10)==0} { execsql { INSERT INTO t1 VALUES($i,$i,$i,$i) } }
   683    }
   684  } {}
   685  check_stat4 14.1.2
   686  
   687  do_test 14.2.1 {
   688    execsql { DELETE FROM t1 }
   689    for {set i 0} {$i < 1600} {incr i} {
   690      execsql { INSERT INTO t1 VALUES($i/10,$i/17,$i/27,$i/37) }
   691    }
   692  } {}
   693  check_stat4 14.2.2
   694  
   695  do_test 14.3.1 {
   696    for {set i 0} {$i < 10} {incr i} {
   697      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   698      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   699      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   700      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   701      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   702      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   703      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   704      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   705      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   706      execsql { INSERT INTO t1 VALUES($i*50,$i*50,$i*50,$i*50) }
   707    }
   708  } {}
   709  check_stat4 14.3.2
   710  
   711  do_test 14.4.1 {
   712    execsql {DELETE FROM t1}
   713    for {set i 1} {$i < 160} {incr i} {
   714      set b [expr $i % 10]
   715      if {$b==0 || $b==2} {set b 1}
   716      execsql { INSERT INTO t1 VALUES($i/10,$b,$i,$i) }
   717    }
   718  } {}
   719  check_stat4 14.4.2
   720  db func lrange lrange
   721  db func lindex lindex
   722  do_execsql_test 14.4.3 {
   723    SELECT lrange(test_decode(sample), 0, 1) AS s FROM sqlite_stat4
   724    WHERE lindex(s, 1)=='1' ORDER BY rowid
   725  } {
   726    {0 1} {1 1} {2 1} {3 1} 
   727    {4 1} {5 1} {6 1} {7 1} 
   728    {8 1} {9 1} {10 1} {11 1} 
   729    {12 1} {13 1} {14 1} {15 1}
   730  }
   731  
   732  #-------------------------------------------------------------------------
   733  # Test that nothing untoward happens if the stat4 table contains entries
   734  # for indexes that do not exist. Or NULL values in the idx column.
   735  # Or NULL values in any of the other columns.
   736  #
   737  drop_all_tables
   738  do_execsql_test 15.1 {
   739    CREATE TABLE x1(a, b, UNIQUE(a, b));
   740    INSERT INTO x1 VALUES(1, 2);
   741    INSERT INTO x1 VALUES(3, 4);
   742    INSERT INTO x1 VALUES(5, 6);
   743    ANALYZE;
   744    INSERT INTO sqlite_stat4 VALUES(NULL, NULL, NULL, NULL, NULL, NULL);
   745  }
   746  db close
   747  sqlite3 db test.db
   748  do_execsql_test 15.2 { SELECT * FROM x1 } {1 2 3 4 5 6}
   749  
   750  do_execsql_test 15.3 {
   751    INSERT INTO sqlite_stat4 VALUES(42, 42, 42, 42, 42, 42);
   752  }
   753  db close
   754  sqlite3 db test.db
   755  do_execsql_test 15.4 { SELECT * FROM x1 } {1 2 3 4 5 6}
   756  
   757  do_execsql_test 15.5 {
   758    UPDATE sqlite_stat1 SET stat = NULL;
   759  }
   760  db close
   761  sqlite3 db test.db
   762  do_execsql_test 15.6 { SELECT * FROM x1 } {1 2 3 4 5 6}
   763  
   764  do_execsql_test 15.7 {
   765    ANALYZE;
   766    UPDATE sqlite_stat1 SET tbl = 'no such tbl';
   767  }
   768  db close
   769  sqlite3 db test.db
   770  do_execsql_test 15.8 { SELECT * FROM x1 } {1 2 3 4 5 6}
   771  
   772  do_execsql_test 15.9 {
   773    ANALYZE;
   774    UPDATE sqlite_stat4 SET neq = NULL, nlt=NULL, ndlt=NULL;
   775  }
   776  db close
   777  sqlite3 db test.db
   778  do_execsql_test 15.10 { SELECT * FROM x1 } {1 2 3 4 5 6}
   779  
   780  # This is just for coverage....
   781  do_execsql_test 15.11 {
   782    ANALYZE;
   783    UPDATE sqlite_stat1 SET stat = stat || ' unordered';
   784  }
   785  db close
   786  sqlite3 db test.db
   787  do_execsql_test 15.12 { SELECT * FROM x1 } {1 2 3 4 5 6}
   788  
   789  #-------------------------------------------------------------------------
   790  # Test that allocations used for sqlite_stat4 samples are included in
   791  # the quantity returned by SQLITE_DBSTATUS_SCHEMA_USED.
   792  #
   793  set one [string repeat x 1000]
   794  set two [string repeat x 2000]
   795  do_test 16.1 {
   796    reset_db
   797    execsql {
   798      CREATE TABLE t1(a, UNIQUE(a));
   799      INSERT INTO t1 VALUES($one);
   800      ANALYZE;
   801    }
   802    set nByte [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
   803  
   804    reset_db
   805    execsql {
   806      CREATE TABLE t1(a, UNIQUE(a));
   807      INSERT INTO t1 VALUES($two);
   808      ANALYZE;
   809    }
   810    set nByte2 [lindex [sqlite3_db_status db SCHEMA_USED 0] 1]
   811    puts -nonewline " (nByte=$nByte nByte2=$nByte2)"
   812  
   813    expr {$nByte2 > $nByte+900 && $nByte2 < $nByte+1100}
   814  } {1}
   815  
   816  #-------------------------------------------------------------------------
   817  # Test that stat4 data may be used with partial indexes.
   818  #
   819  do_test 17.1 {
   820    reset_db
   821    execsql {
   822      CREATE TABLE t1(a, b, c, d);
   823      CREATE INDEX i1 ON t1(a, b) WHERE d IS NOT NULL;
   824      INSERT INTO t1 VALUES(-1, -1, -1, NULL);
   825      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   826      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   827      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   828      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   829      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   830      INSERT INTO t1 SELECT 2*a,2*b,2*c,d FROM t1;
   831    }
   832  
   833    for {set i 0} {$i < 32} {incr i} {
   834      if {$i<8} {set b 0} else { set b $i }
   835      execsql { INSERT INTO t1 VALUES($i%2, $b, $i/2, 'abc') }
   836    }
   837    execsql {ANALYZE main.t1}
   838  } {}
   839  
   840  do_catchsql_test 17.1.2 {
   841    ANALYZE temp.t1;
   842  } {1 {no such table: temp.t1}}
   843  
   844  do_eqp_test 17.2 {
   845    SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
   846  } {/USING INDEX i1/}
   847  do_eqp_test 17.3 {
   848    SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
   849  } {/USING INDEX i1/}
   850  
   851  do_execsql_test 17.4 {
   852    CREATE INDEX i2 ON t1(c, d);
   853    ANALYZE main.i2;
   854  }
   855  do_eqp_test 17.5 {
   856    SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=10 AND c=10;
   857  } {/USING INDEX i1/}
   858  do_eqp_test 17.6 {
   859    SELECT * FROM t1 WHERE d IS NOT NULL AND a=0 AND b=0 AND c=10;
   860  } {/USING INDEX i2/}
   861  
   862  #-------------------------------------------------------------------------
   863  #
   864  do_test 18.1 {
   865    reset_db
   866    execsql {
   867      CREATE TABLE t1(a, b);
   868      CREATE INDEX i1 ON t1(a, b);
   869    }
   870    for {set i 0} {$i < 9} {incr i} {
   871      execsql {
   872        INSERT INTO t1 VALUES($i, 0);
   873        INSERT INTO t1 VALUES($i, 0);
   874        INSERT INTO t1 VALUES($i, 0);
   875        INSERT INTO t1 VALUES($i, 0);
   876        INSERT INTO t1 VALUES($i, 0);
   877        INSERT INTO t1 VALUES($i, 0);
   878        INSERT INTO t1 VALUES($i, 0);
   879        INSERT INTO t1 VALUES($i, 0);
   880        INSERT INTO t1 VALUES($i, 0);
   881        INSERT INTO t1 VALUES($i, 0);
   882        INSERT INTO t1 VALUES($i, 0);
   883        INSERT INTO t1 VALUES($i, 0);
   884        INSERT INTO t1 VALUES($i, 0);
   885        INSERT INTO t1 VALUES($i, 0);
   886        INSERT INTO t1 VALUES($i, 0);
   887      }
   888    }
   889    execsql ANALYZE
   890    execsql { SELECT count(*) FROM sqlite_stat4 }
   891  } {9}
   892  
   893  #-------------------------------------------------------------------------
   894  # For coverage.
   895  #
   896  ifcapable view {
   897    do_test 19.1 {
   898      reset_db 
   899      execsql {
   900        CREATE TABLE t1(x, y);
   901        CREATE INDEX i1 ON t1(x, y);
   902        CREATE VIEW v1 AS SELECT * FROM t1;
   903        ANALYZE;
   904      }
   905    } {}
   906  }
   907  ifcapable auth {
   908    proc authproc {op args} {
   909      if {$op == "SQLITE_ANALYZE"} { return "SQLITE_DENY" }
   910      return "SQLITE_OK"
   911    }
   912    do_test 19.2 {
   913      reset_db 
   914      db auth authproc
   915      execsql {
   916        CREATE TABLE t1(x, y);
   917        CREATE VIEW v1 AS SELECT * FROM t1;
   918      }
   919      catchsql ANALYZE
   920    } {1 {not authorized}}
   921  }
   922  
   923  #-------------------------------------------------------------------------
   924  #
   925  reset_db
   926  proc r {args} { expr rand() }
   927  db func r r
   928  db func lrange lrange
   929  do_test 20.1 {
   930    execsql {
   931      CREATE TABLE t1(a,b,c,d);
   932      CREATE INDEX i1 ON t1(a,b,c,d);
   933    }
   934    for {set i 0} {$i < 16} {incr i} {
   935      execsql {
   936        INSERT INTO t1 VALUES($i, r(), r(), r());
   937        INSERT INTO t1 VALUES($i, $i,  r(), r());
   938        INSERT INTO t1 VALUES($i, $i,  $i,  r());
   939        INSERT INTO t1 VALUES($i, $i,  $i,  $i);
   940        INSERT INTO t1 VALUES($i, $i,  $i,  $i);
   941        INSERT INTO t1 VALUES($i, $i,  $i,  r());
   942        INSERT INTO t1 VALUES($i, $i,  r(), r());
   943        INSERT INTO t1 VALUES($i, r(), r(), r());
   944      }
   945    }
   946  } {}
   947  do_execsql_test 20.2 { ANALYZE }
   948  for {set i 0} {$i<16} {incr i} {
   949      set val "$i $i $i $i"
   950      do_execsql_test 20.3.$i {
   951        SELECT count(*) FROM sqlite_stat4 
   952        WHERE lrange(test_decode(sample), 0, 3)=$val
   953      } {1}
   954  }
   955  
   956  #-------------------------------------------------------------------------
   957  #
   958  reset_db
   959  
   960  do_execsql_test 21.0 {
   961    CREATE TABLE t2(a, b);
   962    CREATE INDEX i2 ON t2(a);
   963  }
   964  
   965  do_test 21.1 {
   966    for {set i 1} {$i < 100} {incr i} {
   967      execsql { 
   968        INSERT INTO t2 VALUES(CASE WHEN $i < 80 THEN 'one' ELSE 'two' END, $i) 
   969      }
   970    }
   971    execsql ANALYZE
   972  } {}
   973  
   974  # Condition (a='one') matches 80% of the table. (rowid<10) reduces this to
   975  # 10%, but (rowid<50) only reduces it to 50%. So in the first case below
   976  # the index is used. In the second, it is not. 
   977  #
   978  do_eqp_test 21.2 {
   979    SELECT * FROM t2 WHERE a='one' AND rowid < 10
   980  } {/*USING INDEX i2 (a=? AND rowid<?)*/}
   981  do_eqp_test 21.3 {
   982    SELECT * FROM t2 WHERE a='one' AND rowid < 50
   983  } {/*USING INTEGER PRIMARY KEY*/}
   984  
   985  #-------------------------------------------------------------------------
   986  #
   987  reset_db
   988  do_execsql_test 22.0 {
   989    CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID;
   990    SELECT * FROM t3;
   991  } {}
   992  do_execsql_test 22.1 {
   993    WITH r(x) AS (
   994      SELECT 1
   995      UNION ALL
   996      SELECT x+1 FROM r WHERE x<=100
   997    )
   998  
   999    INSERT INTO t3 SELECT
  1000      CASE WHEN (x>45 AND x<96) THEN 'B' ELSE 'A' END,  /* Column "a" */
  1001      x,                                                /* Column "b" */
  1002      CASE WHEN (x<51) THEN 'one' ELSE 'two' END,       /* Column "c" */
  1003      x                                                 /* Column "d" */
  1004    FROM r;
  1005  
  1006    CREATE INDEX i3 ON t3(c);
  1007    CREATE INDEX i4 ON t3(d);
  1008    ANALYZE;
  1009  }
  1010  
  1011  # Expression (c='one' AND a='B') matches 5 table rows. But (c='one' AND a=A')
  1012  # matches 45. Expression (d<?) matches 20. Neither index is a covering index.
  1013  #
  1014  # Therefore, with stat4 data, SQLite prefers (c='one' AND a='B') over (d<20),
  1015  # and (d<20) over (c='one' AND a='A').
  1016  foreach {tn where res} {
  1017    1 "c='one' AND a='B' AND d < 20"   {/*INDEX i3 (c=? AND a=?)*/}
  1018    2 "c='one' AND a='A' AND d < 20"   {/*INDEX i4 (d<?)*/}
  1019  } {
  1020    do_eqp_test 22.2.$tn "SELECT * FROM t3 WHERE $where" $res
  1021  }
  1022  
  1023  proc int_to_char {i} {
  1024    set ret ""
  1025    set char [list a b c d e f g h i j]
  1026    foreach {div} {1000 100 10 1} {
  1027      append ret [lindex $char [expr ($i / $div) % 10]]
  1028    }
  1029    set ret
  1030  }
  1031  db func int_to_char int_to_char
  1032  
  1033  do_execsql_test 23.0 {
  1034    CREATE TABLE t4(
  1035      a COLLATE nocase, b, c, 
  1036      d, e, f, 
  1037      PRIMARY KEY(c, b, a)
  1038    ) WITHOUT ROWID;
  1039    CREATE INDEX i41 ON t4(e);
  1040    CREATE INDEX i42 ON t4(f);
  1041  
  1042    WITH data(a, b, c, d, e, f) AS (
  1043      SELECT int_to_char(0), 'xyz', 'zyx', '*', 0, 0
  1044      UNION ALL
  1045      SELECT 
  1046        int_to_char(f+1), b, c, d, (e+1) % 2, f+1
  1047      FROM data WHERE f<1024
  1048    )
  1049    INSERT INTO t4 SELECT a, b, c, d, e, f FROM data;
  1050    ANALYZE;
  1051  } {}
  1052  
  1053  do_eqp_test 23.1 {
  1054    SELECT * FROM t4 WHERE 
  1055      (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300
  1056    -- Formerly used index i41.  But i41 is not a covering index whereas
  1057    -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the
  1058    -- PRIMARY KEY is preferred.
  1059  } {SEARCH t4 USING PRIMARY KEY (c=? AND b=? AND a<?)}
  1060  do_eqp_test 23.2 {
  1061    SELECT * FROM t4 WHERE 
  1062      (e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300
  1063  } {SEARCH t4 USING INDEX i42 (f<?)}
  1064  
  1065  do_execsql_test 24.0 {
  1066    CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID;
  1067    WITH data(a, b, c, d, e) AS (
  1068      SELECT 'z', 'y', 0, 0, 0
  1069      UNION ALL
  1070      SELECT 
  1071        a, CASE WHEN b='y' THEN 'n' ELSE 'y' END, c+1, e/250, e+1 
  1072      FROM data
  1073      WHERE e<1000
  1074    )
  1075    INSERT INTO t5(a, b, c, d, e) SELECT * FROM data;
  1076    CREATE INDEX t5d ON t5(d);
  1077    CREATE INDEX t5e ON t5(e);
  1078    ANALYZE;
  1079  }
  1080  
  1081  foreach {tn where eqp} {
  1082    1 "d=0 AND a='z' AND b='n' AND e<200" {/*t5d (d=? AND a=? AND b=?)*/}
  1083    2 "d=0 AND a='z' AND b='n' AND e<100" {/*t5e (e<?)*/}
  1084  
  1085    3 "d=0 AND e<300"                     {/*t5d (d=?)*/}
  1086    4 "d=0 AND e<200"                     {/*t5e (e<?)*/}
  1087  } {
  1088    do_eqp_test 24.$tn "SeLeCt * FROM t5 WHERE $where" $eqp
  1089  }
  1090  
  1091  #-------------------------------------------------------------------------
  1092  # Test that if stat4 data is available but cannot be used because the
  1093  # rhs of a range constraint is a complex expression, the default estimates
  1094  # are used instead.
  1095  ifcapable stat4&&cte {
  1096    do_execsql_test 25.1 {
  1097      CREATE TABLE t6(a, b);
  1098      WITH ints(i,j) AS (
  1099        SELECT 1,1 UNION ALL SELECT i+1,j+1 FROM ints WHERE i<100
  1100      ) INSERT INTO t6 SELECT * FROM ints;
  1101      CREATE INDEX aa ON t6(a);
  1102      CREATE INDEX bb ON t6(b);
  1103      ANALYZE;
  1104    }
  1105  
  1106    # Term (b<?) is estimated at 25%. Better than (a<30) but not as
  1107    # good as (a<20).
  1108    do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \
  1109      {SEARCH t6 USING INDEX bb (b<?)}
  1110    do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \
  1111      {SEARCH t6 USING INDEX aa (a<?)}
  1112  
  1113    # Term (b BETWEEN ? AND ?) is estimated at 1/64.
  1114    do_eqp_test 25.3.1 { 
  1115      SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ? 
  1116    } {SEARCH t6 USING INDEX bb (b>? AND b<?)}
  1117    
  1118    # Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows -
  1119    # 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than
  1120    # (a<20) but not as good as (a<10).
  1121    do_eqp_test 25.4.1 { 
  1122      SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60)
  1123    } {SEARCH t6 USING INDEX aa (a<?)}
  1124  
  1125    do_eqp_test 25.4.2 { 
  1126      SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60)
  1127    } {SEARCH t6 USING INDEX bb (b>? AND b<?)}
  1128  }
  1129  
  1130  #-------------------------------------------------------------------------
  1131  # Check that a problem in they way stat4 data is used has been 
  1132  # resolved (see below).
  1133  #
  1134  reset_db
  1135  do_test 26.1.1 {
  1136    db transaction {
  1137      execsql { 
  1138        CREATE TABLE t1(x, y, z);
  1139        CREATE INDEX t1xy ON t1(x, y);
  1140        CREATE INDEX t1z ON t1(z);
  1141      }
  1142      for {set i 0} {$i < 10000} {incr i} {
  1143        execsql { INSERT INTO t1(x, y) VALUES($i, $i) }
  1144      }
  1145      for {set i 0} {$i < 10} {incr i} {
  1146        execsql {
  1147          WITH cnt(x) AS (SELECT 1 UNION ALL SELECT x+1 FROM cnt WHERE x<100)
  1148          INSERT INTO t1(x, y) SELECT 10000+$i, x FROM cnt;
  1149          INSERT INTO t1(x, y) SELECT 10000+$i, 100;
  1150        }
  1151      }
  1152      execsql {
  1153        UPDATE t1 SET z = rowid / 20;
  1154        ANALYZE;
  1155      }
  1156    }
  1157  } {}
  1158  
  1159  do_execsql_test 26.1.2 {
  1160    SELECT count(*) FROM t1 WHERE x = 10000 AND y < 50;
  1161  } {49}
  1162  do_execsql_test 26.1.3 {
  1163    SELECT count(*) FROM t1 WHERE z = 444;
  1164  } {20}
  1165  
  1166  # The analyzer knows that any (z=?) expression matches 20 rows. So it
  1167  # will use index "t1z" if the estimate of hits for (x=10000 AND y<50)
  1168  # is greater than 20 rows.
  1169  #
  1170  # And it should be. The analyzer has a stat4 sample as follows:
  1171  #
  1172  #   sample=(x=10000, y=100) nLt=(10000 10099)
  1173  #
  1174  # There should be no other samples that start with (x=10000). So it knows 
  1175  # that (x=10000 AND y<50) must match somewhere between 0 and 99 rows, but
  1176  # no more than that. Guessing less than 20 is therefore unreasonable.
  1177  #
  1178  # At one point though, due to a problem in whereKeyStats(), the planner was
  1179  # estimating that (x=10000 AND y<50) would match only 2 rows.
  1180  #
  1181  do_eqp_test 26.1.4 {
  1182    SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444;
  1183  } {SEARCH t1 USING INDEX t1z (z=?)}
  1184  
  1185  
  1186  # This test - 26.2.* - tests that another manifestation of the same problem
  1187  # is no longer present in the library. Assuming:
  1188  # 
  1189  #   CREATE INDEX t1xy ON t1(x, y)
  1190  #
  1191  # and that have samples for index t1xy as follows:
  1192  #
  1193  #
  1194  #   sample=('A', 70)        nEq=(100, 2)        nLt=(900, 970)
  1195  #   sample=('B', 70)        nEq=(100, 2)        nLt=(1000, 1070)    
  1196  #
  1197  # the planner should estimate that (x = 'B' AND y > 25) matches 76 rows
  1198  # (70 * 2/3 + 30). Before, due to the problem, the planner was estimating 
  1199  # that this matched 100 rows.
  1200  # 
  1201  reset_db
  1202  do_execsql_test 26.2.1 {
  1203    BEGIN;
  1204      CREATE TABLE t1(x, y, z);
  1205      CREATE INDEX i1 ON t1(x, y);
  1206      CREATE INDEX i2 ON t1(z);
  1207    
  1208      WITH 
  1209      cnt(y) AS (SELECT 0 UNION ALL SELECT y+1 FROM cnt WHERE y<99),
  1210      letters(x) AS (
  1211        SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' UNION SELECT 'D'
  1212      )
  1213      INSERT INTO t1(x, y) SELECT x, y FROM letters, cnt;
  1214    
  1215      WITH
  1216      letters(x) AS (
  1217        SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' UNION SELECT 'D'
  1218      )
  1219      INSERT INTO t1(x, y) SELECT x, 70 FROM letters;
  1220    
  1221      WITH
  1222      cnt(i) AS (SELECT 0 UNION ALL SELECT i+1 FROM cnt WHERE i<9999)
  1223      INSERT INTO t1(x, y) SELECT i, i FROM cnt;
  1224    
  1225      UPDATE t1 SET z = (rowid / 95);
  1226      ANALYZE;
  1227    COMMIT;
  1228  }
  1229  
  1230  do_eqp_test 26.2.2 {
  1231    SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?;
  1232  } {SEARCH t1 USING INDEX i1 (x=? AND y>?)}
  1233  
  1234  
  1235  finish_test