1# 2013-04-25 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# Test cases for transitive_closure virtual table. 13 14set testdir [file dirname $argv0] 15source $testdir/tester.tcl 16set testprefix closure01 17 18ifcapable !vtab||!cte { finish_test ; return } 19 20load_static_extension db closure 21 22do_execsql_test 1.0 { 23 BEGIN; 24 CREATE TABLE t1(x INTEGER PRIMARY KEY, y INTEGER); 25 WITH RECURSIVE 26 cnt(i) AS (VALUES(1) UNION ALL SELECT i+1 FROM cnt LIMIT 131072) 27 INSERT INTO t1(x, y) SELECT i, nullif(i,1)/2 FROM cnt; 28 CREATE INDEX t1y ON t1(y); 29 COMMIT; 30 CREATE VIRTUAL TABLE cx 31 USING transitive_closure(tablename=t1, idcolumn=x, parentcolumn=y); 32} {} 33 34# The entire table 35do_timed_execsql_test 1.1 { 36 SELECT count(*), depth FROM cx WHERE root=1 GROUP BY depth ORDER BY 1; 37} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/} 38do_timed_execsql_test 1.1-cte { 39 WITH RECURSIVE 40 below(id,depth) AS ( 41 VALUES(1,0) 42 UNION ALL 43 SELECT t1.x, below.depth+1 44 FROM t1 JOIN below on t1.y=below.id 45 ) 46 SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1; 47} {/1 0 1 17 2 1 4 2 8 3 16 4 .* 65536 16/} 48 49# descendents of 32768 50do_timed_execsql_test 1.2 { 51 SELECT * FROM cx WHERE root=32768 ORDER BY id; 52} {32768 0 65536 1 65537 1 131072 2} 53do_timed_execsql_test 1.2-cte { 54 WITH RECURSIVE 55 below(id,depth) AS ( 56 VALUES(32768,0) 57 UNION ALL 58 SELECT t1.x, below.depth+1 59 FROM t1 JOIN below on t1.y=below.id 60 WHERE below.depth<2 61 ) 62 SELECT id, depth FROM below ORDER BY id; 63} {32768 0 65536 1 65537 1 131072 2} 64 65# descendents of 16384 66do_timed_execsql_test 1.3 { 67 SELECT * FROM cx WHERE root=16384 AND depth<=2 ORDER BY id; 68} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2} 69do_timed_execsql_test 1.3-cte { 70 WITH RECURSIVE 71 below(id,depth) AS ( 72 VALUES(16384,0) 73 UNION ALL 74 SELECT t1.x, below.depth+1 75 FROM t1 JOIN below on t1.y=below.id 76 WHERE below.depth<2 77 ) 78 SELECT id, depth FROM below ORDER BY id; 79} {16384 0 32768 1 32769 1 65536 2 65537 2 65538 2 65539 2} 80 81# children of 16384 82do_execsql_test 1.4 { 83 SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx 84 WHERE root=16384 85 AND depth=1 86 ORDER BY id; 87} {32768 1 {} t1 x y 32769 1 {} t1 x y} 88 89# great-grandparent of 16384 90do_timed_execsql_test 1.5 { 91 SELECT id, depth, root, tablename, idcolumn, parentcolumn FROM cx 92 WHERE root=16384 93 AND depth=3 94 AND idcolumn='Y' 95 AND parentcolumn='X'; 96} {2048 3 {} t1 Y X} 97do_timed_execsql_test 1.5-cte { 98 WITH RECURSIVE 99 above(id,depth) AS ( 100 VALUES(16384,0) 101 UNION ALL 102 SELECT t1.y, above.depth+1 103 FROM t1 JOIN above ON t1.x=above.id 104 WHERE above.depth<3 105 ) 106 SELECT id FROM above WHERE depth=3; 107} {2048} 108 109# depth<5 110do_timed_execsql_test 1.6 { 111 SELECT count(*), depth FROM cx WHERE root=1 AND depth<5 112 GROUP BY depth ORDER BY 1; 113} {1 0 2 1 4 2 8 3 16 4} 114do_timed_execsql_test 1.6-cte { 115 WITH RECURSIVE 116 below(id,depth) AS ( 117 VALUES(1,0) 118 UNION ALL 119 SELECT t1.x, below.depth+1 120 FROM t1 JOIN below ON t1.y=below.id 121 WHERE below.depth<4 122 ) 123 SELECT count(*), depth FROM below GROUP BY depth ORDER BY 1; 124} {1 0 2 1 4 2 8 3 16 4} 125 126# depth<=5 127do_execsql_test 1.7 { 128 SELECT count(*), depth FROM cx WHERE root=1 AND depth<=5 129 GROUP BY depth ORDER BY 1; 130} {1 0 2 1 4 2 8 3 16 4 32 5} 131 132# depth==5 133do_execsql_test 1.8 { 134 SELECT count(*), depth FROM cx WHERE root=1 AND depth=5 135 GROUP BY depth ORDER BY 1; 136} {32 5} 137 138# depth BETWEEN 3 AND 5 139do_execsql_test 1.9 { 140 SELECT count(*), depth FROM cx WHERE root=1 AND depth BETWEEN 3 AND 5 141 GROUP BY depth ORDER BY 1; 142} {8 3 16 4 32 5} 143 144# depth==5 with min() and max() 145do_timed_execsql_test 1.10 { 146 SELECT count(*), min(id), max(id) FROM cx WHERE root=1 AND depth=5; 147} {32 32 63} 148do_timed_execsql_test 1.10-cte { 149 WITH RECURSIVE 150 below(id,depth) AS ( 151 VALUES(1,0) 152 UNION ALL 153 SELECT t1.x, below.depth+1 154 FROM t1 JOIN below ON t1.y=below.id 155 WHERE below.depth<5 156 ) 157 SELECT count(*), min(id), max(id) FROM below WHERE depth=5; 158} {32 32 63} 159 160# Create a much smaller table t2 with only 32 elements 161db eval { 162 CREATE TABLE t2(x INTEGER PRIMARY KEY, y INTEGER); 163 INSERT INTO t2 SELECT x, y FROM t1 WHERE x<32; 164 CREATE INDEX t2y ON t2(y); 165 CREATE VIRTUAL TABLE c2 166 USING transitive_closure(tablename=t2, idcolumn=x, parentcolumn=y); 167} 168 169# t2 full-table 170do_execsql_test 2.1 { 171 SELECT count(*), min(id), max(id) FROM c2 WHERE root=1; 172} {31 1 31} 173# t2 root=10 174do_execsql_test 2.2 { 175 SELECT id FROM c2 WHERE root=10; 176} {10 20 21} 177# t2 root=11 178do_execsql_test 2.3 { 179 SELECT id FROM c2 WHERE root=12; 180} {12 24 25} 181# t2 root IN [10,12] 182do_execsql_test 2.4 { 183 SELECT id FROM c2 WHERE root IN (10,12) ORDER BY id; 184} {10 12 20 21 24 25} 185# t2 root IN [10,12] (sorted) 186do_execsql_test 2.5 { 187 SELECT id FROM c2 WHERE root IN (10,12) ORDER BY +id; 188} {10 12 20 21 24 25} 189 190# t2 c2up from 20 191do_execsql_test 3.0 { 192 CREATE VIRTUAL TABLE c2up USING transitive_closure( 193 tablename = t2, 194 idcolumn = y, 195 parentcolumn = x 196 ); 197 SELECT id FROM c2up WHERE root=20; 198} {1 2 5 10 20} 199 200# cx as c2up 201do_execsql_test 3.1 { 202 SELECT id FROM cx 203 WHERE root=20 204 AND tablename='t2' 205 AND idcolumn='y' 206 AND parentcolumn='x'; 207} {1 2 5 10 20} 208 209# t2 first cousins of 20 210do_execsql_test 3.2 { 211 SELECT DISTINCT id FROM c2 212 WHERE root IN (SELECT id FROM c2up 213 WHERE root=20 AND depth<=2) 214 ORDER BY id; 215} {5 10 11 20 21 22 23} 216 217# t2 first cousins of 20 218do_execsql_test 3.3 { 219 SELECT id FROM c2 220 WHERE root=(SELECT id FROM c2up 221 WHERE root=20 AND depth=2) 222 AND depth=2 223 EXCEPT 224 SELECT id FROM c2 225 WHERE root=(SELECT id FROM c2up 226 WHERE root=20 AND depth=1) 227 AND depth<=1 228 ORDER BY id; 229} {22 23} 230 231# missing tablename. 232do_test 4.1 { 233 catchsql { 234 SELECT id FROM cx 235 WHERE root=20 236 AND tablename='t3' 237 AND idcolumn='y' 238 AND parentcolumn='x'; 239 } 240} {1 {no such table: t3}} 241 242# missing idcolumn 243do_test 4.2 { 244 catchsql { 245 SELECT id FROM cx 246 WHERE root=20 247 AND tablename='t2' 248 AND idcolumn='xyz' 249 AND parentcolumn='x'; 250 } 251} {1 {no such column: t2.xyz}} 252 253# missing parentcolumn 254do_test 4.3 { 255 catchsql { 256 SELECT id FROM cx 257 WHERE root=20 258 AND tablename='t2' 259 AND idcolumn='x' 260 AND parentcolumn='pqr'; 261 } 262} {1 {no such column: t2.pqr}} 263 264# generic closure 265do_execsql_test 5.1 { 266 CREATE VIRTUAL TABLE temp.closure USING transitive_closure; 267 SELECT id FROM closure 268 WHERE root=1 269 AND depth=3 270 AND tablename='t1' 271 AND idcolumn='x' 272 AND parentcolumn='y' 273 ORDER BY id; 274} {8 9 10 11 12 13 14 15} 275 276finish_test 277