191d3a61fSdan# 2014 July 15 291d3a61fSdan# 391d3a61fSdan# The author disclaims copyright to this source code. In place of 491d3a61fSdan# a legal notice, here is a blessing: 591d3a61fSdan# 691d3a61fSdan# May you do good and not evil. 791d3a61fSdan# May you find forgiveness for yourself and forgive others. 891d3a61fSdan# May you share freely, never taking more than you give. 991d3a61fSdan# 1091d3a61fSdan#*********************************************************************** 1191d3a61fSdan# This file implements regression tests for SQLite library. 1291d3a61fSdan# 1391d3a61fSdan 1491d3a61fSdanset testdir [file dirname $argv0] 1591d3a61fSdansource $testdir/tester.tcl 1691d3a61fSdanset testprefix cursorhint 1791d3a61fSdan 18f7854c73Sdrhifcapable !cursorhints { 19f7854c73Sdrh finish_test 20f7854c73Sdrh return 21f7854c73Sdrh} 22f7854c73Sdrh 2391d3a61fSdando_execsql_test 1.0 { 241eb6eeb8Sdrh CREATE TABLE t1(a,b,c,d); 251eb6eeb8Sdrh CREATE TABLE t2(x,y,z); 261eb6eeb8Sdrh INSERT INTO t1(a,b) VALUES(10, 15); 271eb6eeb8Sdrh INSERT INTO t1(a,b) VALUES(20, 25); 281eb6eeb8Sdrh INSERT INTO t2(x,y) VALUES('ten', 'fifteen'); 291eb6eeb8Sdrh INSERT INTO t2(x,y) VALUES('twenty', 'twentyfive'); 301eb6eeb8Sdrh CREATE TABLE t3(id TEXT PRIMARY KEY, a, b, c, d) WITHOUT ROWID; 311eb6eeb8Sdrh INSERT INTO t3(id,a,b,c,d) SELECT rowid, a, b, c, d FROM t1; 3291d3a61fSdan PRAGMA automatic_index = 0; 3391d3a61fSdan} 3491d3a61fSdan 351eb6eeb8Sdrh# Run EXPLAIN on $sql. Return a list of P4 values for all $opcode 361eb6eeb8Sdrh# opcodes. 371eb6eeb8Sdrh# 381eb6eeb8Sdrhproc p4_of_opcode {db opcode sql} { 391eb6eeb8Sdrh set res {} 401eb6eeb8Sdrh $db eval "EXPLAIN $sql" x { 411eb6eeb8Sdrh if {$x(opcode)==$opcode} {lappend res $x(p4)} 421eb6eeb8Sdrh } 431eb6eeb8Sdrh return $res 4491d3a61fSdan} 4591d3a61fSdan 461eb6eeb8Sdrh# Run EXPLAIN on $sql. Return a list of P5 values for all $opcode 471eb6eeb8Sdrh# opcodes that contain regexp $comment in their comment 481eb6eeb8Sdrh# 497f10579aSdrhproc p5_of_opcode {db opcode sql} { 501eb6eeb8Sdrh set res {} 511eb6eeb8Sdrh $db eval "EXPLAIN $sql" x { 527f10579aSdrh if {$x(opcode)==$opcode} { 531eb6eeb8Sdrh lappend res $x(p5) 541eb6eeb8Sdrh } 551eb6eeb8Sdrh } 561eb6eeb8Sdrh return $res 5791d3a61fSdan} 5891d3a61fSdan 591eb6eeb8Sdrh# Verify that when t1 is in the outer loop and t2 is in the inner loop, 601eb6eeb8Sdrh# no cursor hints occur for t1 (since it is a full table scan) but that 611eb6eeb8Sdrh# each t2 access has a cursor hint based on the current t1.a value. 621eb6eeb8Sdrh# 631eb6eeb8Sdrhdo_test 1.1 { 641eb6eeb8Sdrh p4_of_opcode db CursorHint { 651eb6eeb8Sdrh SELECT * FROM t1 CROSS JOIN t2 WHERE a=x 6691d3a61fSdan } 67a67a3162Sdrh} {{EQ(r[1],c0)}} 681eb6eeb8Sdrhdo_test 1.2 { 697f10579aSdrh p5_of_opcode db OpenRead { 701eb6eeb8Sdrh SELECT * FROM t1 CROSS JOIN t2 WHERE a=x 7191d3a61fSdan } 72*a796de83Sdan} {0 0} 7391d3a61fSdan 741eb6eeb8Sdrh# Do the same test the other way around. 751eb6eeb8Sdrh# 761eb6eeb8Sdrhdo_test 2.1 { 771eb6eeb8Sdrh p4_of_opcode db CursorHint { 781eb6eeb8Sdrh SELECT * FROM t2 CROSS JOIN t1 WHERE a=x 7991d3a61fSdan } 80a67a3162Sdrh} {{EQ(c0,r[1])}} 811eb6eeb8Sdrhdo_test 2.2 { 827f10579aSdrh p5_of_opcode db OpenRead { 831eb6eeb8Sdrh SELECT * FROM t2 CROSS JOIN t1 WHERE a=x 841eb6eeb8Sdrh } 85*a796de83Sdan} {0 0} 8691d3a61fSdan 871eb6eeb8Sdrh# Various expressions captured by CursorHint 881eb6eeb8Sdrh# 891eb6eeb8Sdrhdo_test 3.1 { 901eb6eeb8Sdrh p4_of_opcode db CursorHint { 911eb6eeb8Sdrh SELECT * FROM t1 WHERE a=15 AND c=22 AND rowid!=98 9291d3a61fSdan } 93a67a3162Sdrh} {AND(AND(EQ(c0,15),EQ(c2,22)),NE(rowid,98))} 941eb6eeb8Sdrhdo_test 3.2 { 951eb6eeb8Sdrh p4_of_opcode db CursorHint { 961eb6eeb8Sdrh SELECT * FROM t3 WHERE a<15 AND b>22 AND id!=98 971eb6eeb8Sdrh } 98a67a3162Sdrh} {AND(AND(LT(c1,15),GT(c2,22)),NE(c0,98))} 991eb6eeb8Sdrh 1001eb6eeb8Sdrh# Indexed queries 1011eb6eeb8Sdrh# 102b413a546Sdrhdo_test 4.1asc { 1031eb6eeb8Sdrh db eval { 1041eb6eeb8Sdrh CREATE INDEX t1bc ON t1(b,c); 1051eb6eeb8Sdrh CREATE INDEX t2yz ON t2(y,z); 1061eb6eeb8Sdrh } 1071eb6eeb8Sdrh p4_of_opcode db CursorHint { 108b413a546Sdrh SELECT * FROM t1 WHERE b>11 ORDER BY b ASC; 109b413a546Sdrh } 110b413a546Sdrh} {} 111b413a546Sdrhdo_test 4.1desc { 112b413a546Sdrh p4_of_opcode db CursorHint { 113b413a546Sdrh SELECT * FROM t1 WHERE b>11 ORDER BY b DESC; 1141eb6eeb8Sdrh } 115a67a3162Sdrh} {GT(c0,11)} 1161eb6eeb8Sdrhdo_test 4.2 { 1177f10579aSdrh p5_of_opcode db OpenRead { 1181eb6eeb8Sdrh SELECT * FROM t1 WHERE b>11; 1191eb6eeb8Sdrh } 120*a796de83Sdan} {2 0} 121b413a546Sdrhdo_test 4.3asc { 1221eb6eeb8Sdrh p4_of_opcode db CursorHint { 123b413a546Sdrh SELECT c FROM t1 WHERE b<11 ORDER BY b ASC; 1241eb6eeb8Sdrh } 125b413a546Sdrh} {LT(c0,11)} 126b413a546Sdrhdo_test 4.3desc { 127b413a546Sdrh p4_of_opcode db CursorHint { 128b413a546Sdrh SELECT c FROM t1 WHERE b<11 ORDER BY b DESC; 129b413a546Sdrh } 130b413a546Sdrh} {} 1311eb6eeb8Sdrhdo_test 4.4 { 1327f10579aSdrh p5_of_opcode db OpenRead { 133b413a546Sdrh SELECT c FROM t1 WHERE b<11; 1341eb6eeb8Sdrh } 135*a796de83Sdan} {0} 13691d3a61fSdan 137b413a546Sdrhdo_test 4.5asc { 138b413a546Sdrh p4_of_opcode db CursorHint { 139b413a546Sdrh SELECT c FROM t1 WHERE b>=10 AND b<=20 ORDER BY b ASC; 140b413a546Sdrh } 141b413a546Sdrh} {LE(c0,20)} 142b413a546Sdrhdo_test 4.5desc { 143b413a546Sdrh p4_of_opcode db CursorHint { 144b413a546Sdrh SELECT c FROM t1 WHERE b>=10 AND b<=20 ORDER BY b DESC; 145b413a546Sdrh } 146b413a546Sdrh} {GE(c0,10)} 147bcf40a7fSdrh 148bcf40a7fSdrh# If there are any equality terms used in the constraint, then all terms 149bcf40a7fSdrh# should be hinted. 150bcf40a7fSdrh# 151b413a546Sdrhdo_test 4.6asc { 152b413a546Sdrh p4_of_opcode db CursorHint { 153b413a546Sdrh SELECT rowid FROM t1 WHERE b=22 AND c>=10 AND c<=20 ORDER BY b,c ASC; 154b413a546Sdrh } 155bcf40a7fSdrh} {AND(AND(EQ(c0,22),GE(c1,10)),LE(c1,20))} 156b413a546Sdrhdo_test 4.6desc { 157b413a546Sdrh p4_of_opcode db CursorHint { 158b413a546Sdrh SELECT rowid FROM t1 WHERE b=22 AND c>=10 AND c<=20 ORDER BY b,c DESC; 159b413a546Sdrh } 160bcf40a7fSdrh} {AND(AND(EQ(c0,22),GE(c1,10)),LE(c1,20))} 16191d3a61fSdan 16291d3a61fSdanfinish_test 163