# 2013 August 3 # # 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 contains automated tests used to verify that the sqlite_stat4 # functionality is working. # set testdir [file dirname $argv0] source $testdir/tester.tcl set testprefix analyze9 ifcapable !stat4 { finish_test return } proc s {blob} { set ret "" binary scan $blob c* bytes foreach b $bytes { set t [binary format c $b] if {[string is print $t]} { append ret $t } else { append ret . } } return $ret } db function s s do_execsql_test 1.0 { CREATE TABLE t1(a TEXT, b TEXT); INSERT INTO t1 VALUES('(0)', '(0)'); INSERT INTO t1 VALUES('(1)', '(1)'); INSERT INTO t1 VALUES('(2)', '(2)'); INSERT INTO t1 VALUES('(3)', '(3)'); INSERT INTO t1 VALUES('(4)', '(4)'); CREATE INDEX i1 ON t1(a, b); } {} do_execsql_test 1.1 { ANALYZE; } {} do_execsql_test 1.3 { SELECT tbl,idx,nEq,nLt,nDLt,test_decode(sample) FROM sqlite_stat4; } { t1 i1 {1 1 1} {0 0 0} {0 0 0} {(0) (0) 1} t1 i1 {1 1 1} {1 1 1} {1 1 1} {(1) (1) 2} t1 i1 {1 1 1} {2 2 2} {2 2 2} {(2) (2) 3} t1 i1 {1 1 1} {3 3 3} {3 3 3} {(3) (3) 4} t1 i1 {1 1 1} {4 4 4} {4 4 4} {(4) (4) 5} } do_execsql_test 1.2 { SELECT tbl,idx,nEq,nLt,nDLt,s(sample) FROM sqlite_stat4; } { t1 i1 {1 1 1} {0 0 0} {0 0 0} ....(0)(0) t1 i1 {1 1 1} {1 1 1} {1 1 1} ....(1)(1). t1 i1 {1 1 1} {2 2 2} {2 2 2} ....(2)(2). t1 i1 {1 1 1} {3 3 3} {3 3 3} ....(3)(3). t1 i1 {1 1 1} {4 4 4} {4 4 4} ....(4)(4). } #------------------------------------------------------------------------- # This is really just to test SQL user function "test_decode". # reset_db do_execsql_test 2.1 { CREATE TABLE t1(a, b, c); INSERT INTO t1 VALUES('some text', 14, NULL); INSERT INTO t1 VALUES(22.0, NULL, x'656667'); CREATE INDEX i1 ON t1(a, b, c); ANALYZE; SELECT test_decode(sample) FROM sqlite_stat4; } { {22.0 NULL x'656667' 2} {{some text} 14 NULL 1} } #------------------------------------------------------------------------- # reset_db do_execsql_test 3.1 { CREATE TABLE t2(a, b); CREATE INDEX i2 ON t2(a, b); BEGIN; } do_test 3.2 { for {set i 0} {$i < 1000} {incr i} { set a [expr $i / 10] set b [expr int(rand() * 15.0)] execsql { INSERT INTO t2 VALUES($a, $b) } } execsql COMMIT } {} db func lindex lindex # Each value of "a" occurs exactly 10 times in the table. # do_execsql_test 3.3.1 { SELECT count(*) FROM t2 GROUP BY a; } [lrange [string repeat "10 " 100] 0 99] # The first element in the "nEq" list of all samples should therefore be 10. # do_execsql_test 3.3.2 { ANALYZE; SELECT lindex(nEq, 0) FROM sqlite_stat4; } [lrange [string repeat "10 " 100] 0 23] #------------------------------------------------------------------------- # do_execsql_test 3.4 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a INTEGER PRIMARY KEY, b, c); INSERT INTO t1 VALUES(1, 1, 'one-a'); INSERT INTO t1 VALUES(11, 1, 'one-b'); INSERT INTO t1 VALUES(21, 1, 'one-c'); INSERT INTO t1 VALUES(31, 1, 'one-d'); INSERT INTO t1 VALUES(41, 1, 'one-e'); INSERT INTO t1 VALUES(51, 1, 'one-f'); INSERT INTO t1 VALUES(61, 1, 'one-g'); INSERT INTO t1 VALUES(71, 1, 'one-h'); INSERT INTO t1 VALUES(81, 1, 'one-i'); INSERT INTO t1 VALUES(91, 1, 'one-j'); INSERT INTO t1 SELECT a+1,2,'two' || substr(c,4) FROM t1; INSERT INTO t1 SELECT a+2,3,'three'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+3,4,'four'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+4,5,'five'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; INSERT INTO t1 SELECT a+5,6,'six'||substr(c,4) FROM t1 WHERE c GLOB 'one-*'; CREATE INDEX t1b ON t1(b); ANALYZE; SELECT c FROM t1 WHERE b=3 AND a BETWEEN 30 AND 60; } {three-d three-e three-f} #------------------------------------------------------------------------- # These tests verify that the sample selection for stat4 appears to be # working as designed. # reset_db db func lindex lindex db func lrange lrange do_execsql_test 4.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(c, b, a); } proc insert_filler_rows_n {iStart args} { set A(-ncopy) 1 set A(-nval) 1 foreach {k v} $args { if {[info exists A($k)]==0} { error "no such option: $k" } set A($k) $v } if {[llength $args] % 2} { error "option requires an argument: [lindex $args end]" } for {set i 0} {$i < $A(-nval)} {incr i} { set iVal [expr $iStart+$i] for {set j 0} {$j < $A(-ncopy)} {incr j} { execsql { INSERT INTO t1 VALUES($iVal, $iVal, $iVal) } } } } do_test 4.1 { execsql { BEGIN } insert_filler_rows_n 0 -ncopy 10 -nval 19 insert_filler_rows_n 20 -ncopy 1 -nval 100 execsql { INSERT INTO t1(c, b, a) VALUES(200, 1, 'a'); INSERT INTO t1(c, b, a) VALUES(200, 1, 'b'); INSERT INTO t1(c, b, a) VALUES(200, 1, 'c'); INSERT INTO t1(c, b, a) VALUES(200, 2, 'e'); INSERT INTO t1(c, b, a) VALUES(200, 2, 'f'); INSERT INTO t1(c, b, a) VALUES(201, 3, 'g'); INSERT INTO t1(c, b, a) VALUES(201, 4, 'h'); ANALYZE; SELECT count(*) FROM sqlite_stat4; SELECT count(*) FROM t1; } } {24 297} do_execsql_test 4.2 { SELECT neq, lrange(nlt, 0, 2), lrange(ndlt, 0, 2), lrange(test_decode(sample), 0, 2) FROM sqlite_stat4 ORDER BY rowid LIMIT 16; } { {10 10 10 1} {0 0 0} {0 0 0} {0 0 0} {10 10 10 1} {10 10 10} {1 1 1} {1 1 1} {10 10 10 1} {20 20 20} {2 2 2} {2 2 2} {10 10 10 1} {30 30 30} {3 3 3} {3 3 3} {10 10 10 1} {40 40 40} {4 4 4} {4 4 4} {10 10 10 1} {50 50 50} {5 5 5} {5 5 5} {10 10 10 1} {60 60 60} {6 6 6} {6 6 6} {10 10 10 1} {70 70 70} {7 7 7} {7 7 7} {10 10 10 1} {80 80 80} {8 8 8} {8 8 8} {10 10 10 1} {90 90 90} {9 9 9} {9 9 9} {10 10 10 1} {100 100 100} {10 10 10} {10 10 10} {10 10 10 1} {110 110 110} {11 11 11} {11 11 11} {10 10 10 1} {120 120 120} {12 12 12} {12 12 12} {10 10 10 1} {130 130 130} {13 13 13} {13 13 13} {10 10 10 1} {140 140 140} {14 14 14} {14 14 14} {10 10 10 1} {150 150 150} {15 15 15} {15 15 15} } do_execsql_test 4.3 { SELECT neq, lrange(nlt, 0, 2), lrange(ndlt, 0, 2), lrange(test_decode(sample), 0, 1) FROM sqlite_stat4 ORDER BY rowid DESC LIMIT 2; } { {2 1 1 1} {295 296 296} {120 122 125} {201 4} {5 3 1 1} {290 290 292} {119 119 121} {200 1} } do_execsql_test 4.4 { SELECT count(DISTINCT c) FROM t1 WHERE c<201 } 120 do_execsql_test 4.5 { SELECT count(DISTINCT c) FROM t1 WHERE c<200 } 119 # Check that the perioidic samples are present. do_execsql_test 4.6 { SELECT count(*) FROM sqlite_stat4 WHERE lindex(test_decode(sample), 3) IN ('34', '68', '102', '136', '170', '204', '238', '272') } {8} finish_test