blob: 301c19e284db4700d99dd126f0e95bb8e4a93b04 [file] [log] [blame]
dand2db31c2022-12-05 19:16:23 +00001# 2022 December 5
dan231ff4b2022-12-02 20:32:22 +00002#
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
13set testdir [file dirname $argv0]
14source $testdir/tester.tcl
15set testprefix scanstatus2
16
17ifcapable !scanstatus {
18 finish_test
19 return
20}
21
22do_execsql_test 1.0 {
23 CREATE TABLE t1(a, b);
24 CREATE TABLE t2(x, y);
25 INSERT INTO t1 VALUES(1, 2);
26 INSERT INTO t1 VALUES(3, 4);
27 INSERT INTO t2 VALUES('a', 'b');
28 INSERT INTO t2 VALUES('c', 'd');
29 INSERT INTO t2 VALUES('e', 'f');
30}
31
32proc do_zexplain_test {v2 tn sql res} {
33 db eval $sql
34 set stmt [db version -last-stmt-ptr]
35 set idx 0
36 set ret [list]
37
38 set cmd sqlite3_stmt_scanstatus
39 set f [list]
40 if {$v2} { lappend f complex }
41
42 while {1} {
43 set r [sqlite3_stmt_scanstatus -flags $f $stmt $idx]
44 if {[llength $r]==0} break
45 lappend ret [dict get $r zExplain]
46 incr idx
47 }
48 uplevel [list do_test $tn [list set {} $ret] [list {*}$res]]
49}
50
51proc get_cycles {stmt} {
52 set r [sqlite3_stmt_scanstatus $stmt -1]
53 dict get $r nCycle
54}
55
56proc foreach_scan {varname stmt body} {
57 upvar $varname var
58
59 for {set ii 0} {1} {incr ii} {
60 set r [sqlite3_stmt_scanstatus -flags complex $stmt $ii]
61 if {[llength $r]==0} break
62 array set var $r
63 uplevel $body
64 }
65}
66
67proc get_eqp_graph {stmt iPar nIndent} {
68 set res ""
69 foreach_scan A $stmt {
70 if {$A(iParentId)==$iPar} {
71 set txt $A(zExplain)
72 if {$A(nCycle)>=0} {
73 append txt " (nCycle=$A(nCycle))"
74 }
75 append res "[string repeat - $nIndent]$txt\n"
76 append res [get_eqp_graph $stmt $A(iSelectId) [expr $nIndent+2]]
77 }
78 }
79 set res
80}
81
82proc get_graph {stmt} {
83 set nCycle [get_cycles $stmt]
84 set res "QUERY (nCycle=$nCycle)\n"
85 append res [get_eqp_graph $stmt 0 2]
86}
87
88proc do_graph_test {tn sql res} {
89 db eval $sql
90 set stmt [db version -last-stmt-ptr]
dan231ff4b2022-12-02 20:32:22 +000091 set graph [string trim [get_graph $stmt]]
dan2adb3092022-12-06 18:48:06 +000092
dan231ff4b2022-12-02 20:32:22 +000093 set graph [regsub -all {nCycle=[0-9]+} $graph nCycle=nnn]
94 uplevel [list do_test $tn [list set {} $graph] [string trim $res]]
95}
96
danf6f01f12022-12-03 18:16:25 +000097proc puts_graph {sql} {
98 db eval $sql
99 set stmt [db version -last-stmt-ptr]
100 puts [string trim [get_graph $stmt]]
101}
102
dan231ff4b2022-12-02 20:32:22 +0000103
104do_zexplain_test 0 1.1 {
105 SELECT (SELECT a FROM t1 WHERE b=x) FROM t2 WHERE y=2
106} {
107 {SCAN t2}
108 {SCAN t1}
109}
110do_zexplain_test 1 1.2 {
111 SELECT (SELECT a FROM t1 WHERE b=x) FROM t2 WHERE y=2
112} {
113 {SCAN t2}
114 {CORRELATED SCALAR SUBQUERY 1}
115 {SCAN t1}
116}
117
118do_graph_test 1.3 {
119 SELECT (SELECT a FROM t1 WHERE b=x) FROM t2 WHERE y=2
120} {
121QUERY (nCycle=nnn)
dan2adb3092022-12-06 18:48:06 +0000122--SCAN t2 (nCycle=nnn)
dan231ff4b2022-12-02 20:32:22 +0000123--CORRELATED SCALAR SUBQUERY 1 (nCycle=nnn)
dan2adb3092022-12-06 18:48:06 +0000124----SCAN t1 (nCycle=nnn)
dan231ff4b2022-12-02 20:32:22 +0000125}
126
127do_graph_test 1.4 {
128 WITH v2(x,y) AS MATERIALIZED (
129 SELECT x,y FROM t2
130 )
131 SELECT * FROM t1, v2 ORDER BY y;
132} {
133QUERY (nCycle=nnn)
134--MATERIALIZE v2 (nCycle=nnn)
dan2adb3092022-12-06 18:48:06 +0000135----SCAN t2 (nCycle=nnn)
136--SCAN v2 (nCycle=nnn)
137--SCAN t1 (nCycle=nnn)
dana3d0c152022-12-05 18:19:56 +0000138--USE TEMP B-TREE FOR ORDER BY (nCycle=nnn)
dan231ff4b2022-12-02 20:32:22 +0000139}
140
danad23a472022-12-03 21:24:26 +0000141#-------------------------------------------------------------------------
142reset_db
143do_execsql_test 2.0 {
144 CREATE VIRTUAL TABLE ft USING fts5(a);
145 INSERT INTO ft VALUES('abc');
146 INSERT INTO ft VALUES('def');
147 INSERT INTO ft VALUES('ghi');
148}
149
danad23a472022-12-03 21:24:26 +0000150do_graph_test 2.1 {
151 SELECT * FROM ft('def')
152} {
dana3d0c152022-12-05 18:19:56 +0000153QUERY (nCycle=nnn)
154--SCAN ft VIRTUAL TABLE INDEX 0:M1 (nCycle=nnn)
danad23a472022-12-03 21:24:26 +0000155}
156
dan2adb3092022-12-06 18:48:06 +0000157#-------------------------------------------------------------------------
158reset_db
159do_execsql_test 3.0 {
160 CREATE TABLE x1(a, b);
161 CREATE TABLE x2(c, d);
162
163 WITH s(i) AS (SELECT 1 UNION ALL SELECT i+1 FROM s WHERE i<1000)
164 INSERT INTO x1 SELECT i, i FROM s;
165 INSERT INTO x2 SELECT a, b FROM x1;
166}
167
168do_graph_test 2.1 {
169 SELECT * FROM x1, x2 WHERE c=+a;
170} {
171QUERY (nCycle=nnn)
172--SCAN x1 (nCycle=nnn)
danf2cc3382022-12-07 17:29:17 +0000173--CREATE AUTOMATIC INDEX ON x2(c, d) (nCycle=nnn)
dan2adb3092022-12-06 18:48:06 +0000174--SEARCH x2 USING AUTOMATIC COVERING INDEX (c=?) (nCycle=nnn)
175}
176
danf2cc3382022-12-07 17:29:17 +0000177#-------------------------------------------------------------------------
178reset_db
179do_execsql_test 4.0 {
180 CREATE TABLE rt1 (id INTEGER PRIMARY KEY, x1, x2);
181 CREATE TABLE rt2 (id, x1, x2);
182}
183
184do_graph_test 4.1 {
185 SELECT * FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=rt1.x1;
186} {
187QUERY (nCycle=nnn)
188--SCAN rt1 (nCycle=nnn)
189--CREATE AUTOMATIC INDEX ON rt2(x1, id, x2) (nCycle=nnn)
190--SEARCH rt2 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn)
191}
192
193do_graph_test 4.2 {
194 SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=rt1.x1;
195} {
196QUERY (nCycle=nnn)
197--SCAN rt1 (nCycle=nnn)
198--CREATE AUTOMATIC INDEX ON rt2(x1, id) (nCycle=nnn)
199--SEARCH rt2 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn)
200}
201
202do_graph_test 4.3 {
203 SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND (rt2.x1+1)=(rt1.x1+1);
204} {
205QUERY (nCycle=nnn)
206--SCAN rt1 (nCycle=nnn)
207--SCAN rt2 (nCycle=nnn)
208}
209
210do_graph_test 4.4 {
211 SELECT rt2.id FROM rt1, rt2 WHERE rt1.id%2 AND rt2.x1=(rt1.x1+1) AND rt2.id>5;
212} {
213QUERY (nCycle=nnn)
214--SCAN rt1 (nCycle=nnn)
215--CREATE AUTOMATIC INDEX ON rt2(x1, id) WHERE <expr> (nCycle=nnn)
216--SEARCH rt2 USING AUTOMATIC PARTIAL COVERING INDEX (x1=?) (nCycle=nnn)
217}
218
219do_graph_test 4.5 {
220 SELECT v1.cnt FROM rt1, (
221 SELECT count(*) AS cnt, rt2.x1 AS x1 FROM rt2 GROUP BY x1
222 ) AS v1 WHERE rt1.x1=v1.x1
223} {
224QUERY (nCycle=nnn)
dan8b58fbf2022-12-15 11:39:12 +0000225--CO-ROUTINE v1
danf2cc3382022-12-07 17:29:17 +0000226----SCAN rt2 (nCycle=nnn)
227----USE TEMP B-TREE FOR GROUP BY
228--SCAN rt1 (nCycle=nnn)
229--CREATE AUTOMATIC INDEX ON v1(x1, cnt) (nCycle=nnn)
230--SEARCH v1 USING AUTOMATIC COVERING INDEX (x1=?) (nCycle=nnn)
231}
232
dan231ff4b2022-12-02 20:32:22 +0000233finish_test
234
235