Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch rework-EQP Excluding Merge-Ins
This is equivalent to a diff from 853f316359 to 956fef361a
2018-05-03
| ||
19:56 | Overhaul of EXPLAIN QUERY PLAN. The output is now in the form of a tree. More details of the query plan are shown, and what is shown is truer to what actually happens. (check-in: ff01bbdabc user: drh tags: trunk) | |
19:47 | Optimizations to the new EQP framework. (Closed-Leaf check-in: 956fef361a user: drh tags: rework-EQP) | |
01:37 | Enhance EXPLAIN QUERY PLAN to report the generation of constant rows using VALUES or just a SELECT without FROM. (check-in: c75eee69fa user: drh tags: rework-EQP) | |
2018-05-02
| ||
03:01 | Add sqlite3_win32_set_directory8() and sqlite3_win32_set_directory16() functions. (check-in: 22089ea2bb user: mistachkin tags: trunk) | |
00:33 | Begin reengineering the EXPLAIN QUERY PLAN function to provide more intuitive output. (check-in: 70b48a7972 user: drh tags: rework-EQP) | |
2018-05-01
| ||
18:39 | The SQLITE_ALLOW_SQLITE_MASTER_INDEX compile-time option allows a CREATE INDEX statement against the sqlite_master table. Once created, the index works, and is usable by legacy instances of SQLite. (check-in: 853f316359 user: drh tags: trunk) | |
2018-04-28
| ||
19:08 | Test cases added for SQLITE_DBCONFIG_RESET_DATABASE. (check-in: 08665a9e2e user: drh tags: trunk) | |
Changes to ext/expert/expert1.test.
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 ... 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 ... 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 ... 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
eval $setup do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } { SELECT * FROM t1 } { (no new indexes) 0|0|0|SCAN TABLE t1 } do_setup_rec_test $tn.2 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b>?; } { CREATE INDEX t1_idx_00000062 ON t1(b); 0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000062 (b>?) } do_setup_rec_test $tn.3 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ? } { CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE); 0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_3e094c27 (b>? AND b<?) } do_setup_rec_test $tn.4 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 ORDER BY b; } { CREATE INDEX t1_idx_00000062 ON t1(b); 0|0|0|SCAN TABLE t1 USING INDEX t1_idx_00000062 } do_setup_rec_test $tn.5 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 WHERE a=? ORDER BY b; } { CREATE INDEX t1_idx_000123a7 ON t1(a, b); 0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?) } do_setup_rec_test $tn.6 { CREATE TABLE t1(a, b, c); } { SELECT min(a) FROM t1 } { CREATE INDEX t1_idx_00000061 ON t1(a); 0|0|0|SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061 } do_setup_rec_test $tn.7 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 ORDER BY a, b, c; } { CREATE INDEX t1_idx_033e95fe ON t1(a, b, c); 0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_033e95fe } #do_setup_rec_test $tn.1.8 { # CREATE TABLE t1(a, b, c); #} { # SELECT * FROM t1 ORDER BY a ASC, b COLLATE nocase DESC, c ASC; #} { ................................................................................ do_setup_rec_test $tn.8.1 { CREATE TABLE t1(a COLLATE NOCase, b, c); } { SELECT * FROM t1 WHERE a=? } { CREATE INDEX t1_idx_00000061 ON t1(a); 0|0|0|SEARCH TABLE t1 USING INDEX t1_idx_00000061 (a=?) } do_setup_rec_test $tn.8.2 { CREATE TABLE t1(a, b COLLATE nocase, c); } { SELECT * FROM t1 ORDER BY a ASC, b DESC, c ASC; } { CREATE INDEX t1_idx_5cb97285 ON t1(a, b DESC, c); 0|0|0|SCAN TABLE t1 USING COVERING INDEX t1_idx_5cb97285 } # Tables with names that require quotes. # do_setup_rec_test $tn.9.1 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE a=? } { CREATE INDEX 't t_idx_00000061' ON 't t'(a); 0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000061 (a=?) } do_setup_rec_test $tn.9.2 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE b BETWEEN ? AND ? } { CREATE INDEX 't t_idx_00000062' ON 't t'(b); 0|0|0|SEARCH TABLE t t USING INDEX t t_idx_00000062 (b>? AND b<?) } # Columns with names that require quotes. # do_setup_rec_test $tn.10.1 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 WHERE "b b" = ? } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); 0|0|0|SEARCH TABLE t3 USING INDEX t3_idx_00050c52 (b b=?) } do_setup_rec_test $tn.10.2 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 ORDER BY "b b" } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); 0|0|0|SCAN TABLE t3 USING INDEX t3_idx_00050c52 } # Transitive constraints # do_setup_rec_test $tn.11.1 { CREATE TABLE t5(a, b); CREATE TABLE t6(c, d); } { SELECT * FROM t5, t6 WHERE a=? AND b=c AND c=? } { CREATE INDEX t5_idx_000123a7 ON t5(a, b); CREATE INDEX t6_idx_00000063 ON t6(c); 0|0|1|SEARCH TABLE t6 USING INDEX t6_idx_00000063 (c=?) 0|1|0|SEARCH TABLE t5 USING COVERING INDEX t5_idx_000123a7 (a=? AND b=?) } # OR terms. # do_setup_rec_test $tn.12.1 { CREATE TABLE t7(a, b); } { SELECT * FROM t7 WHERE a=? OR b=? } { CREATE INDEX t7_idx_00000062 ON t7(b); CREATE INDEX t7_idx_00000061 ON t7(a); 0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?) 0|0|0|SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?) } # rowid terms. # do_setup_rec_test $tn.13.1 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE rowid=? } { (no new indexes) 0|0|0|SEARCH TABLE t8 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.13.2 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 ORDER BY rowid } { (no new indexes) 0|0|0|SCAN TABLE t8 } do_setup_rec_test $tn.13.3 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE a=? ORDER BY rowid } { CREATE INDEX t8_idx_00000061 ON t8(a); 0|0|0|SEARCH TABLE t8 USING INDEX t8_idx_00000061 (a=?) } # Triggers # do_setup_rec_test $tn.14 { CREATE TABLE t9(a, b, c); CREATE TABLE t10(a, b, c); ................................................................................ CREATE TRIGGER t9t AFTER INSERT ON t9 BEGIN UPDATE t10 SET a=new.a WHERE b = new.b; END; } { INSERT INTO t9 VALUES(?, ?, ?); } { CREATE INDEX t10_idx_00000062 ON t10(b); 0|1|0|-- TRIGGER t9t 0|0|0|SEARCH TABLE t10 USING INDEX t10_idx_00000062 (b=?) } do_setup_rec_test $tn.15 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) ................................................................................ WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s; } { SELECT * FROM t2, t1 WHERE b=? AND d=? AND t2.rowid=t1.rowid } { CREATE INDEX t2_idx_00000064 ON t2(d); 0|0|0|SEARCH TABLE t2 USING INDEX t2_idx_00000064 (d=?) 0|1|1|SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.16 { CREATE TABLE t1(a, b); } { SELECT * FROM t1 WHERE b IS NOT NULL; } { (no new indexes) 0|0|0|SCAN TABLE t1 } } proc do_candidates_test {tn sql res} { set res [squish [string trim $res]] |
| | | | | | | | | | | | | | | | | | | | | | | | | |
91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 ... 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 ... 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 ... 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 |
eval $setup do_setup_rec_test $tn.1 { CREATE TABLE t1(a, b, c) } { SELECT * FROM t1 } { (no new indexes) SCAN TABLE t1 } do_setup_rec_test $tn.2 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b>?; } { CREATE INDEX t1_idx_00000062 ON t1(b); SEARCH TABLE t1 USING INDEX t1_idx_00000062 (b>?) } do_setup_rec_test $tn.3 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 WHERE b COLLATE nocase BETWEEN ? AND ? } { CREATE INDEX t1_idx_3e094c27 ON t1(b COLLATE NOCASE); SEARCH TABLE t1 USING INDEX t1_idx_3e094c27 (b>? AND b<?) } do_setup_rec_test $tn.4 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 ORDER BY b; } { CREATE INDEX t1_idx_00000062 ON t1(b); SCAN TABLE t1 USING INDEX t1_idx_00000062 } do_setup_rec_test $tn.5 { CREATE TABLE t1(a, b, c); } { SELECT a FROM t1 WHERE a=? ORDER BY b; } { CREATE INDEX t1_idx_000123a7 ON t1(a, b); SEARCH TABLE t1 USING COVERING INDEX t1_idx_000123a7 (a=?) } do_setup_rec_test $tn.6 { CREATE TABLE t1(a, b, c); } { SELECT min(a) FROM t1 } { CREATE INDEX t1_idx_00000061 ON t1(a); SEARCH TABLE t1 USING COVERING INDEX t1_idx_00000061 } do_setup_rec_test $tn.7 { CREATE TABLE t1(a, b, c); } { SELECT * FROM t1 ORDER BY a, b, c; } { CREATE INDEX t1_idx_033e95fe ON t1(a, b, c); SCAN TABLE t1 USING COVERING INDEX t1_idx_033e95fe } #do_setup_rec_test $tn.1.8 { # CREATE TABLE t1(a, b, c); #} { # SELECT * FROM t1 ORDER BY a ASC, b COLLATE nocase DESC, c ASC; #} { ................................................................................ do_setup_rec_test $tn.8.1 { CREATE TABLE t1(a COLLATE NOCase, b, c); } { SELECT * FROM t1 WHERE a=? } { CREATE INDEX t1_idx_00000061 ON t1(a); SEARCH TABLE t1 USING INDEX t1_idx_00000061 (a=?) } do_setup_rec_test $tn.8.2 { CREATE TABLE t1(a, b COLLATE nocase, c); } { SELECT * FROM t1 ORDER BY a ASC, b DESC, c ASC; } { CREATE INDEX t1_idx_5cb97285 ON t1(a, b DESC, c); SCAN TABLE t1 USING COVERING INDEX t1_idx_5cb97285 } # Tables with names that require quotes. # do_setup_rec_test $tn.9.1 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE a=? } { CREATE INDEX 't t_idx_00000061' ON 't t'(a); SEARCH TABLE t t USING INDEX t t_idx_00000061 (a=?) } do_setup_rec_test $tn.9.2 { CREATE TABLE "t t"(a, b, c); } { SELECT * FROM "t t" WHERE b BETWEEN ? AND ? } { CREATE INDEX 't t_idx_00000062' ON 't t'(b); SEARCH TABLE t t USING INDEX t t_idx_00000062 (b>? AND b<?) } # Columns with names that require quotes. # do_setup_rec_test $tn.10.1 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 WHERE "b b" = ? } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); SEARCH TABLE t3 USING INDEX t3_idx_00050c52 (b b=?) } do_setup_rec_test $tn.10.2 { CREATE TABLE t3(a, "b b", c); } { SELECT * FROM t3 ORDER BY "b b" } { CREATE INDEX t3_idx_00050c52 ON t3('b b'); SCAN TABLE t3 USING INDEX t3_idx_00050c52 } # Transitive constraints # do_setup_rec_test $tn.11.1 { CREATE TABLE t5(a, b); CREATE TABLE t6(c, d); } { SELECT * FROM t5, t6 WHERE a=? AND b=c AND c=? } { CREATE INDEX t5_idx_000123a7 ON t5(a, b); CREATE INDEX t6_idx_00000063 ON t6(c); SEARCH TABLE t6 USING INDEX t6_idx_00000063 (c=?) SEARCH TABLE t5 USING COVERING INDEX t5_idx_000123a7 (a=? AND b=?) } # OR terms. # do_setup_rec_test $tn.12.1 { CREATE TABLE t7(a, b); } { SELECT * FROM t7 WHERE a=? OR b=? } { CREATE INDEX t7_idx_00000062 ON t7(b); CREATE INDEX t7_idx_00000061 ON t7(a); SEARCH TABLE t7 USING INDEX t7_idx_00000061 (a=?) SEARCH TABLE t7 USING INDEX t7_idx_00000062 (b=?) } # rowid terms. # do_setup_rec_test $tn.13.1 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE rowid=? } { (no new indexes) SEARCH TABLE t8 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.13.2 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 ORDER BY rowid } { (no new indexes) SCAN TABLE t8 } do_setup_rec_test $tn.13.3 { CREATE TABLE t8(a, b); } { SELECT * FROM t8 WHERE a=? ORDER BY rowid } { CREATE INDEX t8_idx_00000061 ON t8(a); SEARCH TABLE t8 USING INDEX t8_idx_00000061 (a=?) } # Triggers # do_setup_rec_test $tn.14 { CREATE TABLE t9(a, b, c); CREATE TABLE t10(a, b, c); ................................................................................ CREATE TRIGGER t9t AFTER INSERT ON t9 BEGIN UPDATE t10 SET a=new.a WHERE b = new.b; END; } { INSERT INTO t9 VALUES(?, ?, ?); } { CREATE INDEX t10_idx_00000062 ON t10(b); -- TRIGGER t9t SEARCH TABLE t10 USING INDEX t10_idx_00000062 (b=?) } do_setup_rec_test $tn.15 { CREATE TABLE t1(a, b); CREATE TABLE t2(c, d); WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) ................................................................................ WITH s(i) AS ( VALUES(1) UNION ALL SELECT i+1 FROM s WHERE i<100) INSERT INTO t2 SELECT (i-1)/20, (i-1)/5 FROM s; } { SELECT * FROM t2, t1 WHERE b=? AND d=? AND t2.rowid=t1.rowid } { CREATE INDEX t2_idx_00000064 ON t2(d); SEARCH TABLE t2 USING INDEX t2_idx_00000064 (d=?) SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) } do_setup_rec_test $tn.16 { CREATE TABLE t1(a, b); } { SELECT * FROM t1 WHERE b IS NOT NULL; } { (no new indexes) SCAN TABLE t1 } } proc do_candidates_test {tn sql res} { set res [squish [string trim $res]] |
Changes to ext/expert/sqlite3expert.c.
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
....
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
|
IdxHashEntry *pEntry; sqlite3_stmt *pExplain = 0; idxHashClear(&hIdx); rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr, "EXPLAIN QUERY PLAN %s", pStmt->zSql ); while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ int iSelectid = sqlite3_column_int(pExplain, 0); int iOrder = sqlite3_column_int(pExplain, 1); int iFrom = sqlite3_column_int(pExplain, 2); const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); int nDetail = STRLEN(zDetail); int i; for(i=0; i<nDetail; i++){ const char *zIdx = 0; if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){ ................................................................................ idxHashAdd(&rc, &hIdx, zSql, 0); if( rc ) goto find_indexes_out; } break; } } pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%d|%d|%d|%s\n", iSelectid, iOrder, iFrom, zDetail ); } for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey); } idxFinalize(&rc, pExplain); |
|
|
|
|
<
<
|
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
....
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
|
IdxHashEntry *pEntry; sqlite3_stmt *pExplain = 0; idxHashClear(&hIdx); rc = idxPrintfPrepareStmt(dbm, &pExplain, pzErr, "EXPLAIN QUERY PLAN %s", pStmt->zSql ); while( rc==SQLITE_OK && sqlite3_step(pExplain)==SQLITE_ROW ){ /* int iId = sqlite3_column_int(pExplain, 0); */ /* int iParent = sqlite3_column_int(pExplain, 1); */ /* int iNotUsed = sqlite3_column_int(pExplain, 2); */ const char *zDetail = (const char*)sqlite3_column_text(pExplain, 3); int nDetail = STRLEN(zDetail); int i; for(i=0; i<nDetail; i++){ const char *zIdx = 0; if( memcmp(&zDetail[i], " USING INDEX ", 13)==0 ){ ................................................................................ idxHashAdd(&rc, &hIdx, zSql, 0); if( rc ) goto find_indexes_out; } break; } } pStmt->zEQP = idxAppendText(&rc, pStmt->zEQP, "%s\n", zDetail); } for(pEntry=hIdx.pFirst; pEntry; pEntry=pEntry->pNext){ pStmt->zIdx = idxAppendText(&rc, pStmt->zIdx, "%s;\n", pEntry->zKey); } idxFinalize(&rc, pExplain); |
Changes to ext/fts5/test/fts5plan.test.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
CREATE TABLE t1(x, y); CREATE VIRTUAL TABLE f1 USING fts5(ff); } do_eqp_test 1.1 { SELECT * FROM t1, f1 WHERE f1 MATCH t1.x } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:} } do_eqp_test 1.2 { SELECT * FROM t1, f1 WHERE f1 > t1.x } { 0 0 1 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:} 0 1 0 {SCAN TABLE t1} } do_eqp_test 1.3 { SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff } { 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 65537:} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 1.4 { SELECT * FROM f1 ORDER BY rank } { 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 0:} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 1.5 { SELECT * FROM f1 WHERE rank MATCH ? } { 0 0 0 {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:} } finish_test |
> | | > | | > | | > | | < | | < < < < |
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 |
CREATE TABLE t1(x, y); CREATE VIRTUAL TABLE f1 USING fts5(ff); } do_eqp_test 1.1 { SELECT * FROM t1, f1 WHERE f1 MATCH t1.x } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537: } do_eqp_test 1.2 { SELECT * FROM t1, f1 WHERE f1 > t1.x } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: `--SCAN TABLE t1 } do_eqp_test 1.3 { SELECT * FROM f1 WHERE f1 MATCH ? ORDER BY ff } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 65537: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.4 { SELECT * FROM f1 ORDER BY rank } { QUERY PLAN |--SCAN TABLE f1 VIRTUAL TABLE INDEX 0: `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT * FROM f1 WHERE rank MATCH ? } {SCAN TABLE f1 VIRTUAL TABLE INDEX 2:} finish_test |
Changes to ext/rtree/rtree6.test.
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
do_test rtree6-1.5 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10} } {C0} do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test rtree6.2.4.1 { SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?)} } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1} 0 1 1 {SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?)} } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1<v } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 2:} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test rtree6-3.1 { CREATE VIRTUAL TABLE t3 USING rtree(id, x1, x2, y1, y2); INSERT INTO t3 VALUES(NULL, 1, 1, 2, 2); SELECT * FROM t3 WHERE x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND |
> | | > | | > | | > | | > | | > | | |
70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
do_test rtree6-1.5 { rtree_strategy {SELECT * FROM t1,t2 WHERE k=+ii AND x1<10} } {C0} do_eqp_test rtree6.2.1 { SELECT * FROM t1,t2 WHERE k=+ii AND x1<10 } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.2 { SELECT * FROM t1,t2 WHERE k=ii AND x1<10 } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0 `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.3 { SELECT * FROM t1,t2 WHERE k=ii } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2: `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test rtree6.2.4.1 { SELECT * FROM t1,t2 WHERE v=+ii and x1<10 and x2>10 } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH TABLE t2 USING AUTOMATIC COVERING INDEX (v=?) } do_eqp_test rtree6.2.4.2 { SELECT * FROM t1,t2 WHERE v=10 and x1<10 and x2>10 } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2:C0E1 `--SEARCH TABLE t2 USING AUTOMATIC PARTIAL COVERING INDEX (v=?) } do_eqp_test rtree6.2.5 { SELECT * FROM t1,t2 WHERE k=ii AND x1<v } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 2: `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test rtree6-3.1 { CREATE VIRTUAL TABLE t3 USING rtree(id, x1, x2, y1, y2); INSERT INTO t3 VALUES(NULL, 1, 1, 2, 2); SELECT * FROM t3 WHERE x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND x1>0.5 AND |
Changes to ext/rtree/rtreeC.test.
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 .. 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 ... 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 ... 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 ... 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 ... 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 |
CREATE TABLE t(x, y); } do_eqp_test 1.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 1 {SCAN TABLE t} 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 0 {SCAN TABLE t} 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { 0 0 0 {SCAN TABLE t} 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 1.5 { SELECT * FROM t, r_tree } { 0 0 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:} 0 1 0 {SCAN TABLE t} } do_execsql_test 2.0 { INSERT INTO t VALUES(0, 0); INSERT INTO t VALUES(0, 1); INSERT INTO t VALUES(0, 2); INSERT INTO t VALUES(0, 3); ................................................................................ db close sqlite3 db test.db do_eqp_test 2.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 1 {SCAN TABLE t} 0 1 0 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { 0 0 0 {SCAN TABLE t} 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { 0 0 0 {SCAN TABLE t} 0 1 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0} } do_eqp_test 2.5 { SELECT * FROM t, r_tree } { 0 0 1 {SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:} 0 1 0 {SCAN TABLE t} } #------------------------------------------------------------------------- # Test that the special CROSS JOIN handling works with rtree tables. # do_execsql_test 3.1 { CREATE TABLE t1(x); CREATE TABLE t2(y); CREATE VIRTUAL TABLE t3 USING rtree(z, x1,x2, y1,y2); } do_eqp_test 3.2.1 { SELECT * FROM t1 CROSS JOIN t2 } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE t2} } do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } { 0 0 0 {SCAN TABLE t2} 0 1 1 {SCAN TABLE t1} } do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE t3 VIRTUAL TABLE INDEX 2:} } do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } { 0 0 0 {SCAN TABLE t3 VIRTUAL TABLE INDEX 2:} 0 1 1 {SCAN TABLE t1} } #-------------------------------------------------------------------- # Test that LEFT JOINs are not reordered if the right-hand-side is # a virtual table. # reset_db ................................................................................ # First test a query with no ANALYZE data at all. The outer loop is # real table "t1". # do_eqp_test 5.2 { SELECT * FROM t1, rt WHERE x==id; } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} } # Now create enough ANALYZE data to tell SQLite that virtual table "rt" # contains very few rows. This causes it to move "rt" to the outer loop. # do_execsql_test 5.3 { ANALYZE; ................................................................................ DELETE FROM sqlite_stat1 WHERE tbl='t1'; } db close sqlite3 db test.db do_eqp_test 5.4 { SELECT * FROM t1, rt WHERE x==id; } { 0 0 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:} 0 1 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?)} } # Delete the ANALYZE data. "t1" should be the outer loop again. # do_execsql_test 5.5 { DROP TABLE sqlite_stat1; } db close sqlite3 db test.db do_eqp_test 5.6 { SELECT * FROM t1, rt WHERE x==id; } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} } # This time create and attach a database that contains ANALYZE data for # tables of the same names as those used internally by virtual table # "rt". Check that the rtree module is not fooled into using this data. # Table "t1" should remain the outer loop. # ................................................................................ db close sqlite3 db test.db execsql { ATTACH 'test.db2' AS aux; } } {} do_eqp_test 5.8 { SELECT * FROM t1, rt WHERE x==id; } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 1:} } #-------------------------------------------------------------------- # Test that having a second connection drop the sqlite_stat1 table # before it is required by rtreeConnect() does not cause problems. # ifcapable rtree { ................................................................................ INSERT INTO rt VALUES(1, 2, 7, 12, 14); -- Not a hit INSERT INTO rt VALUES(2, 2, 7, 8, 12); -- A hit! INSERT INTO rt VALUES(3, 7, 11, 8, 12); -- Not a hit! INSERT INTO rt VALUES(4, 5, 5, 10, 10); -- A hit! } proc do_eqp_execsql_test {tn sql res} { set query "EXPLAIN QUERY PLAN $sql ; $sql " uplevel [list do_execsql_test $tn $query $res] } do_eqp_execsql_test 7.1 { SELECT id FROM xdir, rt, ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 0 {SCAN TABLE xdir} 0 1 2 {SCAN TABLE ydir} 0 2 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1} 2 4 } do_eqp_execsql_test 7.2 { SELECT * FROM xdir, rt LEFT JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 0 {SCAN TABLE xdir} 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 5 1 2 7 12 14 {} 5 2 2 7 8 12 10 5 4 5 5 10 10 10 } do_eqp_execsql_test 7.3 { SELECT id FROM xdir, rt CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 0 {SCAN TABLE xdir} 0 1 1 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } do_eqp_execsql_test 7.4 { SELECT id FROM rt, xdir CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { 0 0 1 {SCAN TABLE xdir} 0 1 0 {SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1} 0 2 2 {SCAN TABLE ydir} 2 4 } finish_test |
> | | > | | > | | > | | > | | > | | > | | > | | > | | > | > > | | > | | > | | > | | > | | > | | | | | > | | | > > | | | < > > | | | > > | | | > |
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 .. 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 ... 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 ... 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 ... 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 |
CREATE TABLE t(x, y); } do_eqp_test 1.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 1.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: `--SCAN TABLE t } do_execsql_test 2.0 { INSERT INTO t VALUES(0, 0); INSERT INTO t VALUES(0, 1); INSERT INTO t VALUES(0, 2); INSERT INTO t VALUES(0, 3); ................................................................................ db close sqlite3 db test.db do_eqp_test 2.1 { SELECT * FROM r_tree, t WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.2 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND t.x<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.3 { SELECT * FROM t, r_tree WHERE t.x>=min_x AND t.x<=max_x AND t.y>=min_y AND ?<=max_y } { QUERY PLAN |--SCAN TABLE t `--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2:D3B2D1B0 } do_eqp_test 2.5 { SELECT * FROM t, r_tree } { QUERY PLAN |--SCAN TABLE r_tree VIRTUAL TABLE INDEX 2: `--SCAN TABLE t } #------------------------------------------------------------------------- # Test that the special CROSS JOIN handling works with rtree tables. # do_execsql_test 3.1 { CREATE TABLE t1(x); CREATE TABLE t2(y); CREATE VIRTUAL TABLE t3 USING rtree(z, x1,x2, y1,y2); } do_eqp_test 3.2.1 { SELECT * FROM t1 CROSS JOIN t2 } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE t2 } do_eqp_test 3.2.2 { SELECT * FROM t2 CROSS JOIN t1 } { QUERY PLAN |--SCAN TABLE t2 `--SCAN TABLE t1 } do_eqp_test 3.3.1 { SELECT * FROM t1 CROSS JOIN t3 } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: } do_eqp_test 3.3.2 { SELECT * FROM t3 CROSS JOIN t1 } { QUERY PLAN |--SCAN TABLE t3 VIRTUAL TABLE INDEX 2: `--SCAN TABLE t1 } #-------------------------------------------------------------------- # Test that LEFT JOINs are not reordered if the right-hand-side is # a virtual table. # reset_db ................................................................................ # First test a query with no ANALYZE data at all. The outer loop is # real table "t1". # do_eqp_test 5.2 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: } # Now create enough ANALYZE data to tell SQLite that virtual table "rt" # contains very few rows. This causes it to move "rt" to the outer loop. # do_execsql_test 5.3 { ANALYZE; ................................................................................ DELETE FROM sqlite_stat1 WHERE tbl='t1'; } db close sqlite3 db test.db do_eqp_test 5.4 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN TABLE rt VIRTUAL TABLE INDEX 2: `--SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (x=?) } # Delete the ANALYZE data. "t1" should be the outer loop again. # do_execsql_test 5.5 { DROP TABLE sqlite_stat1; } db close sqlite3 db test.db do_eqp_test 5.6 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: } # This time create and attach a database that contains ANALYZE data for # tables of the same names as those used internally by virtual table # "rt". Check that the rtree module is not fooled into using this data. # Table "t1" should remain the outer loop. # ................................................................................ db close sqlite3 db test.db execsql { ATTACH 'test.db2' AS aux; } } {} do_eqp_test 5.8 { SELECT * FROM t1, rt WHERE x==id; } { QUERY PLAN |--SCAN TABLE t1 `--SCAN TABLE rt VIRTUAL TABLE INDEX 1: } #-------------------------------------------------------------------- # Test that having a second connection drop the sqlite_stat1 table # before it is required by rtreeConnect() does not cause problems. # ifcapable rtree { ................................................................................ INSERT INTO rt VALUES(1, 2, 7, 12, 14); -- Not a hit INSERT INTO rt VALUES(2, 2, 7, 8, 12); -- A hit! INSERT INTO rt VALUES(3, 7, 11, 8, 12); -- Not a hit! INSERT INTO rt VALUES(4, 5, 5, 10, 10); -- A hit! } proc do_eqp_execsql_test {tn sql res1 res2} { do_eqp_test $tn.1 $sql $res1 do_execsql_test $tn.2 $sql $res2 } do_eqp_execsql_test 7.1 { SELECT id FROM xdir, rt, ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN TABLE xdir |--SCAN TABLE ydir `--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B2D3B0D1 } { 2 4 } do_eqp_execsql_test 7.2 { SELECT * FROM xdir, rt LEFT JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE ydir } { 5 1 2 7 12 14 {} 5 2 2 7 8 12 10 5 4 5 5 10 10 10 } do_eqp_execsql_test 7.3 { SELECT id FROM xdir, rt CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE ydir } { 2 4 } do_eqp_execsql_test 7.4 { SELECT id FROM rt, xdir CROSS JOIN ydir ON (y1 BETWEEN ymin AND ymax) WHERE (x1 BETWEEN xmin AND xmax); } { QUERY PLAN |--SCAN TABLE xdir |--SCAN TABLE rt VIRTUAL TABLE INDEX 2:B0D1 `--SCAN TABLE ydir } { 2 4 } finish_test |
Changes to src/expr.c.
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 .... 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 .... 2773 2774 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 |
if( aiMap ) aiMap[i] = j; } assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); if( colUsed==(MASKBIT(nExpr)-1) ){ /* If we reach this point, that means the index pIdx is usable */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); #ifndef SQLITE_OMIT_EXPLAIN sqlite3VdbeAddOp4(v, OP_Explain, 0, 0, 0, sqlite3MPrintf(db, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName), P4_DYNAMIC); #endif sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull ){ ................................................................................ ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %sLIST SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } #endif assert( !isRowid ); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ if( ALWAYS(pEList->nExpr==nVal) ){ SelectDest dest; int i; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); ................................................................................ Expr *pLimit; /* New limit expression */ testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); assert( ExprHasProperty(pExpr, EP_xIsSelect) ); #ifndef SQLITE_OMIT_EXPLAIN if( pParse->explain==2 ){ char *zMsg = sqlite3MPrintf(pParse->db, "EXECUTE %sSCALAR SUBQUERY %d", jmpIfDynamic>=0?"":"CORRELATED ", pParse->iNextSelectId ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } #endif pSel = pExpr->x.pSelect; nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; dest.iSdst = dest.iSDParm; dest.nSdst = nReg; |
| < | < < | < < | < | < < < < < | | < | < < < < < < < < |
2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 .... 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 .... 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 2775 2776 2777 2778 |
if( aiMap ) aiMap[i] = j; } assert( i==nExpr || colUsed!=(MASKBIT(nExpr)-1) ); if( colUsed==(MASKBIT(nExpr)-1) ){ /* If we reach this point, that means the index pIdx is usable */ int iAddr = sqlite3VdbeAddOp0(v, OP_Once); VdbeCoverage(v); ExplainQueryPlan((pParse, 0, "USING INDEX %s FOR IN-OPERATOR",pIdx->zName)); sqlite3VdbeAddOp3(v, OP_OpenRead, iTab, pIdx->tnum, iDb); sqlite3VdbeSetP4KeyInfo(pParse, pIdx); VdbeComment((v, "%s", pIdx->zName)); assert( IN_INDEX_INDEX_DESC == IN_INDEX_INDEX_ASC+1 ); eType = IN_INDEX_INDEX_ASC + pIdx->aSortOrder[0]; if( prRhsHasNull ){ ................................................................................ ** ** Generate code to write the results of the select into the temporary ** table allocated and opened above. */ Select *pSelect = pExpr->x.pSelect; ExprList *pEList = pSelect->pEList; ExplainQueryPlan((pParse, 1, "%sLIST SUBQUERY", jmpIfDynamic>=0?"":"CORRELATED " )); assert( !isRowid ); /* If the LHS and RHS of the IN operator do not match, that ** error will have been caught long before we reach this point. */ if( ALWAYS(pEList->nExpr==nVal) ){ SelectDest dest; int i; sqlite3SelectDestInit(&dest, SRT_Set, pExpr->iTable); ................................................................................ Expr *pLimit; /* New limit expression */ testcase( pExpr->op==TK_EXISTS ); testcase( pExpr->op==TK_SELECT ); assert( pExpr->op==TK_EXISTS || pExpr->op==TK_SELECT ); assert( ExprHasProperty(pExpr, EP_xIsSelect) ); pSel = pExpr->x.pSelect; ExplainQueryPlan((pParse, 1, "%sSCALAR SUBQUERY", jmpIfDynamic>=0?"":"CORRELATED ")); nReg = pExpr->op==TK_SELECT ? pSel->pEList->nExpr : 1; sqlite3SelectDestInit(&dest, 0, pParse->nMem+1); pParse->nMem += nReg; if( pExpr->op==TK_SELECT ){ dest.eDest = SRT_Mem; dest.iSdst = dest.iSDParm; dest.nSdst = nReg; |
Changes to src/prepare.c.
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
}
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"selectid", "order", "from", "detail"
};
int iFirst, mx;
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
iFirst = 8;
mx = 12;
}else{
|
| |
612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 |
}
rc = sParse.rc;
#ifndef SQLITE_OMIT_EXPLAIN
if( rc==SQLITE_OK && sParse.pVdbe && sParse.explain ){
static const char * const azColName[] = {
"addr", "opcode", "p1", "p2", "p3", "p4", "p5", "comment",
"id", "parent", "notused", "detail"
};
int iFirst, mx;
if( sParse.explain==2 ){
sqlite3VdbeSetNumCols(sParse.pVdbe, 4);
iFirst = 8;
mx = 12;
}else{
|
Changes to src/select.c.
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 .... 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 .... 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 .... 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 .... 2357 2358 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 .... 2402 2403 2404 2405 2406 2407 2408 2409 2410 2411 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 .... 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 .... 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 2719 2720 2721 2722 2723 2724 2725 2726 2727 2728 2729 2730 2731 2732 2733 2734 2735 2736 2737 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 .... 3072 3073 3074 3075 3076 3077 3078 3079 3080 3081 3082 3083 3084 3085 3086 3087 3088 3089 .... 3195 3196 3197 3198 3199 3200 3201 3202 3203 3204 3205 3206 3207 3208 3209 3210 3211 3212 3213 3214 3215 3216 .... 3217 3218 3219 3220 3221 3222 3223 3224 3225 3226 3227 3228 3229 3230 3231 .... 3329 3330 3331 3332 3333 3334 3335 3336 3337 3338 3339 3340 3341 3342 3343 .... 5117 5118 5119 5120 5121 5122 5123 5124 5125 5126 5127 5128 5129 5130 5131 5132 5133 5134 5135 5136 5137 5138 .... 5337 5338 5339 5340 5341 5342 5343 5344 5345 5346 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 5361 5362 5363 5364 5365 5366 .... 5389 5390 5391 5392 5393 5394 5395 5396 5397 5398 5399 5400 5401 5402 5403 5404 5405 5406 .... 5487 5488 5489 5490 5491 5492 5493 5494 5495 5496 5497 5498 5499 5500 5501 5502 5503 5504 5505 .... 5603 5604 5605 5606 5607 5608 5609 5610 5611 5612 5613 5614 5615 5616 5617 .... 5638 5639 5640 5641 5642 5643 5644 5645 5646 5647 5648 5649 5650 5651 5652 5653 5654 5655 5656 5657 .... 6281 6282 6283 6284 6285 6286 6287 6288 6289 6290 6291 6292 6293 6294 |
/* ** Trace output macros */ #if SELECTTRACE_ENABLED /***/ int sqlite3SelectTrace = 0; # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->iSelectId,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) #endif /* ................................................................................ ** ** "USE TEMP B-TREE FOR xxx" ** ** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ if( pParse->explain==2 ){ Vdbe *v = pParse->pVdbe; char *zMsg = sqlite3MPrintf(pParse->db, "USE TEMP B-TREE FOR %s", zUsage); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } } /* ** Assign expression b to lvalue a. A second, no-op, version of this macro ** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code ** in sqlite3Select() to assign values to structure member variables that ** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the ................................................................................ #else /* No-op versions of the explainXXX() functions and macros. */ # define explainTempTable(y,z) # define explainSetInteger(y,z) #endif #if !defined(SQLITE_OMIT_EXPLAIN) && !defined(SQLITE_OMIT_COMPOUND_SELECT) /* ** Unless an "EXPLAIN QUERY PLAN" command is being processed, this function ** is a no-op. Otherwise, it adds a single row of output to the EQP result, ** where the caption is of one of the two forms: ** ** "COMPOSITE SUBQUERIES iSub1 and iSub2 (op)" ** "COMPOSITE SUBQUERIES iSub1 and iSub2 USING TEMP B-TREE (op)" ** ** where iSub1 and iSub2 are the integers passed as the corresponding ** function parameters, and op is the text representation of the parameter ** of the same name. The parameter "op" must be one of TK_UNION, TK_EXCEPT, ** TK_INTERSECT or TK_ALL. The first form is used if argument bUseTmp is ** false, or the second form if it is true. */ static void explainComposite( Parse *pParse, /* Parse context */ int op, /* One of TK_UNION, TK_EXCEPT etc. */ int iSub1, /* Subquery id 1 */ int iSub2, /* Subquery id 2 */ int bUseTmp /* True if a temp table was used */ ){ assert( op==TK_UNION || op==TK_EXCEPT || op==TK_INTERSECT || op==TK_ALL ); if( pParse->explain==2 ){ Vdbe *v = pParse->pVdbe; char *zMsg = sqlite3MPrintf( pParse->db, "COMPOUND SUBQUERIES %d AND %d %s(%s)", iSub1, iSub2, bUseTmp?"USING TEMP B-TREE ":"", selectOpName(op) ); sqlite3VdbeAddOp4(v, OP_Explain, pParse->iSelectId, 0, 0, zMsg, P4_DYNAMIC); } } #else /* No-op versions of the explainXXX() functions and macros. */ # define explainComposite(v,w,x,y,z) #endif /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. */ ................................................................................ } /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Store the results of the setup-query in Queue. */ pSetup->pNext = 0; rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); ................................................................................ /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ if( p->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); }else{ p->pPrior = 0; sqlite3Select(pParse, p, &destQueue); assert( p->pPrior==0 ); p->pPrior = pSetup; } /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); ................................................................................ ** Since the limit is exactly 1, we only need to evalutes the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ Select *pPrior; Select *pRightmost = p; int nRow = 1; int rc = 0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; nRow++; }while(1); while( p ){ pPrior = p->pPrior; p->pPrior = 0; rc = sqlite3Select(pParse, p, pDest); p->pPrior = pPrior; if( rc || pRightmost->pLimit ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } /* ................................................................................ ){ int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ sqlite3 *db; /* Database connection */ #ifndef SQLITE_OMIT_EXPLAIN int iSub1 = 0; /* EQP id of left-hand query */ int iSub2 = 0; /* EQP id of right-hand query */ #endif /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); db = pParse->db; ................................................................................ }else #endif /* Compound SELECTs that have an ORDER BY clause are handled separately. */ if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest); }else /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &dest); p->pLimit = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ sqlite3VdbeAddOp3(v, OP_OffsetLimit, p->iLimit, p->iOffset+1, p->iOffset); } } explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); } break; } case TK_EXCEPT: case TK_UNION: { int unionTab; /* Cursor number of the temporary table holding result */ u8 op = 0; /* One of the SRT_ operations to apply to self */ int priorOp; /* The SRT_ operation to apply to prior selects */ Expr *pLimit; /* Saved values of p->nLimit */ int addr; SelectDest uniondest; testcase( p->op==TK_EXCEPT ); testcase( p->op==TK_UNION ); priorOp = SRT_Union; if( dest.eDest==priorOp ){ /* We can reuse a temporary table generated by a SELECT to our ** right. */ assert( p->pLimit==0 ); /* Not allowed on leftward elements */ unionTab = dest.iSDParm; }else{ /* We will need to create our own temporary table to hold the ** intermediate results. */ unionTab = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ if( p->op==TK_EXCEPT ){ op = SRT_Except; }else{ assert( p->op==TK_UNION ); op = SRT_Union; } p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; uniondest.eDest = op; explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); /* Query flattening in sqlite3Select() might refill p->pOrderBy. ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ sqlite3ExprListDelete(db, p->pOrderBy); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; if( p->op==TK_UNION ){ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } default: assert( p->op==TK_INTERSECT ); { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit; int addr; SelectDest intersectdest; int r1; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); explainSetInteger(iSub1, pParse->iNextSelectId); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; intersectdest.iSDParm = tab2; explainSetInteger(iSub2, pParse->iNextSelectId); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; if( p->nSelectRow>pPrior->nSelectRow ) p->nSelectRow = pPrior->nSelectRow; sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; /* Generate code to take the intersection of the two temporary ** tables. */ assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } } explainComposite(pParse, p->op, iSub1, iSub2, p->op!=TK_ALL); /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ................................................................................ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ int *aPermute; /* Mapping from ORDER BY terms to result set columns */ #ifndef SQLITE_OMIT_EXPLAIN int iSub1; /* EQP id of left-hand query */ int iSub2; /* EQP id of right-hand query */ #endif assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ labelEnd = sqlite3VdbeMakeLabel(v); ................................................................................ regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); pPrior->iLimit = regLimitA; explainSetInteger(iSub1, pParse->iNextSelectId); sqlite3Select(pParse, pPrior, &destA); sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ ................................................................................ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); VdbeComment((v, "right SELECT")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; p->iOffset = 0; explainSetInteger(iSub2, pParse->iNextSelectId); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; sqlite3VdbeEndCoroutine(v, regAddrB); /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. ................................................................................ sqlite3SelectDelete(db, p->pPrior); } p->pPrior = pPrior; pPrior->pNext = p; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ explainComposite(pParse, p->op, iSub1, iSub2, 0); return pParse->nErr!=0; } #endif #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* An instance of the SubstContext object describes an substitution edit ................................................................................ static void explainSimpleCount( Parse *pParse, /* Parse context */ Table *pTab, /* Table being queried */ Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); char *zEqp = sqlite3MPrintf(pParse->db, "SCAN TABLE %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); sqlite3VdbeAddOp4( pParse->pVdbe, OP_Explain, pParse->iSelectId, 0, 0, zEqp, P4_DYNAMIC ); } } #else # define explainSimpleCount(a,b,c) #endif /* ................................................................................ SortCtx sSort; /* Info on how to code the ORDER BY clause */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ u8 minMaxFlag; /* Flag for min/max queries */ #ifndef SQLITE_OMIT_EXPLAIN int iRestoreSelectId = pParse->iSelectId; pParse->iSelectId = pParse->iNextSelectId++; #endif db = pParse->db; if( p==0 || db->mallocFailed || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); #if SELECTTRACE_ENABLED #ifndef SQLITE_OMIT_EXPLAIN p->iSelectId = pParse->iSelectId; #endif SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->iSelectId)); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewSelect(0, p, 0); } #endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); ................................................................................ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x104 ){ SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif /* Get a pointer the VDBE under construction, allocating a new VDBE if one ** does not already exist */ v = sqlite3GetVdbe(pParse); if( v==0 ) goto select_end; if( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } /* Try to various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query */ ................................................................................ /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x2000)!=0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif explainSetInteger(pParse->iSelectId, iRestoreSelectId); return rc; } #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries ................................................................................ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); ................................................................................ VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); }else{ VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); } pPrior = isSelfJoinView(pTabList, pItem); if( pPrior ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); explainSetInteger(pItem->iSelectId, pPrior->iSelectId); assert( pPrior->pSelect!=0 ); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); explainSetInteger(pItem->iSelectId, (u8)pParse->iNextSelectId); sqlite3Select(pParse, pSub, &dest); } pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); ................................................................................ */ select_end: sqlite3ExprListDelete(db, pMinMaxOrderBy); sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end processing\n")); if( pParse->iSelectId==0 && (sqlite3SelectTrace & 0x2000)!=0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif explainSetInteger(pParse->iSelectId, iRestoreSelectId); return rc; } |
| < < | < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < < > > < < > | > > < < | | < < < < < | > > > > > > > | | | | | | | | | | < | | | | | | | | | | | | | | | | < > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | | | | < > > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | | | | | | | | | | | | | < > > | | | | | > > | | | | | | | | | | | | | | > | | | | | | | | | | | | < > > > | > > > < < < < > > | | | | < < < < < < < < > < < < | < < < < | | | < | | | |
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 .... 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 .... 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 .... 2283 2284 2285 2286 2287 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 .... 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 .... 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 2391 2392 2393 2394 2395 .... 2430 2431 2432 2433 2434 2435 2436 2437 2438 2439 2440 2441 2442 2443 .... 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 2588 2589 2590 2591 2592 2593 2594 2595 2596 2597 2598 2599 2600 2601 2602 2603 2604 2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 2622 2623 2624 2625 2626 2627 2628 2629 2630 2631 2632 2633 2634 2635 2636 2637 2638 2639 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 2668 2669 2670 2671 2672 2673 2674 2675 2676 2677 2678 2679 2680 2681 2682 2683 2684 2685 2686 2687 2688 2689 2690 2691 2692 2693 2694 2695 2696 2697 2698 2699 2700 2701 2702 2703 2704 2705 2706 2707 2708 2709 2710 2711 2712 2713 2714 2715 2716 2717 2718 .... 3042 3043 3044 3045 3046 3047 3048 3049 3050 3051 3052 3053 3054 3055 .... 3161 3162 3163 3164 3165 3166 3167 3168 3169 3170 3171 3172 3173 3174 3175 3176 3177 3178 3179 3180 3181 3182 3183 3184 .... 3185 3186 3187 3188 3189 3190 3191 3192 3193 3194 3195 3196 3197 3198 3199 .... 3297 3298 3299 3300 3301 3302 3303 3304 3305 3306 3307 3308 3309 3310 3311 .... 5085 5086 5087 5088 5089 5090 5091 5092 5093 5094 5095 5096 5097 5098 5099 5100 5101 5102 5103 .... 5302 5303 5304 5305 5306 5307 5308 5309 5310 5311 5312 5313 5314 5315 5316 5317 5318 5319 5320 5321 5322 5323 5324 .... 5347 5348 5349 5350 5351 5352 5353 5354 5355 5356 5357 5358 5359 5360 .... 5441 5442 5443 5444 5445 5446 5447 5448 5449 5450 5451 5452 5453 5454 5455 5456 5457 5458 5459 .... 5557 5558 5559 5560 5561 5562 5563 5564 5565 5566 5567 5568 5569 5570 5571 .... 5592 5593 5594 5595 5596 5597 5598 5599 5600 5601 5602 5603 5604 5605 5606 5607 5608 5609 5610 .... 6234 6235 6236 6237 6238 6239 6240 6241 6242 6243 6244 6245 6246 6247 |
/* ** Trace output macros */ #if SELECTTRACE_ENABLED /***/ int sqlite3SelectTrace = 0; # define SELECTTRACE(K,P,S,X) \ if(sqlite3SelectTrace&(K)) \ sqlite3DebugPrintf("%s/%d/%p: ",(S)->zSelName,(P)->addrExplain,(S)),\ sqlite3DebugPrintf X #else # define SELECTTRACE(K,P,S,X) #endif /* ................................................................................ ** ** "USE TEMP B-TREE FOR xxx" ** ** where xxx is one of "DISTINCT", "ORDER BY" or "GROUP BY". Exactly which ** is determined by the zUsage argument. */ static void explainTempTable(Parse *pParse, const char *zUsage){ ExplainQueryPlan((pParse, 0, "USE TEMP B-TREE FOR %s", zUsage)); } /* ** Assign expression b to lvalue a. A second, no-op, version of this macro ** is provided when SQLITE_OMIT_EXPLAIN is defined. This allows the code ** in sqlite3Select() to assign values to structure member variables that ** only exist if SQLITE_OMIT_EXPLAIN is not defined without polluting the ................................................................................ #else /* No-op versions of the explainXXX() functions and macros. */ # define explainTempTable(y,z) # define explainSetInteger(y,z) #endif /* ** If the inner loop was generated using a non-null pOrderBy argument, ** then the results were placed in a sorter. After the loop is terminated ** we need to run the sorter and output the results. The following ** routine generates the code needed to do that. */ ................................................................................ } /* Detach the ORDER BY clause from the compound SELECT */ p->pOrderBy = 0; /* Store the results of the setup-query in Queue. */ pSetup->pNext = 0; ExplainQueryPlan((pParse, 1, "SETUP")); rc = sqlite3Select(pParse, pSetup, &destQueue); pSetup->pNext = p; if( rc ) goto end_of_recursive_query; /* Find the next row in the Queue and output that row */ addrTop = sqlite3VdbeAddOp2(v, OP_Rewind, iQueue, addrBreak); VdbeCoverage(v); ................................................................................ /* Execute the recursive SELECT taking the single row in Current as ** the value for the recursive-table. Store the results in the Queue. */ if( p->selFlags & SF_Aggregate ){ sqlite3ErrorMsg(pParse, "recursive aggregate queries not supported"); }else{ p->pPrior = 0; ExplainQueryPlan((pParse, 1, "RECURSIVE STEP")); sqlite3Select(pParse, p, &destQueue); assert( p->pPrior==0 ); p->pPrior = pSetup; } /* Keep running the loop until the Queue is empty */ sqlite3VdbeGoto(v, addrTop); ................................................................................ ** Since the limit is exactly 1, we only need to evalutes the left-most VALUES. */ static int multiSelectValues( Parse *pParse, /* Parsing context */ Select *p, /* The right-most of SELECTs to be coded */ SelectDest *pDest /* What to do with query results */ ){ int nRow = 1; int rc = 0; int bShowAll = p->pLimit==0; assert( p->selFlags & SF_MultiValue ); do{ assert( p->selFlags & SF_Values ); assert( p->op==TK_ALL || (p->op==TK_SELECT && p->pPrior==0) ); assert( p->pNext==0 || p->pEList->nExpr==p->pNext->pEList->nExpr ); if( p->pPrior==0 ) break; assert( p->pPrior->pNext==p ); p = p->pPrior; nRow += bShowAll; }while(1); ExplainQueryPlan((pParse, 0, "SCAN %d CONSTANT ROW%s", nRow, nRow==1 ? "" : "S")); while( p ){ selectInnerLoop(pParse, p, -1, 0, 0, pDest, 1, 1); if( !bShowAll ) break; p->nSelectRow = nRow; p = p->pNext; } return rc; } /* ................................................................................ ){ int rc = SQLITE_OK; /* Success code from a subroutine */ Select *pPrior; /* Another SELECT immediately to our left */ Vdbe *v; /* Generate code to this VDBE */ SelectDest dest; /* Alternative data destination */ Select *pDelete = 0; /* Chain of simple selects to delete */ sqlite3 *db; /* Database connection */ /* Make sure there is no ORDER BY or LIMIT clause on prior SELECTs. Only ** the last (right-most) SELECT in the series may have an ORDER BY or LIMIT. */ assert( p && p->pPrior ); /* Calling function guarantees this much */ assert( (p->selFlags & SF_Recursive)==0 || p->op==TK_ALL || p->op==TK_UNION ); db = pParse->db; ................................................................................ }else #endif /* Compound SELECTs that have an ORDER BY clause are handled separately. */ if( p->pOrderBy ){ return multiSelectOrderBy(pParse, p, pDest); }else{ #ifndef SQLITE_OMIT_EXPLAIN if( pPrior->pPrior==0 ){ ExplainQueryPlan((pParse, 1, "COMPOUND QUERY")); ExplainQueryPlan((pParse, 1, "LEFT-MOST SUBQUERY")); } #endif /* Generate code for the left and right SELECT statements. */ switch( p->op ){ case TK_ALL: { int addr = 0; int nLimit; assert( !pPrior->pLimit ); pPrior->iLimit = p->iLimit; pPrior->iOffset = p->iOffset; pPrior->pLimit = p->pLimit; rc = sqlite3Select(pParse, pPrior, &dest); p->pLimit = 0; if( rc ){ goto multi_select_end; } p->pPrior = 0; p->iLimit = pPrior->iLimit; p->iOffset = pPrior->iOffset; if( p->iLimit ){ addr = sqlite3VdbeAddOp1(v, OP_IfNot, p->iLimit); VdbeCoverage(v); VdbeComment((v, "Jump ahead if LIMIT reached")); if( p->iOffset ){ sqlite3VdbeAddOp3(v, OP_OffsetLimit, p->iLimit, p->iOffset+1, p->iOffset); } } ExplainQueryPlan((pParse, 1, "UNION ALL")); rc = sqlite3Select(pParse, p, &dest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); if( pPrior->pLimit && sqlite3ExprIsInteger(pPrior->pLimit->pLeft, &nLimit) && nLimit>0 && p->nSelectRow > sqlite3LogEst((u64)nLimit) ){ p->nSelectRow = sqlite3LogEst((u64)nLimit); } if( addr ){ sqlite3VdbeJumpHere(v, addr); } break; } case TK_EXCEPT: case TK_UNION: { int unionTab; /* Cursor number of the temp table holding result */ u8 op = 0; /* One of the SRT_ operations to apply to self */ int priorOp; /* The SRT_ operation to apply to prior selects */ Expr *pLimit; /* Saved values of p->nLimit */ int addr; SelectDest uniondest; testcase( p->op==TK_EXCEPT ); testcase( p->op==TK_UNION ); priorOp = SRT_Union; if( dest.eDest==priorOp ){ /* We can reuse a temporary table generated by a SELECT to our ** right. */ assert( p->pLimit==0 ); /* Not allowed on leftward elements */ unionTab = dest.iSDParm; }else{ /* We will need to create our own temporary table to hold the ** intermediate results. */ unionTab = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, unionTab, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); } /* Code the SELECT statements to our left */ assert( !pPrior->pOrderBy ); sqlite3SelectDestInit(&uniondest, priorOp, unionTab); rc = sqlite3Select(pParse, pPrior, &uniondest); if( rc ){ goto multi_select_end; } /* Code the current SELECT statement */ if( p->op==TK_EXCEPT ){ op = SRT_Except; }else{ assert( p->op==TK_UNION ); op = SRT_Union; } p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; uniondest.eDest = op; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", selectOpName(p->op))); rc = sqlite3Select(pParse, p, &uniondest); testcase( rc!=SQLITE_OK ); /* Query flattening in sqlite3Select() might refill p->pOrderBy. ** Be sure to delete p->pOrderBy, therefore, to avoid a memory leak. */ sqlite3ExprListDelete(db, p->pOrderBy); pDelete = p->pPrior; p->pPrior = pPrior; p->pOrderBy = 0; if( p->op==TK_UNION ){ p->nSelectRow = sqlite3LogEstAdd(p->nSelectRow, pPrior->nSelectRow); } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; p->iLimit = 0; p->iOffset = 0; /* Convert the data in the temporary table into whatever form ** it is that we currently need. */ assert( unionTab==dest.iSDParm || dest.eDest!=priorOp ); if( dest.eDest!=priorOp ){ int iCont, iBreak, iStart; assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, unionTab, iBreak); VdbeCoverage(v); iStart = sqlite3VdbeCurrentAddr(v); selectInnerLoop(pParse, p, unionTab, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, unionTab, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, unionTab, 0); } break; } default: assert( p->op==TK_INTERSECT ); { int tab1, tab2; int iCont, iBreak, iStart; Expr *pLimit; int addr; SelectDest intersectdest; int r1; /* INTERSECT is different from the others since it requires ** two temporary tables. Hence it has its own case. Begin ** by allocating the tables we will need. */ tab1 = pParse->nTab++; tab2 = pParse->nTab++; assert( p->pOrderBy==0 ); addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab1, 0); assert( p->addrOpenEphm[0] == -1 ); p->addrOpenEphm[0] = addr; findRightmost(p)->selFlags |= SF_UsesEphemeral; assert( p->pEList ); /* Code the SELECTs to our left into temporary table "tab1". */ sqlite3SelectDestInit(&intersectdest, SRT_Union, tab1); rc = sqlite3Select(pParse, pPrior, &intersectdest); if( rc ){ goto multi_select_end; } /* Code the current SELECT into temporary table "tab2" */ addr = sqlite3VdbeAddOp2(v, OP_OpenEphemeral, tab2, 0); assert( p->addrOpenEphm[1] == -1 ); p->addrOpenEphm[1] = addr; p->pPrior = 0; pLimit = p->pLimit; p->pLimit = 0; intersectdest.iSDParm = tab2; ExplainQueryPlan((pParse, 1, "%s USING TEMP B-TREE", selectOpName(p->op))); rc = sqlite3Select(pParse, p, &intersectdest); testcase( rc!=SQLITE_OK ); pDelete = p->pPrior; p->pPrior = pPrior; if( p->nSelectRow>pPrior->nSelectRow ){ p->nSelectRow = pPrior->nSelectRow; } sqlite3ExprDelete(db, p->pLimit); p->pLimit = pLimit; /* Generate code to take the intersection of the two temporary ** tables. */ assert( p->pEList ); iBreak = sqlite3VdbeMakeLabel(v); iCont = sqlite3VdbeMakeLabel(v); computeLimitRegisters(pParse, p, iBreak); sqlite3VdbeAddOp2(v, OP_Rewind, tab1, iBreak); VdbeCoverage(v); r1 = sqlite3GetTempReg(pParse); iStart = sqlite3VdbeAddOp2(v, OP_RowData, tab1, r1); sqlite3VdbeAddOp4Int(v, OP_NotFound, tab2, iCont, r1, 0); VdbeCoverage(v); sqlite3ReleaseTempReg(pParse, r1); selectInnerLoop(pParse, p, tab1, 0, 0, &dest, iCont, iBreak); sqlite3VdbeResolveLabel(v, iCont); sqlite3VdbeAddOp2(v, OP_Next, tab1, iStart); VdbeCoverage(v); sqlite3VdbeResolveLabel(v, iBreak); sqlite3VdbeAddOp2(v, OP_Close, tab2, 0); sqlite3VdbeAddOp2(v, OP_Close, tab1, 0); break; } } #ifndef SQLITE_OMIT_EXPLAIN if( p->pNext==0 ){ ExplainQueryPlanPop(pParse); } #endif } /* Compute collating sequences used by ** temporary tables needed to implement the compound select. ** Attach the KeyInfo structure to all temporary tables. ** ** This section is run by the right-most SELECT statement only. ** SELECT statements to the left always skip this part. The right-most ** SELECT might also skip this part if it has no ORDER BY clause and ................................................................................ int op; /* One of TK_ALL, TK_UNION, TK_EXCEPT, TK_INTERSECT */ KeyInfo *pKeyDup = 0; /* Comparison information for duplicate removal */ KeyInfo *pKeyMerge; /* Comparison information for merging rows */ sqlite3 *db; /* Database connection */ ExprList *pOrderBy; /* The ORDER BY clause */ int nOrderBy; /* Number of terms in the ORDER BY clause */ int *aPermute; /* Mapping from ORDER BY terms to result set columns */ assert( p->pOrderBy!=0 ); assert( pKeyDup==0 ); /* "Managed" code needs this. Ticket #3382. */ db = pParse->db; v = pParse->pVdbe; assert( v!=0 ); /* Already thrown the error if VDBE alloc failed */ labelEnd = sqlite3VdbeMakeLabel(v); ................................................................................ regAddrA = ++pParse->nMem; regAddrB = ++pParse->nMem; regOutA = ++pParse->nMem; regOutB = ++pParse->nMem; sqlite3SelectDestInit(&destA, SRT_Coroutine, regAddrA); sqlite3SelectDestInit(&destB, SRT_Coroutine, regAddrB); ExplainQueryPlan((pParse, 1, "MERGE (%s)", selectOpName(p->op))); /* Generate a coroutine to evaluate the SELECT statement to the ** left of the compound operator - the "A" select. */ addrSelectA = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrA, 0, addrSelectA); VdbeComment((v, "left SELECT")); pPrior->iLimit = regLimitA; ExplainQueryPlan((pParse, 1, "LEFT")); sqlite3Select(pParse, pPrior, &destA); sqlite3VdbeEndCoroutine(v, regAddrA); sqlite3VdbeJumpHere(v, addr1); /* Generate a coroutine to evaluate the SELECT statement on ** the right - the "B" select */ ................................................................................ addrSelectB = sqlite3VdbeCurrentAddr(v) + 1; addr1 = sqlite3VdbeAddOp3(v, OP_InitCoroutine, regAddrB, 0, addrSelectB); VdbeComment((v, "right SELECT")); savedLimit = p->iLimit; savedOffset = p->iOffset; p->iLimit = regLimitB; p->iOffset = 0; ExplainQueryPlan((pParse, 1, "RIGHT")); sqlite3Select(pParse, p, &destB); p->iLimit = savedLimit; p->iOffset = savedOffset; sqlite3VdbeEndCoroutine(v, regAddrB); /* Generate a subroutine that outputs the current row of the A ** select as the next output row of the compound select. ................................................................................ sqlite3SelectDelete(db, p->pPrior); } p->pPrior = pPrior; pPrior->pNext = p; /*** TBD: Insert subroutine calls to close cursors on incomplete **** subqueries ****/ ExplainQueryPlanPop(pParse); return pParse->nErr!=0; } #endif #if !defined(SQLITE_OMIT_SUBQUERY) || !defined(SQLITE_OMIT_VIEW) /* An instance of the SubstContext object describes an substitution edit ................................................................................ static void explainSimpleCount( Parse *pParse, /* Parse context */ Table *pTab, /* Table being queried */ Index *pIdx /* Index used to optimize scan, or NULL */ ){ if( pParse->explain==2 ){ int bCover = (pIdx!=0 && (HasRowid(pTab) || !IsPrimaryKeyIndex(pIdx))); sqlite3VdbeExplain(pParse, 0, "SCAN TABLE %s%s%s", pTab->zName, bCover ? " USING COVERING INDEX " : "", bCover ? pIdx->zName : "" ); } } #else # define explainSimpleCount(a,b,c) #endif /* ................................................................................ SortCtx sSort; /* Info on how to code the ORDER BY clause */ AggInfo sAggInfo; /* Information used by aggregate queries */ int iEnd; /* Address of the end of the query */ sqlite3 *db; /* The database connection */ ExprList *pMinMaxOrderBy = 0; /* Added ORDER BY for min/max queries */ u8 minMaxFlag; /* Flag for min/max queries */ db = pParse->db; v = sqlite3GetVdbe(pParse); if( p==0 || db->mallocFailed || pParse->nErr ){ return 1; } if( sqlite3AuthCheck(pParse, SQLITE_SELECT, 0, 0, 0) ) return 1; memset(&sAggInfo, 0, sizeof(sAggInfo)); #if SELECTTRACE_ENABLED SELECTTRACE(1,pParse,p, ("begin processing:\n", pParse->addrExplain)); if( sqlite3SelectTrace & 0x100 ){ sqlite3TreeViewSelect(0, p, 0); } #endif assert( p->pOrderBy==0 || pDest->eDest!=SRT_DistFifo ); assert( p->pOrderBy==0 || pDest->eDest!=SRT_Fifo ); ................................................................................ #if SELECTTRACE_ENABLED if( sqlite3SelectTrace & 0x104 ){ SELECTTRACE(0x104,pParse,p, ("after name resolution:\n")); sqlite3TreeViewSelect(0, p, 0); } #endif if( pDest->eDest==SRT_Output ){ generateColumnNames(pParse, p); } /* Try to various optimizations (flattening subqueries, and strength ** reduction of join operators) in the FROM clause up into the main query */ ................................................................................ /* Handle compound SELECT statements using the separate multiSelect() ** procedure. */ if( p->pPrior ){ rc = multiSelect(pParse, p, pDest); #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end compound-select processing\n")); if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif if( p->pNext==0 ) ExplainQueryPlanPop(pParse); return rc; } #endif /* For each term in the FROM clause, do two things: ** (1) Authorized unreferenced tables ** (2) Generate code for all sub-queries ................................................................................ int addrTop = sqlite3VdbeCurrentAddr(v)+1; pItem->regReturn = ++pParse->nMem; sqlite3VdbeAddOp3(v, OP_InitCoroutine, pItem->regReturn, 0, addrTop); VdbeComment((v, "%s", pItem->pTab->zName)); pItem->addrFillSub = addrTop; sqlite3SelectDestInit(&dest, SRT_Coroutine, pItem->regReturn); ExplainQueryPlan((pParse, 1, "CO-ROUTINE 0x%p", pSub)); sqlite3Select(pParse, pSub, &dest); pItem->pTab->nRowLogEst = pSub->nSelectRow; pItem->fg.viaCoroutine = 1; pItem->regResult = dest.iSdst; sqlite3VdbeEndCoroutine(v, pItem->regReturn); sqlite3VdbeJumpHere(v, addrTop-1); sqlite3ClearTempRegCache(pParse); ................................................................................ VdbeComment((v, "materialize \"%s\"", pItem->pTab->zName)); }else{ VdbeNoopComment((v, "materialize \"%s\"", pItem->pTab->zName)); } pPrior = isSelfJoinView(pTabList, pItem); if( pPrior ){ sqlite3VdbeAddOp2(v, OP_OpenDup, pItem->iCursor, pPrior->iCursor); assert( pPrior->pSelect!=0 ); pSub->nSelectRow = pPrior->pSelect->nSelectRow; }else{ sqlite3SelectDestInit(&dest, SRT_EphemTab, pItem->iCursor); ExplainQueryPlan((pParse, 1, "MATERIALIZE 0x%p", pSub)); sqlite3Select(pParse, pSub, &dest); } pItem->pTab->nRowLogEst = pSub->nSelectRow; if( onceAddr ) sqlite3VdbeJumpHere(v, onceAddr); retAddr = sqlite3VdbeAddOp1(v, OP_Return, pItem->regReturn); VdbeComment((v, "end %s", pItem->pTab->zName)); sqlite3VdbeChangeP1(v, topAddr, retAddr); ................................................................................ */ select_end: sqlite3ExprListDelete(db, pMinMaxOrderBy); sqlite3DbFree(db, sAggInfo.aCol); sqlite3DbFree(db, sAggInfo.aFunc); #if SELECTTRACE_ENABLED SELECTTRACE(0x1,pParse,p,("end processing\n")); if( (sqlite3SelectTrace & 0x2000)!=0 && ExplainQueryPlanParent(pParse)==0 ){ sqlite3TreeViewSelect(0, p, 0); } #endif ExplainQueryPlanPop(pParse); return rc; } |
Changes to src/shell.c.in.
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 ... 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 .... 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 .... 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 .... 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 1735 1736 1737 1738 1739 1740 1741 1742 1743 1744 1745 .... 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 .... 2952 2953 2954 2955 2956 2957 2958 2959 2960 2961 2962 2963 2964 2965 2966 2967 2968 .... 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 5922 5923 5924 5925 5926 5927 |
sqlite3expert *pExpert; int bVerbose; }; /* A single line in the EQP output */ typedef struct EQPGraphRow EQPGraphRow; struct EQPGraphRow { int iSelectId; /* The SelectID for this row */ EQPGraphRow *pNext; /* Next row in sequence */ char zText[1]; /* Text to display for this row */ }; /* All EQP output is collected into an instance of the following */ typedef struct EQPGraph EQPGraph; struct EQPGraph { ................................................................................ ** instance of the following structure. */ typedef struct ShellState ShellState; struct ShellState { sqlite3 *db; /* The database */ u8 autoExplain; /* Automatically turn on .explain mode */ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ u8 statsOn; /* True to display memory stats before each finalize */ u8 scanstatsOn; /* True to display scan stats before each finalize */ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ int outCount; /* Revert to stdout when reaching zero */ ................................................................................ #endif ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; /* Allowed values for ShellState.autoEQP */ #define AUTOEQP_off 0 #define AUTOEQP_on 1 #define AUTOEQP_trigger 2 #define AUTOEQP_full 3 /* Allowed values for ShellState.openMode */ #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ #define SHELL_OPEN_NORMAL 1 /* Normal database file */ #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ ................................................................................ } return 1; } /* ** Add a new entry to the EXPLAIN QUERY PLAN data */ static void eqp_append(ShellState *p, int iSelectId, const char *zText){ EQPGraphRow *pNew; int nText = strlen30(zText); pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); if( pNew==0 ) shell_out_of_memory(); pNew->iSelectId = iSelectId; memcpy(pNew->zText, zText, nText+1); pNew->pNext = 0; if( p->sGraph.pLast ){ p->sGraph.pLast->pNext = pNew; }else{ p->sGraph.pRow = pNew; } ................................................................................ for(pRow = p->sGraph.pRow; pRow; pRow = pNext){ pNext = pRow->pNext; sqlite3_free(pRow); } memset(&p->sGraph, 0, sizeof(p->sGraph)); } /* Return the next EXPLAIN QUERY PLAN line with iSelectId that occurs after ** pOld, or return the first such line if pOld is NULL */ static EQPGraphRow *eqp_next_row(ShellState *p, int iSelectId, EQPGraphRow *pOld){ EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow; while( pRow && pRow->iSelectId!=iSelectId ) pRow = pRow->pNext; return pRow; } /* Render a single level of the graph shell having iSelectId. Called ** recursively to render sublevels. */ static void eqp_render_level(ShellState *p, int iSelectId){ EQPGraphRow *pRow, *pNext; int i; int n = strlen30(p->sGraph.zPrefix); char *z; for(pRow = eqp_next_row(p, iSelectId, 0); pRow; pRow = pNext){ pNext = eqp_next_row(p, iSelectId, pRow); z = pRow->zText; utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z); if( n<sizeof(p->sGraph.zPrefix)-7 && (z = strstr(z, " SUBQUER"))!=0 ){ memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); if( strncmp(z, " SUBQUERY ", 9)==0 && (i = atoi(z+10))>iSelectId ){ eqp_render_level(p, i); }else if( strncmp(z, " SUBQUERIES ", 12)==0 ){ i = atoi(z+12); if( i>iSelectId ){ utf8_printf(p->out, "%s|--SUBQUERY %d\n", p->sGraph.zPrefix, i); memcpy(&p->sGraph.zPrefix[n+3],"| ",4); eqp_render_level(p, i); } z = strstr(z, " AND "); if( z && (i = atoi(z+5))>iSelectId ){ p->sGraph.zPrefix[n+3] = 0; utf8_printf(p->out, "%s`--SUBQUERY %d\n", p->sGraph.zPrefix, i); memcpy(&p->sGraph.zPrefix[n+3]," ",4); eqp_render_level(p, i); } } p->sGraph.zPrefix[n] = 0; } } } /* ** Display and reset the EXPLAIN QUERY PLAN data ................................................................................ if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); } utf8_printf(p->out, "%s", p->rowSeparator); break; } case MODE_EQP: { eqp_append(p, atoi(azArg[0]), azArg[3]); break; } } return 0; } /* ................................................................................ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0); } zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3); int iSelectId = sqlite3_column_int(pExplain, 0); if( zEQPLine[0]=='-' ) eqp_render(pArg); eqp_append(pArg, iSelectId, zEQPLine); } eqp_render(pArg); } sqlite3_finalize(pExplain); sqlite3_free(zEQP); if( pArg->autoEQP>=AUTOEQP_full ){ /* Also do an EXPLAIN for ".eqp full" mode */ ................................................................................ raw_printf(stderr, "Usage: .echo on|off\n"); rc = 1; } }else if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ if( nArg==2 ){ if( strcmp(azArg[1],"full")==0 ){ p->autoEQP = AUTOEQP_full; }else if( strcmp(azArg[1],"trigger")==0 ){ p->autoEQP = AUTOEQP_trigger; }else{ p->autoEQP = (u8)booleanValue(azArg[1]); } }else{ raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n"); rc = 1; } |
| > > | | | | | > > > < > > | | | | | < | | | < | < < < < < < < < < < < < < < < | | > | > > > > |
977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 .... 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 .... 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 .... 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 .... 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732 1733 1734 .... 2099 2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 .... 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 .... 5900 5901 5902 5903 5904 5905 5906 5907 5908 5909 5910 5911 5912 5913 5914 5915 5916 5917 5918 5919 5920 5921 |
sqlite3expert *pExpert; int bVerbose; }; /* A single line in the EQP output */ typedef struct EQPGraphRow EQPGraphRow; struct EQPGraphRow { int iEqpId; /* ID for this row */ int iParentId; /* ID of the parent row */ EQPGraphRow *pNext; /* Next row in sequence */ char zText[1]; /* Text to display for this row */ }; /* All EQP output is collected into an instance of the following */ typedef struct EQPGraph EQPGraph; struct EQPGraph { ................................................................................ ** instance of the following structure. */ typedef struct ShellState ShellState; struct ShellState { sqlite3 *db; /* The database */ u8 autoExplain; /* Automatically turn on .explain mode */ u8 autoEQP; /* Run EXPLAIN QUERY PLAN prior to seach SQL stmt */ u8 autoEQPtest; /* autoEQP is in test mode */ u8 statsOn; /* True to display memory stats before each finalize */ u8 scanstatsOn; /* True to display scan stats before each finalize */ u8 openMode; /* SHELL_OPEN_NORMAL, _APPENDVFS, or _ZIPFILE */ u8 doXdgOpen; /* Invoke start/open/xdg-open in output_reset() */ u8 nEqpLevel; /* Depth of the EQP output graph */ unsigned mEqpLines; /* Mask of veritical lines in the EQP output graph */ int outCount; /* Revert to stdout when reaching zero */ ................................................................................ #endif ExpertInfo expert; /* Valid if previous command was ".expert OPT..." */ }; /* Allowed values for ShellState.autoEQP */ #define AUTOEQP_off 0 /* Automatic EXPLAIN QUERY PLAN is off */ #define AUTOEQP_on 1 /* Automatic EQP is on */ #define AUTOEQP_trigger 2 /* On and also show plans for triggers */ #define AUTOEQP_full 3 /* Show full EXPLAIN */ /* Allowed values for ShellState.openMode */ #define SHELL_OPEN_UNSPEC 0 /* No open-mode specified */ #define SHELL_OPEN_NORMAL 1 /* Normal database file */ #define SHELL_OPEN_APPENDVFS 2 /* Use appendvfs */ #define SHELL_OPEN_ZIPFILE 3 /* Use the zipfile virtual table */ ................................................................................ } return 1; } /* ** Add a new entry to the EXPLAIN QUERY PLAN data */ static void eqp_append(ShellState *p, int iEqpId, int p2, const char *zText){ EQPGraphRow *pNew; int nText = strlen30(zText); if( p->autoEQPtest ){ utf8_printf(p->out, "%d,%d,%s\n", iEqpId, p2, zText); } pNew = sqlite3_malloc64( sizeof(*pNew) + nText ); if( pNew==0 ) shell_out_of_memory(); pNew->iEqpId = iEqpId; pNew->iParentId = p2; memcpy(pNew->zText, zText, nText+1); pNew->pNext = 0; if( p->sGraph.pLast ){ p->sGraph.pLast->pNext = pNew; }else{ p->sGraph.pRow = pNew; } ................................................................................ for(pRow = p->sGraph.pRow; pRow; pRow = pNext){ pNext = pRow->pNext; sqlite3_free(pRow); } memset(&p->sGraph, 0, sizeof(p->sGraph)); } /* Return the next EXPLAIN QUERY PLAN line with iEqpId that occurs after ** pOld, or return the first such line if pOld is NULL */ static EQPGraphRow *eqp_next_row(ShellState *p, int iEqpId, EQPGraphRow *pOld){ EQPGraphRow *pRow = pOld ? pOld->pNext : p->sGraph.pRow; while( pRow && pRow->iParentId!=iEqpId ) pRow = pRow->pNext; return pRow; } /* Render a single level of the graph that has iEqpId as its parent. Called ** recursively to render sublevels. */ static void eqp_render_level(ShellState *p, int iEqpId){ EQPGraphRow *pRow, *pNext; int n = strlen30(p->sGraph.zPrefix); char *z; for(pRow = eqp_next_row(p, iEqpId, 0); pRow; pRow = pNext){ pNext = eqp_next_row(p, iEqpId, pRow); z = pRow->zText; utf8_printf(p->out, "%s%s%s\n", p->sGraph.zPrefix, pNext ? "|--" : "`--", z); if( n<sizeof(p->sGraph.zPrefix)-7 ){ memcpy(&p->sGraph.zPrefix[n], pNext ? "| " : " ", 4); eqp_render_level(p, pRow->iEqpId); p->sGraph.zPrefix[n] = 0; } } } /* ** Display and reset the EXPLAIN QUERY PLAN data ................................................................................ if( i>0 ) utf8_printf(p->out, "%s", p->colSeparator); utf8_printf(p->out,"%s",azArg[i] ? azArg[i] : p->nullValue); } utf8_printf(p->out, "%s", p->rowSeparator); break; } case MODE_EQP: { eqp_append(p, atoi(azArg[0]), atoi(azArg[1]), azArg[3]); break; } } return 0; } /* ................................................................................ sqlite3_db_config(db, SQLITE_DBCONFIG_TRIGGER_EQP, 1, 0); } zEQP = sqlite3_mprintf("EXPLAIN QUERY PLAN %s", zStmtSql); rc = sqlite3_prepare_v2(db, zEQP, -1, &pExplain, 0); if( rc==SQLITE_OK ){ while( sqlite3_step(pExplain)==SQLITE_ROW ){ const char *zEQPLine = (const char*)sqlite3_column_text(pExplain,3); int iEqpId = sqlite3_column_int(pExplain, 0); int iParentId = sqlite3_column_int(pExplain, 1); if( zEQPLine[0]=='-' ) eqp_render(pArg); eqp_append(pArg, iEqpId, iParentId, zEQPLine); } eqp_render(pArg); } sqlite3_finalize(pExplain); sqlite3_free(zEQP); if( pArg->autoEQP>=AUTOEQP_full ){ /* Also do an EXPLAIN for ".eqp full" mode */ ................................................................................ raw_printf(stderr, "Usage: .echo on|off\n"); rc = 1; } }else if( c=='e' && strncmp(azArg[0], "eqp", n)==0 ){ if( nArg==2 ){ p->autoEQPtest = 0; if( strcmp(azArg[1],"full")==0 ){ p->autoEQP = AUTOEQP_full; }else if( strcmp(azArg[1],"trigger")==0 ){ p->autoEQP = AUTOEQP_trigger; }else if( strcmp(azArg[1],"test")==0 ){ p->autoEQP = AUTOEQP_on; p->autoEQPtest = 1; }else{ p->autoEQP = (u8)booleanValue(azArg[1]); } }else{ raw_printf(stderr, "Usage: .eqp off|on|trigger|full\n"); rc = 1; } |
Changes to src/sqliteInt.h.
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 2619 2620 2621 .... 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 2790 2791 2792 2793 .... 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 2831 2832 2833 2834 2835 .... 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 3101 3102 3103 3104 3105 3106 |
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ } fg; #ifndef SQLITE_OMIT_EXPLAIN u8 iSelectId; /* If pSelect!=0, the id of the sub-select in EQP */ #endif int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ ................................................................................ ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ #if SELECTTRACE_ENABLED char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ u32 iSelectId; /* EXPLAIN QUERY PLAN select ID */ #endif int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ ................................................................................ #define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ #define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ #define SF_ComplexResult 0x40000 /* Result set contains subquery or function */ /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** ** SRT_Union Store results as a key in a temporary index ................................................................................ u8 explain; /* True if the EXPLAIN flag is found on the query */ #ifndef SQLITE_OMIT_VIRTUALTABLE u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int iSelectId; /* ID of current select for EXPLAIN output */ int iNextSelectId; /* Next available select ID for EXPLAIN output */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ |
< < < < | < | < |
2605 2606 2607 2608 2609 2610 2611 2612 2613 2614 2615 2616 2617 2618 .... 2776 2777 2778 2779 2780 2781 2782 2783 2784 2785 2786 2787 2788 2789 .... 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829 2830 .... 3086 3087 3088 3089 3090 3091 3092 3093 3094 3095 3096 3097 3098 3099 3100 |
unsigned notIndexed :1; /* True if there is a NOT INDEXED clause */ unsigned isIndexedBy :1; /* True if there is an INDEXED BY clause */ unsigned isTabFunc :1; /* True if table-valued-function syntax */ unsigned isCorrelated :1; /* True if sub-query is correlated */ unsigned viaCoroutine :1; /* Implemented as a co-routine */ unsigned isRecursive :1; /* True for recursive reference in WITH */ } fg; int iCursor; /* The VDBE cursor number used to access this table */ Expr *pOn; /* The ON clause of a join */ IdList *pUsing; /* The USING clause of a join */ Bitmask colUsed; /* Bit N (1<<N) set if column N of pTab is used */ union { char *zIndexedBy; /* Identifier from "INDEXED BY <zIndex>" clause */ ExprList *pFuncArg; /* Arguments to table-valued-function */ ................................................................................ ExprList *pEList; /* The fields of the result */ u8 op; /* One of: TK_UNION TK_ALL TK_INTERSECT TK_EXCEPT */ LogEst nSelectRow; /* Estimated number of result rows */ u32 selFlags; /* Various SF_* values */ int iLimit, iOffset; /* Memory registers holding LIMIT & OFFSET counters */ #if SELECTTRACE_ENABLED char zSelName[12]; /* Symbolic name of this SELECT use for debugging */ #endif int addrOpenEphm[2]; /* OP_OpenEphem opcodes related to this select */ SrcList *pSrc; /* The FROM clause */ Expr *pWhere; /* The WHERE clause */ ExprList *pGroupBy; /* The GROUP BY clause */ Expr *pHaving; /* The HAVING clause */ ExprList *pOrderBy; /* The ORDER BY clause */ ................................................................................ #define SF_NestedFrom 0x00800 /* Part of a parenthesized FROM clause */ #define SF_MinMaxAgg 0x01000 /* Aggregate containing min() or max() */ #define SF_Recursive 0x02000 /* The recursive part of a recursive CTE */ #define SF_FixedLimit 0x04000 /* nSelectRow set by a constant LIMIT */ #define SF_MaybeConvert 0x08000 /* Need convertCompoundSelectToSubquery() */ #define SF_Converted 0x10000 /* By convertCompoundSelectToSubquery() */ #define SF_IncludeHidden 0x20000 /* Include hidden columns in output */ #define SF_ComplexResult 0x40000 /* Result contains subquery or function */ /* ** The results of a SELECT can be distributed in several ways, as defined ** by one of the following macros. The "SRT" prefix means "SELECT Result ** Type". ** ** SRT_Union Store results as a key in a temporary index ................................................................................ u8 explain; /* True if the EXPLAIN flag is found on the query */ #ifndef SQLITE_OMIT_VIRTUALTABLE u8 declareVtab; /* True if inside sqlite3_declare_vtab() */ int nVtabLock; /* Number of virtual tables to lock */ #endif int nHeight; /* Expression tree height of current sub-select */ #ifndef SQLITE_OMIT_EXPLAIN int addrExplain; /* Address of current OP_Explain opcode */ #endif VList *pVList; /* Mapping between variable names and numbers */ Vdbe *pReprepare; /* VM being reprepared (sqlite3Reprepare()) */ const char *zTail; /* All SQL text past the last semicolon parsed */ Table *pNewTable; /* A table being constructed by CREATE TABLE */ Trigger *pNewTrigger; /* Trigger under construct by a CREATE TRIGGER */ const char *zAuthContext; /* The 6th parameter to db->xAuth callbacks */ |
Changes to src/treeview.c.
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ #if SELECTTRACE_ENABLED sqlite3TreeViewLine(pView, "SELECT%s%s (%s/%d/%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p->zSelName, p->iSelectId, p, p->selFlags, (int)p->nSelectRow ); #else sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, (int)p->nSelectRow |
| | |
137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
sqlite3TreeViewWith(pView, p->pWith, 1); cnt = 1; sqlite3TreeViewPush(pView, 1); } do{ #if SELECTTRACE_ENABLED sqlite3TreeViewLine(pView, "SELECT%s%s (%s/%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p->zSelName, p, p->selFlags, (int)p->nSelectRow ); #else sqlite3TreeViewLine(pView, "SELECT%s%s (0x%p) selFlags=0x%x nSelectRow=%d", ((p->selFlags & SF_Distinct) ? " DISTINCT" : ""), ((p->selFlags & SF_Aggregate) ? " agg_flag" : ""), p, p->selFlags, (int)p->nSelectRow |
Changes to src/vdbe.h.
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 |
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS)
void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N);
void sqlite3VdbeVerifyNoResultRow(Vdbe *p);
#else
# define sqlite3VdbeVerifyNoMallocRequired(A,B)
# define sqlite3VdbeVerifyNoResultRow(A)
#endif
VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp, int iLineno);
void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*);
void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8);
void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1);
void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2);
void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3);
void sqlite3VdbeChangeP5(Vdbe*, u16 P5);
void sqlite3VdbeJumpHere(Vdbe*, int addr);
|
| > > > > > > > > > > > > |
193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 |
#if defined(SQLITE_DEBUG) && !defined(SQLITE_TEST_REALLOC_STRESS) void sqlite3VdbeVerifyNoMallocRequired(Vdbe *p, int N); void sqlite3VdbeVerifyNoResultRow(Vdbe *p); #else # define sqlite3VdbeVerifyNoMallocRequired(A,B) # define sqlite3VdbeVerifyNoResultRow(A) #endif VdbeOp *sqlite3VdbeAddOpList(Vdbe*, int nOp, VdbeOpList const *aOp,int iLineno); #ifndef SQLITE_OMIT_EXPLAIN void sqlite3VdbeExplain(Parse*,u8,const char*,...); void sqlite3VdbeExplainPop(Parse*); int sqlite3VdbeExplainParent(Parse*); # define ExplainQueryPlan(P) sqlite3VdbeExplain P # define ExplainQueryPlanPop(P) sqlite3VdbeExplainPop(P) # define ExplainQueryPlanParent(P) sqlite3VdbeExplainParent(P) #else # define ExplainQueryPlan(P) # define ExplainQueryPlanPop(P) # define ExplainQueryPlanParent(P) 0 #endif void sqlite3VdbeAddParseSchemaOp(Vdbe*,int,char*); void sqlite3VdbeChangeOpcode(Vdbe*, u32 addr, u8); void sqlite3VdbeChangeP1(Vdbe*, u32 addr, int P1); void sqlite3VdbeChangeP2(Vdbe*, u32 addr, int P2); void sqlite3VdbeChangeP3(Vdbe*, u32 addr, int P3); void sqlite3VdbeChangeP5(Vdbe*, u16 P5); void sqlite3VdbeJumpHere(Vdbe*, int addr); |
Changes to src/vdbeaux.c.
299 300 301 302 303 304 305 306 307 308 309 310 311 312 |
int p4type /* P4 operand type */ ){ char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); if( p4copy ) memcpy(p4copy, zP4, 8); return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > |
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 |
int p4type /* P4 operand type */ ){ char *p4copy = sqlite3DbMallocRawNN(sqlite3VdbeDb(p), 8); if( p4copy ) memcpy(p4copy, zP4, 8); return sqlite3VdbeAddOp4(p, op, p1, p2, p3, p4copy, p4type); } #ifndef SQLITE_OMIT_EXPLAIN /* ** Return the address of the current EXPLAIN QUERY PLAN baseline. ** 0 means "none". */ int sqlite3VdbeExplainParent(Parse *pParse){ VdbeOp *pOp; if( pParse->addrExplain==0 ) return 0; pOp = sqlite3VdbeGetOp(pParse->pVdbe, pParse->addrExplain); return pOp->p2; } /* ** Add a new OP_Explain opcode. ** ** If the bPush flag is true, then make this opcode the parent for ** subsequent Explains until sqlite3VdbeExplainPop() is called. */ void sqlite3VdbeExplain(Parse *pParse, u8 bPush, const char *zFmt, ...){ if( pParse->explain==2 ){ char *zMsg; Vdbe *v = pParse->pVdbe; va_list ap; int iThis; va_start(ap, zFmt); zMsg = sqlite3VMPrintf(pParse->db, zFmt, ap); va_end(ap); v = pParse->pVdbe; iThis = v->nOp; sqlite3VdbeAddOp4(v, OP_Explain, iThis, pParse->addrExplain, 0, zMsg, P4_DYNAMIC); if( bPush) pParse->addrExplain = iThis; } } /* ** Pop the EXPLAIN QUERY PLAN stack one level. */ void sqlite3VdbeExplainPop(Parse *pParse){ pParse->addrExplain = sqlite3VdbeExplainParent(pParse); } #endif /* SQLITE_OMIT_EXPLAIN */ /* ** Add an OP_ParseSchema opcode. This routine is broken out from ** sqlite3VdbeAddOp4() since it needs to also needs to mark all btrees ** as having been used. ** ** The zWhere string must have been obtained from sqlite3_malloc(). ** This routine will take ownership of the allocated memory. |
Changes to src/where.c.
4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 |
/* Special case: No FROM clause */ if( nTabList==0 ){ if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr; if( wctrlFlags & WHERE_WANT_DISTINCT ){ pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE; } }else{ /* Assign a bit from the bitmask to every term in the FROM clause. ** ** The N-th term of the FROM clause is assigned a bitmask of 1<<N. ** ** The rule of the previous sentence ensures thta if X is the bitmask for ** a table T, then X-1 is the bitmask for all other tables to the left of T. |
> |
4588 4589 4590 4591 4592 4593 4594 4595 4596 4597 4598 4599 4600 4601 4602 |
/* Special case: No FROM clause
*/
if( nTabList==0 ){
if( pOrderBy ) pWInfo->nOBSat = pOrderBy->nExpr;
if( wctrlFlags & WHERE_WANT_DISTINCT ){
pWInfo->eDistinct = WHERE_DISTINCT_UNIQUE;
}
ExplainQueryPlan((pParse, 0, "SCAN CONSTANT ROW"));
}else{
/* Assign a bit from the bitmask to every term in the FROM clause.
**
** The N-th term of the FROM clause is assigned a bitmask of 1<<N.
**
** The rule of the previous sentence ensures thta if X is the bitmask for
** a table T, then X-1 is the bitmask for all other tables to the left of T.
|
Changes to src/wherecode.c.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 ... 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 ... 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int iId = pParse->iSelectId; /* Select id (left-most output column) */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ ................................................................................ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, " SUBQUERY %d", pItem->iSelectId); }else{ sqlite3XPrintf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&str, " AS %s", pItem->zAlias); } ................................................................................ if( pLoop->nOut>=10 ){ sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, iId, iLevel, iFrom, zMsg,P4_DYNAMIC); } return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* |
< | | > |
130 131 132 133 134 135 136 137 138 139 140 141 142 143 ... 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 ... 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 |
#if !defined(SQLITE_DEBUG) && !defined(SQLITE_ENABLE_STMT_SCANSTATUS) if( sqlite3ParseToplevel(pParse)->explain==2 ) #endif { struct SrcList_item *pItem = &pTabList->a[pLevel->iFrom]; Vdbe *v = pParse->pVdbe; /* VM being constructed */ sqlite3 *db = pParse->db; /* Database handle */ int isSearch; /* True for a SEARCH. False for SCAN. */ WhereLoop *pLoop; /* The controlling WhereLoop object */ u32 flags; /* Flags that describe this loop */ char *zMsg; /* Text to add to EQP output */ StrAccum str; /* EQP output string */ char zBuf[100]; /* Initial space for EQP output string */ ................................................................................ isSearch = (flags&(WHERE_BTM_LIMIT|WHERE_TOP_LIMIT))!=0 || ((flags&WHERE_VIRTUALTABLE)==0 && (pLoop->u.btree.nEq>0)) || (wctrlFlags&(WHERE_ORDERBY_MIN|WHERE_ORDERBY_MAX)); sqlite3StrAccumInit(&str, db, zBuf, sizeof(zBuf), SQLITE_MAX_LENGTH); sqlite3StrAccumAppendAll(&str, isSearch ? "SEARCH" : "SCAN"); if( pItem->pSelect ){ sqlite3XPrintf(&str, " SUBQUERY 0x%p", pItem->pSelect); }else{ sqlite3XPrintf(&str, " TABLE %s", pItem->zName); } if( pItem->zAlias ){ sqlite3XPrintf(&str, " AS %s", pItem->zAlias); } ................................................................................ if( pLoop->nOut>=10 ){ sqlite3XPrintf(&str, " (~%llu rows)", sqlite3LogEstToInt(pLoop->nOut)); }else{ sqlite3StrAccumAppend(&str, " (~1 row)", 9); } #endif zMsg = sqlite3StrAccumFinish(&str); ret = sqlite3VdbeAddOp4(v, OP_Explain, sqlite3VdbeCurrentAddr(v), pParse->addrExplain, 0, zMsg,P4_DYNAMIC); } return ret; } #endif /* SQLITE_OMIT_EXPLAIN */ #ifdef SQLITE_ENABLE_STMT_SCANSTATUS /* |
Changes to test/analyze3.test.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 ... 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 ... 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 ... 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 ... 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# The first of the following two SELECT statements visits 99 rows. So # it is better to use the index. But the second visits every row in # the table (1000 in total) so it is better to do a full-table scan. # do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} do_eqp_test analyze3-1.1.3 { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } {0 0 0 {SCAN TABLE t1}} # 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables # the use of bound parameters by STAT4 # db cache flush unset -nocomplain l unset -nocomplain u do_eqp_test analyze3-1.1.3.100 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} set l 200 set u 300 do_eqp_test analyze3-1.1.3.101 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} set l 0 set u 1100 do_eqp_test analyze3-1.1.3.102 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {0 0 0 {SCAN TABLE t1}} db cache flush sqlite3_db_config db ENABLE_QPSG 1 do_eqp_test analyze3-1.1.3.103 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)}} db cache flush sqlite3_db_config db ENABLE_QPSG 0 do_eqp_test analyze3-1.1.3.104 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {0 0 0 {SCAN TABLE t1}} do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.1.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] ................................................................................ } {} do_execsql_test analyze3-2.1.x { SELECT count(*) FROM t2 WHERE x>1 AND x<2; SELECT count(*) FROM t2 WHERE x>0 AND x<99; } {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 } {0 0 0 {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)}} do_eqp_test analyze3-1.2.3 { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } {0 0 0 {SCAN TABLE t2}} do_test analyze3-1.2.4 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } } {161 0 4760} do_test analyze3-1.2.5 { set l [string range "12" 0 end] set u [string range "20" 0 end] ................................................................................ } {} do_execsql_test analyze3-1.3.x { SELECT count(*) FROM t3 WHERE x>200 AND x<300; SELECT count(*) FROM t3 WHERE x>0 AND x<1100 } {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } {0 0 0 {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)}} do_eqp_test analyze3-1.3.3 { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } {0 0 0 {SCAN TABLE t3}} do_test analyze3-1.3.4 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.3.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] ................................................................................ append t [lindex {a b c d e f g h i j} [expr ($i%10)]] execsql { INSERT INTO t1 VALUES($i, $t) } } execsql COMMIT } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)}} do_eqp_test analyze3-2.3 { SELECT count(a) FROM t1 WHERE b LIKE '%a' } {0 0 0 {SCAN TABLE t1}} # Return the first argument if like_match_blobs is true (the default) # or the second argument if not # proc ilmb {a b} { ifcapable like_match_blobs {return $a} return $b ................................................................................ } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} do_eqp_test analyze3-6-2 { SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)}} #----------------------------------------------------------------------------- # 2015-04-20. # Memory leak in sqlite3Stat4ProbeFree(). (Discovered while fuzzing.) # do_execsql_test analyze-7.1 { DROP TABLE IF EXISTS t1; |
| | | | | | | | | | | | | | | |
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 ... 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 ... 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 ... 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 ... 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 |
# The first of the following two SELECT statements visits 99 rows. So # it is better to use the index. But the second visits every row in # the table (1000 in total) so it is better to do a full-table scan. # do_eqp_test analyze3-1.1.2 { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)} do_eqp_test analyze3-1.1.3 { SELECT sum(y) FROM t1 WHERE x>0 AND x<1100 } {SCAN TABLE t1} # 2017-06-26: Verify that the SQLITE_DBCONFIG_ENABLE_QPSG setting disables # the use of bound parameters by STAT4 # db cache flush unset -nocomplain l unset -nocomplain u do_eqp_test analyze3-1.1.3.100 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)} set l 200 set u 300 do_eqp_test analyze3-1.1.3.101 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)} set l 0 set u 1100 do_eqp_test analyze3-1.1.3.102 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SCAN TABLE t1} db cache flush sqlite3_db_config db ENABLE_QPSG 1 do_eqp_test analyze3-1.1.3.103 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SEARCH TABLE t1 USING INDEX i1 (x>? AND x<?)} db cache flush sqlite3_db_config db ENABLE_QPSG 0 do_eqp_test analyze3-1.1.3.104 { SELECT sum(y) FROM t1 WHERE x>$l AND x<$u } {SCAN TABLE t1} do_test analyze3-1.1.4 { sf_execsql { SELECT sum(y) FROM t1 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.1.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] ................................................................................ } {} do_execsql_test analyze3-2.1.x { SELECT count(*) FROM t2 WHERE x>1 AND x<2; SELECT count(*) FROM t2 WHERE x>0 AND x<99; } {200 990} do_eqp_test analyze3-1.2.2 { SELECT sum(y) FROM t2 WHERE x>1 AND x<2 } {SEARCH TABLE t2 USING INDEX i2 (x>? AND x<?)} do_eqp_test analyze3-1.2.3 { SELECT sum(y) FROM t2 WHERE x>0 AND x<99 } {SCAN TABLE t2} do_test analyze3-1.2.4 { sf_execsql { SELECT sum(y) FROM t2 WHERE x>12 AND x<20 } } {161 0 4760} do_test analyze3-1.2.5 { set l [string range "12" 0 end] set u [string range "20" 0 end] ................................................................................ } {} do_execsql_test analyze3-1.3.x { SELECT count(*) FROM t3 WHERE x>200 AND x<300; SELECT count(*) FROM t3 WHERE x>0 AND x<1100 } {99 1000} do_eqp_test analyze3-1.3.2 { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } {SEARCH TABLE t3 USING INDEX i3 (x>? AND x<?)} do_eqp_test analyze3-1.3.3 { SELECT sum(y) FROM t3 WHERE x>0 AND x<1100 } {SCAN TABLE t3} do_test analyze3-1.3.4 { sf_execsql { SELECT sum(y) FROM t3 WHERE x>200 AND x<300 } } {199 0 14850} do_test analyze3-1.3.5 { set l [string range "200" 0 end] set u [string range "300" 0 end] ................................................................................ append t [lindex {a b c d e f g h i j} [expr ($i%10)]] execsql { INSERT INTO t1 VALUES($i, $t) } } execsql COMMIT } {} do_eqp_test analyze3-2.2 { SELECT count(a) FROM t1 WHERE b LIKE 'a%' } {SEARCH TABLE t1 USING INDEX i1 (b>? AND b<?)} do_eqp_test analyze3-2.3 { SELECT count(a) FROM t1 WHERE b LIKE '%a' } {SCAN TABLE t1} # Return the first argument if like_match_blobs is true (the default) # or the second argument if not # proc ilmb {a b} { ifcapable like_match_blobs {return $a} return $b ................................................................................ } execsql COMMIT execsql ANALYZE } {} do_eqp_test analyze3-6-3 { SELECT * FROM t1 WHERE a = 5 AND c = 13; } {SEARCH TABLE t1 USING INDEX i2 (c=?)} do_eqp_test analyze3-6-2 { SELECT * FROM t1 WHERE a = 5 AND b > 'w' AND c = 13; } {SEARCH TABLE t1 USING INDEX i2 (c=?)} #----------------------------------------------------------------------------- # 2015-04-20. # Memory leak in sqlite3Stat4ProbeFree(). (Discovered while fuzzing.) # do_execsql_test analyze-7.1 { DROP TABLE IF EXISTS t1; |
Changes to test/analyze4.test.
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
INSERT INTO t1 SELECT a+32, b FROM t1; INSERT INTO t1 SELECT a+64, b FROM t1; ANALYZE; } # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} # Verify that the t1b index shows that it does not narrow down the # search any at all. # do_test analyze4-1.1 { db eval { SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx; |
| |
34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 |
INSERT INTO t1 SELECT a+32, b FROM t1; INSERT INTO t1 SELECT a+64, b FROM t1; ANALYZE; } # Should choose the t1a index since it is more specific than t1b. db eval {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=5 AND b IS NULL} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} # Verify that the t1b index shows that it does not narrow down the # search any at all. # do_test analyze4-1.1 { db eval { SELECT idx, stat FROM sqlite_stat1 WHERE tbl='t1' ORDER BY idx; |
Changes to test/analyze6.test.
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 |
# The lowest cost plan is to scan CAT and for each integer there, do a single # lookup of the first corresponding entry in EV then read off the equal values # in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would # have used EV for the outer loop instead of CAT - which was about 3x slower.) # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} } {0 0 1 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 0 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}} # The same plan is chosen regardless of the order of the tables in the # FROM clause. # do_test analyze6-1.2 { eqp {SELECT count(*) FROM cat, ev WHERE x=y} } {0 0 0 {SCAN TABLE cat USING COVERING INDEX catx} 0 1 1 {SEARCH TABLE ev USING COVERING INDEX evy (y=?)}} # Ticket [83ea97620bd3101645138b7b0e71c12c5498fe3d] 2011-03-30 # If ANALYZE is run on an empty table, make sure indices are used # on the table. # do_test analyze6-2.1 { execsql { CREATE TABLE t201(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX t201z ON t201(z); ANALYZE; } eqp {SELECT * FROM t201 WHERE z=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} } {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} do_test analyze6-2.4 { execsql { INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} } {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} do_test analyze6-2.7 { execsql { INSERT INTO t201 VALUES(4,5,7); INSERT INTO t201 SELECT x+100, y+100, z+100 FROM t201; INSERT INTO t201 SELECT x+200, y+200, z+200 FROM t201; INSERT INTO t201 SELECT x+400, y+400, z+400 FROM t201; ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX t201z (z=?)}} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} } {0 0 0 {SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)}} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} } {0 0 0 {SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)}} finish_test |
| | | > > > | > | | | | | | | | | |
57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
# The lowest cost plan is to scan CAT and for each integer there, do a single # lookup of the first corresponding entry in EV then read off the equal values # in EV. (Prior to the 2011-03-04 enhancement to where.c, this query would # have used EV for the outer loop instead of CAT - which was about 3x slower.) # do_test analyze6-1.1 { eqp {SELECT count(*) FROM ev, cat WHERE x=y} } {/*SCAN TABLE cat USING COVERING INDEX catx*SEARCH TABLE ev USING COVERING INDEX evy (y=?)*/} # The same plan is chosen regardless of the order of the tables in the # FROM clause. # do_eqp_test analyze6-1.2 { SELECT count(*) FROM cat, ev WHERE x=y } { QUERY PLAN |--SCAN TABLE cat USING COVERING INDEX catx `--SEARCH TABLE ev USING COVERING INDEX evy (y=?) } # Ticket [83ea97620bd3101645138b7b0e71c12c5498fe3d] 2011-03-30 # If ANALYZE is run on an empty table, make sure indices are used # on the table. # do_test analyze6-2.1 { execsql { CREATE TABLE t201(x INTEGER PRIMARY KEY, y UNIQUE, z); CREATE INDEX t201z ON t201(z); ANALYZE; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.2 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.3 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.4 { execsql { INSERT INTO t201 VALUES(1,2,3),(2,3,4),(3,4,5); ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.5 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.6 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} do_test analyze6-2.7 { execsql { INSERT INTO t201 VALUES(4,5,7); INSERT INTO t201 SELECT x+100, y+100, z+100 FROM t201; INSERT INTO t201 SELECT x+200, y+200, z+200 FROM t201; INSERT INTO t201 SELECT x+400, y+400, z+400 FROM t201; ANALYZE t201; } eqp {SELECT * FROM t201 WHERE z=5} } {/*SEARCH TABLE t201 USING INDEX t201z (z=?)*/} do_test analyze6-2.8 { eqp {SELECT * FROM t201 WHERE y=5} } {/*SEARCH TABLE t201 USING INDEX sqlite_autoindex_t201_1 (y=?)*/} do_test analyze6-2.9 { eqp {SELECT * FROM t201 WHERE x=5} } {/*SEARCH TABLE t201 USING INTEGER PRIMARY KEY (rowid=?)*/} finish_test |
Changes to test/analyze7.test.
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
CREATE INDEX t1b ON t1(b); CREATE INDEX t1cd ON t1(c,d); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t1 SELECT value, value, value/100, value FROM nums WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} # Run an analyze on one of the three indices. Verify that this # effects the row-count estimate on the one query that uses that # one index. # do_test analyze7-2.0 { execsql {ANALYZE t1a;} db cache flush execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} # Verify that since the query planner now things that t1a is more # selective than t1b, it prefers to use t1a. # do_test analyze7-2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} # Run an analysis on another of the three indices. Verify that this # new analysis works and does not disrupt the previous analysis. # do_test analyze7-3.0 { execsql {ANALYZE t1cd;} db cache flush; execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} ifcapable stat4||stat3 { # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} } else { # If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=?)}} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} ifcapable {!stat4 && !stat3} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} } do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)}} finish_test |
| | | | | | | | | | | | | | | | |
33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
CREATE INDEX t1b ON t1(b); CREATE INDEX t1cd ON t1(c,d); CREATE VIRTUAL TABLE nums USING wholenumber; INSERT INTO t1 SELECT value, value, value/100, value FROM nums WHERE value BETWEEN 1 AND 256; EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123; } } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-1.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-1.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} # Run an analyze on one of the three indices. Verify that this # effects the row-count estimate on the one query that uses that # one index. # do_test analyze7-2.0 { execsql {ANALYZE t1a;} db cache flush execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} # Verify that since the query planner now things that t1a is more # selective than t1b, it prefers to use t1a. # do_test analyze7-2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} # Run an analysis on another of the three indices. Verify that this # new analysis works and does not disrupt the previous analysis. # do_test analyze7-3.0 { execsql {ANALYZE t1cd;} db cache flush; execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123;} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test analyze7-3.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b=123;} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.2.1 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=?;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} ifcapable stat4||stat3 { # If ENABLE_STAT4 is defined, SQLite comes up with a different estimated # row count for (c=2) than it does for (c=?). do_test analyze7-3.2.2 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} } else { # If ENABLE_STAT4 is not defined, the expected row count for (c=2) is the # same as that for (c=?). do_test analyze7-3.2.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=2;} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=?)*/} } do_test analyze7-3.3 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} ifcapable {!stat4 && !stat3} { do_test analyze7-3.4 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test analyze7-3.5 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=123 AND c=123} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} } do_test analyze7-3.6 { execsql {EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE c=123 AND d=123 AND b=123} } {/*SEARCH TABLE t1 USING INDEX t1cd (c=? AND d=?)*/} finish_test |
Changes to test/analyze8.test.
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# with a==100. And so for those cases, choose the t1b index. # # Buf ro a==99 and a==101, there are far fewer rows so choose # the t1a index. # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} # There are many more values of c between 0 and 100000 than there are # between 800000 and 900000. So t1c is more selective for the latter # range. # # Test 3.2 is a little unstable. It depends on the planner estimating # that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN ................................................................................ do_execsql_test 3.0 { SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} do_test 3.2 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 800000 AND 900000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} do_test 3.3 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 0 AND 100000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1a (a=?)}} do_test 3.4 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 800000 AND 900000} } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} finish_test |
|
|
|
|
|
|
|
|
|
|
|
|
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
..
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
# with a==100. And so for those cases, choose the t1b index. # # Buf ro a==99 and a==101, there are far fewer rows so choose # the t1a index. # do_test 1.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b=55} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test 1.2 { eqp {SELECT * FROM t1 WHERE a=99 AND b=55} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.3 { eqp {SELECT * FROM t1 WHERE a=101 AND b=55} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.4 { eqp {SELECT * FROM t1 WHERE a=100 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1b (b=?)*/} do_test 1.5 { eqp {SELECT * FROM t1 WHERE a=99 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 1.6 { eqp {SELECT * FROM t1 WHERE a=101 AND b=56} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 2.1 { eqp {SELECT * FROM t1 WHERE a=100 AND b BETWEEN 50 AND 54} } {/*SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)*/} # There are many more values of c between 0 and 100000 than there are # between 800000 and 900000. So t1c is more selective for the latter # range. # # Test 3.2 is a little unstable. It depends on the planner estimating # that (b BETWEEN 30 AND 34) will match more rows than (c BETWEEN ................................................................................ do_execsql_test 3.0 { SELECT count(*) FROM t1 WHERE b BETWEEN 30 AND 34; SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 100000; SELECT count(*) FROM t1 WHERE c BETWEEN 800000 AND 900000; } {50 376 32} do_test 3.1 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 0 AND 100000} } {/*SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)*/} do_test 3.2 { eqp {SELECT * FROM t1 WHERE b BETWEEN 30 AND 34 AND c BETWEEN 800000 AND 900000} } {/*SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)*/} do_test 3.3 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 0 AND 100000} } {/*SEARCH TABLE t1 USING INDEX t1a (a=?)*/} do_test 3.4 { eqp {SELECT * FROM t1 WHERE a=100 AND c BETWEEN 800000 AND 900000} } {/*SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)*/} finish_test |
Changes to test/analyze9.test.
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 .... 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 .... 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 .... 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 .... 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 |
} {/*USING INTEGER PRIMARY KEY*/} #------------------------------------------------------------------------- # reset_db do_execsql_test 22.0 { CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; } do_execsql_test 22.1 { WITH r(x) AS ( SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<=100 ) ................................................................................ do_eqp_test 23.1 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300 -- Formerly used index i41. But i41 is not a covering index whereas -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the -- PRIMARY KEY is preferred. } { 0 0 0 {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)} } do_eqp_test 23.2 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300 } { 0 0 0 {SEARCH TABLE t4 USING INDEX i42 (f<?)} } do_execsql_test 24.0 { CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID; WITH data(a, b, c, d, e) AS ( SELECT 'z', 'y', 0, 0, 0 UNION ALL SELECT ................................................................................ CREATE INDEX aa ON t6(a); CREATE INDEX bb ON t6(b); ANALYZE; } # Term (b<?) is estimated at 25%. Better than (a<30) but not as # good as (a<20). do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } { 0 0 0 {SEARCH TABLE t6 USING INDEX bb (b<?)} } do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } { 0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)} } # Term (b BETWEEN ? AND ?) is estimated at 1/64. do_eqp_test 25.3.1 { SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ? } { 0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)} } # Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows - # 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than # (a<20) but not as good as (a<10). do_eqp_test 25.4.1 { SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60) } { 0 0 0 {SEARCH TABLE t6 USING INDEX aa (a<?)} } do_eqp_test 25.4.2 { SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60) } { 0 0 0 {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)} } } #------------------------------------------------------------------------- # Check that a problem in they way stat4 data is used has been # resolved (see below). # reset_db ................................................................................ # no more than that. Guessing less than 20 is therefore unreasonable. # # At one point though, due to a problem in whereKeyStats(), the planner was # estimating that (x=10000 AND y<50) would match only 2 rows. # do_eqp_test 26.1.4 { SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444; } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1z (z=?)} } # This test - 26.2.* - tests that another manifestation of the same problem # is no longer present in the library. Assuming: # # CREATE INDEX t1xy ON t1(x, y) # ................................................................................ UPDATE t1 SET z = (rowid / 95); ANALYZE; COMMIT; } do_eqp_test 26.2.2 { SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?; } { 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)} } finish_test |
> | < | < < | < | | < | | < < | < < | | < | < < | < < | < |
983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 .... 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 .... 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 .... 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 .... 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 |
} {/*USING INTEGER PRIMARY KEY*/} #------------------------------------------------------------------------- # reset_db do_execsql_test 22.0 { CREATE TABLE t3(a, b, c, d, PRIMARY KEY(a, b)) WITHOUT ROWID; SELECT * FROM t3; } {} do_execsql_test 22.1 { WITH r(x) AS ( SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<=100 ) ................................................................................ do_eqp_test 23.1 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'AEA') AND f<300 -- Formerly used index i41. But i41 is not a covering index whereas -- the PRIMARY KEY is a covering index, and so as of 2017-10-15, the -- PRIMARY KEY is preferred. } {SEARCH TABLE t4 USING PRIMARY KEY (c=? AND b=? AND a<?)} do_eqp_test 23.2 { SELECT * FROM t4 WHERE (e=1 AND b='xyz' AND c='zyx' AND a<'JJJ') AND f<300 } {SEARCH TABLE t4 USING INDEX i42 (f<?)} do_execsql_test 24.0 { CREATE TABLE t5(c, d, b, e, a, PRIMARY KEY(a, b, c)) WITHOUT ROWID; WITH data(a, b, c, d, e) AS ( SELECT 'z', 'y', 0, 0, 0 UNION ALL SELECT ................................................................................ CREATE INDEX aa ON t6(a); CREATE INDEX bb ON t6(b); ANALYZE; } # Term (b<?) is estimated at 25%. Better than (a<30) but not as # good as (a<20). do_eqp_test 25.2.1 { SELECT * FROM t6 WHERE a<30 AND b<? } \ {SEARCH TABLE t6 USING INDEX bb (b<?)} do_eqp_test 25.2.2 { SELECT * FROM t6 WHERE a<20 AND b<? } \ {SEARCH TABLE t6 USING INDEX aa (a<?)} # Term (b BETWEEN ? AND ?) is estimated at 1/64. do_eqp_test 25.3.1 { SELECT * FROM t6 WHERE a BETWEEN 5 AND 10 AND b BETWEEN ? AND ? } {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)} # Term (b BETWEEN ? AND 60) is estimated to return roughly 15 rows - # 60 from (b<=60) multiplied by 0.25 for the b>=? term. Better than # (a<20) but not as good as (a<10). do_eqp_test 25.4.1 { SELECT * FROM t6 WHERE a < 10 AND (b BETWEEN ? AND 60) } {SEARCH TABLE t6 USING INDEX aa (a<?)} do_eqp_test 25.4.2 { SELECT * FROM t6 WHERE a < 20 AND (b BETWEEN ? AND 60) } {SEARCH TABLE t6 USING INDEX bb (b>? AND b<?)} } #------------------------------------------------------------------------- # Check that a problem in they way stat4 data is used has been # resolved (see below). # reset_db ................................................................................ # no more than that. Guessing less than 20 is therefore unreasonable. # # At one point though, due to a problem in whereKeyStats(), the planner was # estimating that (x=10000 AND y<50) would match only 2 rows. # do_eqp_test 26.1.4 { SELECT * FROM t1 WHERE x = 10000 AND y < 50 AND z = 444; } {SEARCH TABLE t1 USING INDEX t1z (z=?)} # This test - 26.2.* - tests that another manifestation of the same problem # is no longer present in the library. Assuming: # # CREATE INDEX t1xy ON t1(x, y) # ................................................................................ UPDATE t1 SET z = (rowid / 95); ANALYZE; COMMIT; } do_eqp_test 26.2.2 { SELECT * FROM t1 WHERE x='B' AND y>25 AND z=?; } {SEARCH TABLE t1 USING INDEX i1 (x=? AND y>?)} finish_test |
Changes to test/analyzeA.test.
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1 do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49 do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49 do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1 do_eqp_test 1.$tn.2.5 { SELECT * FROM t1 WHERE b = 31 AND c = 0; } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)}} do_eqp_test 1.$tn.2.6 { SELECT * FROM t1 WHERE b = 125 AND c = 16; } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)}} do_execsql_test 1.$tn.3.1 { SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50 } {6} do_execsql_test 1.$tn.3.2 { SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50 } {90} ................................................................................ } {90} do_execsql_test 1.$tn.3.4 { SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125 } {6} do_eqp_test 1.$tn.3.5 { SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} do_eqp_test 1.$tn.3.6 { SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} do_eqp_test 1.$tn.3.7 { SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} do_eqp_test 1.$tn.3.8 { SELECT * FROM t1 WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real) AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real) } {0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}} do_eqp_test 1.$tn.3.9 { SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125 } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} do_eqp_test 1.$tn.3.10 { SELECT * FROM t1 WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real) AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real) } {0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}} } finish_test |
|
|
|
|
|
|
|
|
|
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
...
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
|
do_execsql_test 1.$tn.2.1 { SELECT count(*) FROM t1 WHERE b=31 } 1
do_execsql_test 1.$tn.2.2 { SELECT count(*) FROM t1 WHERE c=0 } 49
do_execsql_test 1.$tn.2.3 { SELECT count(*) FROM t1 WHERE b=125 } 49
do_execsql_test 1.$tn.2.4 { SELECT count(*) FROM t1 WHERE c=16 } 1
do_eqp_test 1.$tn.2.5 {
SELECT * FROM t1 WHERE b = 31 AND c = 0;
} {SEARCH TABLE t1 USING INDEX t1b (b=?)}
do_eqp_test 1.$tn.2.6 {
SELECT * FROM t1 WHERE b = 125 AND c = 16;
} {SEARCH TABLE t1 USING INDEX t1c (c=?)}
do_execsql_test 1.$tn.3.1 {
SELECT count(*) FROM t1 WHERE b BETWEEN 0 AND 50
} {6}
do_execsql_test 1.$tn.3.2 {
SELECT count(*) FROM t1 WHERE c BETWEEN 0 AND 50
} {90}
................................................................................
} {90}
do_execsql_test 1.$tn.3.4 {
SELECT count(*) FROM t1 WHERE c BETWEEN 75 AND 125
} {6}
do_eqp_test 1.$tn.3.5 {
SELECT * FROM t1 WHERE b BETWEEN 0 AND 50 AND c BETWEEN 0 AND 50
} {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
do_eqp_test 1.$tn.3.6 {
SELECT * FROM t1 WHERE b BETWEEN 75 AND 125 AND c BETWEEN 75 AND 125
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
do_eqp_test 1.$tn.3.7 {
SELECT * FROM t1 WHERE b BETWEEN +0 AND +50 AND c BETWEEN +0 AND +50
} {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
do_eqp_test 1.$tn.3.8 {
SELECT * FROM t1
WHERE b BETWEEN cast('0' AS int) AND cast('50.0' AS real)
AND c BETWEEN cast('0' AS numeric) AND cast('50.0' AS real)
} {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)}
do_eqp_test 1.$tn.3.9 {
SELECT * FROM t1 WHERE b BETWEEN +75 AND +125 AND c BETWEEN +75 AND +125
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
do_eqp_test 1.$tn.3.10 {
SELECT * FROM t1
WHERE b BETWEEN cast('75' AS int) AND cast('125.0' AS real)
AND c BETWEEN cast('75' AS numeric) AND cast('125.0' AS real)
} {SEARCH TABLE t1 USING INDEX t1c (c>? AND c<?)}
}
finish_test
|
Changes to test/analyzeD.test.
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
..
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
|
} {} # With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than # a=3001 (7 rows). # do_eqp_test 1.2 { SELECT * FROM t1 WHERE a=3001 AND c=150; } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)} } do_test 1.3 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} ................................................................................ # Without stat1, because 3001 is larger than all samples in the stat4 # table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly) # chooses it over the c=150 index (5 rows). Even with stat1 data, things # worked this way before commit [e6f7f97dbc]. # do_eqp_test 1.4 { SELECT * FROM t1 WHERE a=3001 AND c=150; } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1_ab (a=?)} } do_test 1.5 { execsql { UPDATE t1 SET a=13 WHERE a = 3001; ANALYZE; } } {} do_eqp_test 1.6 { SELECT * FROM t1 WHERE a=13 AND c=150; } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)} } do_test 1.7 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} # Same test as 1.4, except this time the 7 rows that match the a=? condition # do not feature larger values than all rows in the stat4 table. So SQLite # gets this right, even without stat1 data. do_eqp_test 1.8 { SELECT * FROM t1 WHERE a=13 AND c=150; } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1_c (c=?)} } finish_test |
<
|
<
<
|
<
<
|
<
<
|
|
<
|
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
..
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
|
} {} # With full ANALYZE data, SQLite sees that c=150 (5 rows) is better than # a=3001 (7 rows). # do_eqp_test 1.2 { SELECT * FROM t1 WHERE a=3001 AND c=150; } {SEARCH TABLE t1 USING INDEX t1_c (c=?)} do_test 1.3 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} ................................................................................ # Without stat1, because 3001 is larger than all samples in the stat4 # table, SQLite thinks that a=3001 matches just 1 row. So it (incorrectly) # chooses it over the c=150 index (5 rows). Even with stat1 data, things # worked this way before commit [e6f7f97dbc]. # do_eqp_test 1.4 { SELECT * FROM t1 WHERE a=3001 AND c=150; } {SEARCH TABLE t1 USING INDEX t1_ab (a=?)} do_test 1.5 { execsql { UPDATE t1 SET a=13 WHERE a = 3001; ANALYZE; } } {} do_eqp_test 1.6 { SELECT * FROM t1 WHERE a=13 AND c=150; } {SEARCH TABLE t1 USING INDEX t1_c (c=?)} do_test 1.7 { execsql { DELETE FROM sqlite_stat1 } db close sqlite3 db test.db } {} # Same test as 1.4, except this time the 7 rows that match the a=? condition # do not feature larger values than all rows in the stat4 table. So SQLite # gets this right, even without stat1 data. do_eqp_test 1.8 { SELECT * FROM t1 WHERE a=13 AND c=150; } {SEARCH TABLE t1 USING INDEX t1_c (c=?)} finish_test |
Changes to test/analyzeF.test.
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
9 "x = str('19') AND y = str('4')" {t1y (y=?)} 10 "x = str('4') AND y = str('19')" {t1y (y=?)} 11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)} 12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)} } { set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}" do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res } # Test that functions that do not exist - "func()" - do not cause an error. # do_catchsql_test 2.1 { SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3) ................................................................................ foreach {tn where idx} { 1 "x = det4() AND y = det19()" {t1x (x=?)} 2 "x = det19() AND y = det4()" {t1y (y=?)} 3 "x = nondet4() AND y = nondet19()" {t1y (y=?)} 4 "x = nondet19() AND y = nondet4()" {t1y (y=?)} } { set res "0 0 0 {SEARCH TABLE t1 USING INDEX $idx}" do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res } execsql { DELETE FROM t1 } proc throw_error {err} { error $err } |
|
|
|
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
..
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
|
9 "x = str('19') AND y = str('4')" {t1y (y=?)}
10 "x = str('4') AND y = str('19')" {t1y (y=?)}
11 "x = nullif('19', 0) AND y = nullif('4', 0)" {t1y (y=?)}
12 "x = nullif('4', 0) AND y = nullif('19', 0)" {t1y (y=?)}
} {
set res "SEARCH TABLE t1 USING INDEX $idx"
do_eqp_test 1.$tn "SELECT * FROM t1 WHERE $where" $res
}
# Test that functions that do not exist - "func()" - do not cause an error.
#
do_catchsql_test 2.1 {
SELECT * FROM t1 WHERE x = substr('145', 2, 1) AND y = func(1, 2, 3)
................................................................................
foreach {tn where idx} {
1 "x = det4() AND y = det19()" {t1x (x=?)}
2 "x = det19() AND y = det4()" {t1y (y=?)}
3 "x = nondet4() AND y = nondet19()" {t1y (y=?)}
4 "x = nondet19() AND y = nondet4()" {t1y (y=?)}
} {
set res "SEARCH TABLE t1 USING INDEX $idx"
do_eqp_test 3.$tn "SELECT * FROM t1 WHERE $where" $res
}
execsql { DELETE FROM t1 }
proc throw_error {err} { error $err }
|
Changes to test/autoindex1.test.
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 ... 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 ... 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 |
# do_execsql_test autoindex1-500 { CREATE TABLE t501(a INTEGER PRIMARY KEY, b); CREATE TABLE t502(x INTEGER PRIMARY KEY, y); INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t501',null,'1000000'); INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t502',null,'1000'); ANALYZE sqlite_master; EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {EXECUTE LIST SUBQUERY 1} 1 0 0 {SCAN TABLE t502} } do_execsql_test autoindex1-501 { EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { 0 0 0 {SCAN TABLE t501} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} 1 0 0 {SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?)} } do_execsql_test autoindex1-502 { EXPLAIN QUERY PLAN SELECT b FROM t501 WHERE t501.a=123 AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { 0 0 0 {SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} 1 0 0 {SCAN TABLE t502} } # The following code checks a performance regression reported on the # mailing list on 2010-10-19. The problem is that the nRowEst field # of ephermeral tables was not being initialized correctly and so no # automatic index was being created for the emphemeral table when it was # used as part of a join. # ................................................................................ ON flock_owner (owner_change_date); CREATE INDEX fo_owner_person_id_index ON flock_owner (owner_person_id); CREATE INDEX sheep_org_flock_index ON sheep (originating_flock); CREATE INDEX sheep_reg_flock_index ON sheep (registering_flock); EXPLAIN QUERY PLAN SELECT x.sheep_no, x.registering_flock, x.date_of_registration FROM sheep x LEFT JOIN (SELECT s.sheep_no, prev.flock_no, prev.owner_person_id, s.date_of_registration, prev.owner_change_date FROM sheep s JOIN flock_owner prev ON s.registering_flock = prev.flock_no AND (prev.owner_change_date <= s.date_of_registration || ' 00:00:00') ................................................................................ WHERE prev.flock_no = later.flock_no AND later.owner_change_date > prev.owner_change_date AND later.owner_change_date <= s.date_of_registration||' 00:00:00') ) y ON x.sheep_no = y.sheep_no WHERE y.sheep_no IS NULL ORDER BY x.registering_flock; } { 1 0 0 {SCAN TABLE sheep AS s} 1 1 1 {SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?)} 1 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?)} 0 0 0 {SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index} 0 1 1 {SEARCH SUBQUERY 1 AS y USING AUTOMATIC COVERING INDEX (sheep_no=?)} } do_execsql_test autoindex1-700 { CREATE TABLE t5(a, b, c); EXPLAIN QUERY PLAN SELECT a FROM t5 WHERE b=10 ORDER BY c; } { 0 0 0 {SCAN TABLE t5} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # The following checks a performance issue reported on the sqlite-dev # mailing list on 2013-01-10 # do_execsql_test autoindex1-800 { CREATE TABLE accounts( |
| > > | | | | < > | | | | < > | | | < | > > > | | | | | | > > | > | | |
173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 ... 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 ... 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 |
# do_execsql_test autoindex1-500 { CREATE TABLE t501(a INTEGER PRIMARY KEY, b); CREATE TABLE t502(x INTEGER PRIMARY KEY, y); INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t501',null,'1000000'); INSERT INTO sqlite_stat1(tbl,idx,stat) VALUES('t502',null,'1000'); ANALYZE sqlite_master; } do_eqp_test autoindex1-500.1 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=?); } { QUERY PLAN |--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) `--LIST SUBQUERY `--SCAN TABLE t502 } do_eqp_test autoindex1-501 { SELECT b FROM t501 WHERE t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN |--SCAN TABLE t501 `--CORRELATED LIST SUBQUERY `--SEARCH TABLE t502 USING AUTOMATIC COVERING INDEX (y=?) } do_eqp_test autoindex1-502 { SELECT b FROM t501 WHERE t501.a=123 AND t501.a IN (SELECT x FROM t502 WHERE y=t501.b); } { QUERY PLAN |--SEARCH TABLE t501 USING INTEGER PRIMARY KEY (rowid=?) `--CORRELATED LIST SUBQUERY `--SCAN TABLE t502 } # The following code checks a performance regression reported on the # mailing list on 2010-10-19. The problem is that the nRowEst field # of ephermeral tables was not being initialized correctly and so no # automatic index was being created for the emphemeral table when it was # used as part of a join. # ................................................................................ ON flock_owner (owner_change_date); CREATE INDEX fo_owner_person_id_index ON flock_owner (owner_person_id); CREATE INDEX sheep_org_flock_index ON sheep (originating_flock); CREATE INDEX sheep_reg_flock_index ON sheep (registering_flock); } do_eqp_test autoindex1-600a { SELECT x.sheep_no, x.registering_flock, x.date_of_registration FROM sheep x LEFT JOIN (SELECT s.sheep_no, prev.flock_no, prev.owner_person_id, s.date_of_registration, prev.owner_change_date FROM sheep s JOIN flock_owner prev ON s.registering_flock = prev.flock_no AND (prev.owner_change_date <= s.date_of_registration || ' 00:00:00') ................................................................................ WHERE prev.flock_no = later.flock_no AND later.owner_change_date > prev.owner_change_date AND later.owner_change_date <= s.date_of_registration||' 00:00:00') ) y ON x.sheep_no = y.sheep_no WHERE y.sheep_no IS NULL ORDER BY x.registering_flock; } { QUERY PLAN |--MATERIALIZE xxxxxx | |--SCAN TABLE sheep AS s | |--SEARCH TABLE flock_owner AS prev USING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date<?) | `--CORRELATED SCALAR SUBQUERY | `--SEARCH TABLE flock_owner AS later USING COVERING INDEX sqlite_autoindex_flock_owner_1 (flock_no=? AND owner_change_date>? AND owner_change_date<?) |--SCAN TABLE sheep AS x USING INDEX sheep_reg_flock_index `--SEARCH SUBQUERY xxxxxx AS y USING AUTOMATIC COVERING INDEX (sheep_no=?) } do_execsql_test autoindex1-700 { CREATE TABLE t5(a, b, c); } do_eqp_test autoindex1-700a { SELECT a FROM t5 WHERE b=10 ORDER BY c; } { QUERY PLAN |--SCAN TABLE t5 `--USE TEMP B-TREE FOR ORDER BY } # The following checks a performance issue reported on the sqlite-dev # mailing list on 2013-01-10 # do_execsql_test autoindex1-800 { CREATE TABLE accounts( |
Changes to test/autoindex3.test.
80 81 82 83 84 85 86 87 88 89 90 91 92 |
# on the basis that the real index "uab" must be better than the automatic # index. This is not right - a skip-scan is not necessarily better than an # automatic index scan. # do_eqp_test 220 { select count(*) from u, v where u.b = v.b and v.e > 34; } { 0 0 1 {SEARCH TABLE v USING INDEX ve (e>?)} 0 1 0 {SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?)} } finish_test |
> | | |
80 81 82 83 84 85 86 87 88 89 90 91 92 93 |
# on the basis that the real index "uab" must be better than the automatic # index. This is not right - a skip-scan is not necessarily better than an # automatic index scan. # do_eqp_test 220 { select count(*) from u, v where u.b = v.b and v.e > 34; } { QUERY PLAN |--SEARCH TABLE v USING INDEX ve (e>?) `--SEARCH TABLE u USING AUTOMATIC COVERING INDEX (b=?) } finish_test |
Changes to test/autoindex5.test.
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
..
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
|
AND debian_bugs.note = package_notes.id ORDER BY debian_bugs.bug; } {} # The following query should use an automatic index for the view # in FROM clause of the subquery of the second result column. # do_execsql_test autoindex5-1.1 { EXPLAIN QUERY PLAN SELECT st.bug_name, (SELECT ALL debian_cve.bug FROM debian_cve WHERE debian_cve.bug_name = st.bug_name ORDER BY debian_cve.bug), sp.release FROM ................................................................................ WHERE sp.rowid = st.package AND st.bug_name = bugs.name AND ( st.bug_name LIKE 'CVE-%' OR st.bug_name LIKE 'TEMP-%' ) AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie' OR sp.release = 'wheezy' OR sp.release = 'squeeze' ) ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease; } {/SEARCH SUBQUERY 2 USING AUTOMATIC COVERING INDEX .bug_name=/} #------------------------------------------------------------------------- # Test that ticket [8a2adec1] has been fixed. # do_execsql_test 2.1 { CREATE TABLE one(o); INSERT INTO one DEFAULT VALUES; |
|
<
|
|
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
..
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
|
AND debian_bugs.note = package_notes.id ORDER BY debian_bugs.bug; } {} # The following query should use an automatic index for the view # in FROM clause of the subquery of the second result column. # do_eqp_test autoindex5-1.1 { SELECT st.bug_name, (SELECT ALL debian_cve.bug FROM debian_cve WHERE debian_cve.bug_name = st.bug_name ORDER BY debian_cve.bug), sp.release FROM ................................................................................ WHERE sp.rowid = st.package AND st.bug_name = bugs.name AND ( st.bug_name LIKE 'CVE-%' OR st.bug_name LIKE 'TEMP-%' ) AND ( sp.release = 'sid' OR sp.release = 'stretch' OR sp.release = 'jessie' OR sp.release = 'wheezy' OR sp.release = 'squeeze' ) ORDER BY sp.name, st.bug_name, sp.release, sp.subrelease; } {SEARCH SUBQUERY * USING AUTOMATIC COVERING INDEX (bug_name=?)} #------------------------------------------------------------------------- # Test that ticket [8a2adec1] has been fixed. # do_execsql_test 2.1 { CREATE TABLE one(o); INSERT INTO one DEFAULT VALUES; |
Changes to test/bestindex1.test.
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
...
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
|
do_execsql_test 1.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' } { 0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} } do_eqp_test 1.2 { SELECT * FROM x1 WHERE a IN ('abc', 'def'); } { 0 0 0 {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} } #------------------------------------------------------------------------- # reset_db register_tcl_module db # Parameter $mode may be one of: ................................................................................ do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2} do_execsql_test 2.2.$mode.5 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } {1 4} set plan(use) { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set plan(omit) { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%'} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set plan(use2) { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 2.2.$mode.6 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } $plan($mode) } # 2016-04-09. # Demonstrate a register overwrite problem when using two virtual # tables where the outer loop uses the IN operator. # set G(collist) [list PrimaryKey flagA columnA] |
<
|
<
<
|
<
>
|
|
>
|
|
>
|
|
|
|
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
...
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
|
do_execsql_test 1.0 { CREATE VIRTUAL TABLE x1 USING tcl(vtab_command); } {} do_eqp_test 1.1 { SELECT * FROM x1 WHERE a = 'abc' } {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} do_eqp_test 1.2 { SELECT * FROM x1 WHERE a IN ('abc', 'def'); } {SCAN TABLE x1 VIRTUAL TABLE INDEX 555:eq!} #------------------------------------------------------------------------- # reset_db register_tcl_module db # Parameter $mode may be one of: ................................................................................ do_execsql_test 2.2.$mode.4 {SELECT rowid FROM t1 WHERE a='two'} {2} do_execsql_test 2.2.$mode.5 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } {1 4} set plan(use) { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(omit) { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x WHERE a='%1%' `--USE TEMP B-TREE FOR ORDER BY } set plan(use2) { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:SELECT * FROM t1x `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 2.2.$mode.6 { SELECT rowid FROM t1 WHERE a IN ('one', 'four') ORDER BY +rowid } [string map {"\n " "\n"} $plan($mode)] } # 2016-04-09. # Demonstrate a register overwrite problem when using two virtual # tables where the outer loop uses the IN operator. # set G(collist) [list PrimaryKey flagA columnA] |
Changes to test/bestindex2.test.
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 |
CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}"); CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}"); CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a='abc' } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} } do_eqp_test 1.2 { SELECT * FROM t1 WHERE a='abc' AND b='def' } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} } do_eqp_test 1.3 { SELECT * FROM t1 WHERE a='abc' AND a='def' } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} } do_eqp_test 1.4 { SELECT * FROM t1,t2 WHERE c=a } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} } do_eqp_test 1.5 { SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)} } do_eqp_test 1.6 { SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 0 1 1 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 0 2 2 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)} } do_execsql_test 1.7.1 { CREATE TABLE x1(a, b); } do_eqp_test 1.7.2 { SELECT * FROM x1 CROSS JOIN t1, t2, t3 WHERE t1.a = t2.c AND t1.b = t3.e } { 0 0 0 {SCAN TABLE x1} 0 1 1 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:} 0 2 2 {SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?)} 0 3 3 {SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?)} } finish_test |
< | | < | | < | | > | | > | | | > | | | > | | | | |
85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 |
CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd t1 {a b}"); CREATE VIRTUAL TABLE t2 USING tcl("vtab_cmd t2 {c d}"); CREATE VIRTUAL TABLE t3 USING tcl("vtab_cmd t3 {e f}"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a='abc' } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a='abc' AND b='def' } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=? AND b=?)} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a='abc' AND a='def' } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:indexed(a=?)} do_eqp_test 1.4 { SELECT * FROM t1,t2 WHERE c=a } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: `--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) } do_eqp_test 1.5 { SELECT * FROM t1, t2 CROSS JOIN t3 WHERE t2.c = +t1.b AND t3.e=t2.d } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_eqp_test 1.6 { SELECT * FROM t1, t2, t3 WHERE t2.c = +t1.b AND t3.e = t2.d } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } do_execsql_test 1.7.1 { CREATE TABLE x1(a, b); } do_eqp_test 1.7.2 { SELECT * FROM x1 CROSS JOIN t1, t2, t3 WHERE t1.a = t2.c AND t1.b = t3.e } { QUERY PLAN |--SCAN TABLE x1 |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0: |--SCAN TABLE t2 VIRTUAL TABLE INDEX 0:indexed(c=?) `--SCAN TABLE t3 VIRTUAL TABLE INDEX 0:indexed(e=?) } finish_test |
Changes to test/bestindex3.test.
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
...
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
|
do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} } do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} } do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_eqp_test 1.4 { SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def'; } { 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} 0 0 0 {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ?} } do_execsql_test 1.5 { CREATE TABLE ttt(a, b, c); INSERT INTO ttt VALUES(1, 'two', 'three'); INSERT INTO ttt VALUES(2, 'one', 'two'); ................................................................................ CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT); CREATE INDEX t2x ON t2(x COLLATE nocase); CREATE INDEX t2y ON t2(y); } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?)} 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } } #------------------------------------------------------------------------- # Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE # statement is currently ignored. # proc vvv_command {method args} { |
<
|
<
<
|
<
>
|
|
>
|
|
|
>
|
|
|
|
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
...
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
|
do_execsql_test 1.0 { CREATE VIRTUAL TABLE t1 USING tcl("vtab_cmd 0"); } do_eqp_test 1.1 { SELECT * FROM t1 WHERE a LIKE 'abc'; } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ?} do_eqp_test 1.2 { SELECT * FROM t1 WHERE a = 'abc'; } {SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ?} do_eqp_test 1.3 { SELECT * FROM t1 WHERE a = 'abc' OR b = 'def'; } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a EQ ? `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_eqp_test 1.4 { SELECT * FROM t1 WHERE a LIKE 'abc%' OR b = 'def'; } { QUERY PLAN |--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:a LIKE ? `--SCAN TABLE t1 VIRTUAL TABLE INDEX 0:b EQ ? } do_execsql_test 1.5 { CREATE TABLE ttt(a, b, c); INSERT INTO ttt VALUES(1, 'two', 'three'); INSERT INTO ttt VALUES(2, 'one', 'two'); ................................................................................ CREATE TABLE t2(x TEXT COLLATE nocase, y TEXT); CREATE INDEX t2x ON t2(x COLLATE nocase); CREATE INDEX t2y ON t2(y); } do_eqp_test 2.2 { SELECT * FROM t2 WHERE x LIKE 'abc%' OR y = 'def' } [string map {"\n " \n} { QUERY PLAN |--SEARCH TABLE t2 USING INDEX t2x (x>? AND x<?) `--SEARCH TABLE t2 USING INDEX t2y (y=?) }] } #------------------------------------------------------------------------- # Test that any PRIMARY KEY within a sqlite3_decl_vtab() CREATE TABLE # statement is currently ignored. # proc vvv_command {method args} { |
Changes to test/bigmmap.test.
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
ORDER BY b, c; " {} do_eqp_test 2.$i.$t.3 " SELECT * FROM t$t AS o WHERE NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c ) ORDER BY b, c; " " 0 0 0 {SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1} 1 0 0 {SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?)} " } } finish_test |
| > | | | | < |
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 |
ORDER BY b, c; " {} do_eqp_test 2.$i.$t.3 " SELECT * FROM t$t AS o WHERE NOT EXISTS( SELECT * FROM t$t AS i WHERE a=o.a AND +b=o.b AND +c=o.c ) ORDER BY b, c; " [string map {"\n " "\n"} " QUERY PLAN |--SCAN TABLE t$t AS o USING COVERING INDEX sqlite_autoindex_t${t}_1 `--CORRELATED SCALAR SUBQUERY `--SEARCH TABLE t$t AS i USING INTEGER PRIMARY KEY (rowid=?) "] } } finish_test |
Changes to test/cost.test.
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 .. 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 .. 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 ... 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 ... 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 ... 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 |
CREATE TABLE t4(c, d, e); CREATE UNIQUE INDEX i3 ON t3(b); CREATE UNIQUE INDEX i4 ON t4(c, d); } do_eqp_test 1.2 { SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; } { 0 0 0 {SCAN TABLE t3 USING COVERING INDEX i3} 0 1 1 {SEARCH TABLE t4 USING INDEX i4 (c=?)} } do_execsql_test 2.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } # It is better to use an index for ORDER BY than sort externally, even # if the index is a non-covering index. do_eqp_test 2.2 { SELECT * FROM t1 ORDER BY a; } { 0 0 0 {SCAN TABLE t1 USING INDEX i1} } do_execsql_test 3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g); CREATE INDEX t5b ON t5(b); CREATE INDEX t5c ON t5(c); CREATE INDEX t5d ON t5(d); CREATE INDEX t5e ON t5(e); ................................................................................ } do_eqp_test 3.2 { SELECT a FROM t5 WHERE b IS NULL OR c IS NULL OR d IS NULL ORDER BY a; } { 0 0 0 {SEARCH TABLE t5 USING INDEX t5b (b=?)} 0 0 0 {SEARCH TABLE t5 USING INDEX t5c (c=?)} 0 0 0 {SEARCH TABLE t5 USING INDEX t5d (d=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } #------------------------------------------------------------------------- # If there is no likelihood() or stat3 data, SQLite assumes that a closed # range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint) # visits 1/64 of the rows in a table. # ................................................................................ do_execsql_test 4.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); } do_eqp_test 4.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?; } { 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } do_eqp_test 4.3 { SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; } { 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)} } #------------------------------------------------------------------------- # reset_db do_execsql_test 5.1 { CREATE TABLE t2(x, y); CREATE INDEX t2i1 ON t2(x); } do_eqp_test 5.2 { SELECT * FROM t2 ORDER BY x, y; } { 0 0 0 {SCAN TABLE t2 USING INDEX t2i1} 0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} } do_eqp_test 5.3 { SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid; } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # where7.test, where8.test: # do_execsql_test 6.1 { CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); CREATE INDEX t3i1 ON t3(b); CREATE INDEX t3i2 ON t3(c); } do_eqp_test 6.2 { SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a } { 0 0 0 {SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?)} 0 0 0 {SEARCH TABLE t3 USING INDEX t3i2 (c=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g); ................................................................................ } do_eqp_test 7.2 { SELECT a FROM t1 WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) ORDER BY a } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?)} 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 7.3 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } { 0 0 0 {SCAN TABLE t1} } do_eqp_test 7.4 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL } { 0 0 0 {SCAN TABLE t1} } #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE TABLE composer( cid INTEGER PRIMARY KEY, ................................................................................ do_eqp_test 8.2 { SELECT DISTINCT aname FROM album, composer, track WHERE cname LIKE '%bach%' AND unlikely(composer.cid=track.cid) AND unlikely(album.aid=track.aid); } { 0 0 2 {SCAN TABLE track} 0 1 0 {SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?)} 0 2 1 {SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t1( a,b,c,d,e, f,g,h,i,j, ................................................................................ execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) } } execsql ANALYZE } {} do_eqp_test 10.3 { SELECT rowid FROM t6 WHERE a=0 AND c=0 } { 0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} } do_eqp_test 10.4 { SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0 } { 0 0 0 {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} } do_eqp_test 10.5 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0 } { 0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=?)} } do_eqp_test 10.6 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0 } { 0 0 0 {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)} } } finish_test |
> | | < | < > | | | | < | | < | < > | | > | | > | | | > | | | < | < < | < > | | | | < | < < | < < | < < | < |
20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 .. 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 .. 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 ... 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 ... 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 ... 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 |
CREATE TABLE t4(c, d, e); CREATE UNIQUE INDEX i3 ON t3(b); CREATE UNIQUE INDEX i4 ON t4(c, d); } do_eqp_test 1.2 { SELECT e FROM t3, t4 WHERE b=c ORDER BY b, d; } { QUERY PLAN |--SCAN TABLE t3 USING COVERING INDEX i3 `--SEARCH TABLE t4 USING INDEX i4 (c=?) } do_execsql_test 2.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } # It is better to use an index for ORDER BY than sort externally, even # if the index is a non-covering index. do_eqp_test 2.2 { SELECT * FROM t1 ORDER BY a; } {SCAN TABLE t1 USING INDEX i1} do_execsql_test 3.1 { CREATE TABLE t5(a INTEGER PRIMARY KEY,b,c,d,e,f,g); CREATE INDEX t5b ON t5(b); CREATE INDEX t5c ON t5(c); CREATE INDEX t5d ON t5(d); CREATE INDEX t5e ON t5(e); ................................................................................ } do_eqp_test 3.2 { SELECT a FROM t5 WHERE b IS NULL OR c IS NULL OR d IS NULL ORDER BY a; } { QUERY PLAN |--SEARCH TABLE t5 USING INDEX t5b (b=?) |--SEARCH TABLE t5 USING INDEX t5c (c=?) |--SEARCH TABLE t5 USING INDEX t5d (d=?) `--USE TEMP B-TREE FOR ORDER BY } #------------------------------------------------------------------------- # If there is no likelihood() or stat3 data, SQLite assumes that a closed # range scan (e.g. one constrained by "col BETWEEN ? AND ?" constraint) # visits 1/64 of the rows in a table. # ................................................................................ do_execsql_test 4.1 { CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); CREATE INDEX i2 ON t1(b); } do_eqp_test 4.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.014) AND b BETWEEN ? AND ?; } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test 4.3 { SELECT * FROM t1 WHERE likelihood(a=?, 0.016) AND b BETWEEN ? AND ?; } {SEARCH TABLE t1 USING INDEX i2 (b>? AND b<?)} #------------------------------------------------------------------------- # reset_db do_execsql_test 5.1 { CREATE TABLE t2(x, y); CREATE INDEX t2i1 ON t2(x); } do_eqp_test 5.2 { SELECT * FROM t2 ORDER BY x, y; } { QUERY PLAN |--SCAN TABLE t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 5.3 { SELECT * FROM t2 WHERE x BETWEEN ? AND ? ORDER BY rowid; } { QUERY PLAN |--SEARCH TABLE t2 USING INDEX t2i1 (x>? AND x<?) `--USE TEMP B-TREE FOR ORDER BY } # where7.test, where8.test: # do_execsql_test 6.1 { CREATE TABLE t3(a INTEGER PRIMARY KEY, b, c); CREATE INDEX t3i1 ON t3(b); CREATE INDEX t3i2 ON t3(c); } do_eqp_test 6.2 { SELECT a FROM t3 WHERE (b BETWEEN 2 AND 4) OR c=100 ORDER BY a } { QUERY PLAN |--SEARCH TABLE t3 USING INDEX t3i1 (b>? AND b<?) |--SEARCH TABLE t3 USING INDEX t3i2 (c=?) `--USE TEMP B-TREE FOR ORDER BY } #------------------------------------------------------------------------- # reset_db do_execsql_test 7.1 { CREATE TABLE t1(a INTEGER PRIMARY KEY,b,c,d,e,f,g); ................................................................................ } do_eqp_test 7.2 { SELECT a FROM t1 WHERE (b>=950 AND b<=1010) OR (b IS NULL AND c NOT NULL) ORDER BY a } { QUERY PLAN |--SEARCH TABLE t1 USING INDEX t1b (b>? AND b<?) |--SEARCH TABLE t1 USING INDEX t1b (b=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 7.3 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL AND d NOT NULL) OR (b NOT NULL AND c IS NULL AND d NOT NULL) OR (b NOT NULL AND c NOT NULL AND d IS NULL) } {SCAN TABLE t1} do_eqp_test 7.4 { SELECT rowid FROM t1 WHERE (+b IS NULL AND c NOT NULL) OR c IS NULL } {SCAN TABLE t1} #------------------------------------------------------------------------- # reset_db do_execsql_test 8.1 { CREATE TABLE composer( cid INTEGER PRIMARY KEY, ................................................................................ do_eqp_test 8.2 { SELECT DISTINCT aname FROM album, composer, track WHERE cname LIKE '%bach%' AND unlikely(composer.cid=track.cid) AND unlikely(album.aid=track.aid); } { QUERY PLAN |--SCAN TABLE track |--SEARCH TABLE album USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE composer USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR DISTINCT } #------------------------------------------------------------------------- # do_execsql_test 9.1 { CREATE TABLE t1( a,b,c,d,e, f,g,h,i,j, ................................................................................ execsql { INSERT INTO t6 VALUES($i%4, 'xyz', $i%8) } } execsql ANALYZE } {} do_eqp_test 10.3 { SELECT rowid FROM t6 WHERE a=0 AND c=0 } {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.4 { SELECT rowid FROM t6 WHERE a=0 AND b='xyz' AND c=0 } {SEARCH TABLE t6 USING INDEX t6i2 (c=?)} do_eqp_test 10.5 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND c=0 } {SEARCH TABLE t6 USING INDEX t6i1 (a=?)} do_eqp_test 10.6 { SELECT rowid FROM t6 WHERE likelihood(a=0, 0.1) AND b='xyz' AND c=0 } {SEARCH TABLE t6 USING INDEX t6i1 (a=? AND b=?)} } finish_test |
Changes to test/coveridxscan.test.
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols); CREATE INDEX i2 ON t2($cols); " do_eqp_test 5.1.1 { SELECT * FROM t1 ORDER BY c1, c2; } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} } do_eqp_test 5.1.2 { SELECT * FROM t2 ORDER BY c1, c2; } { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i2} } finish_test |
< | < < | < < |
105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 |
CREATE TABLE t2(i INTEGER PRIMARY KEY, $cols); CREATE INDEX i2 ON t2($cols); " do_eqp_test 5.1.1 { SELECT * FROM t1 ORDER BY c1, c2; } {SCAN TABLE t1 USING COVERING INDEX i1} do_eqp_test 5.1.2 { SELECT * FROM t2 ORDER BY c1, c2; } {SCAN TABLE t2 USING COVERING INDEX i2} finish_test |
Changes to test/e_createtable.test.
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 |
# do_execsql_test 4.10.0 { CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2(a, b, c, UNIQUE(b, c)); } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" {0 0 0 {SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)}} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" {0 0 0 {SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1}} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" {0 0 0 {SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)}} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a # column definition or specified as a table constraint. In practice it # makes no difference. # # All the tests that deal with CHECK constraints below (4.11.* and |
| | | |
1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 |
# do_execsql_test 4.10.0 { CREATE TABLE t1(a, b PRIMARY KEY); CREATE TABLE t2(a, b, c, UNIQUE(b, c)); } do_createtable_tests 4.10 { 1 "EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 5" {/*SEARCH TABLE t1 USING INDEX sqlite_autoindex_t1_1 (b=?)*/} 2 "EXPLAIN QUERY PLAN SELECT * FROM t2 ORDER BY b, c" {/*SCAN TABLE t2 USING INDEX sqlite_autoindex_t2_1*/} 3 "EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE b=10 AND c>10" {/*SEARCH TABLE t2 USING INDEX sqlite_autoindex_t2_1 (b=? AND c>?)*/} } # EVIDENCE-OF: R-45493-35653 A CHECK constraint may be attached to a # column definition or specified as a table constraint. In practice it # makes no difference. # # All the tests that deal with CHECK constraints below (4.11.* and |
Changes to test/eqp.test.
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 ... 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 ... 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 ... 553 554 555 556 557 558 559 560 561 562 563 564 565 566 ... 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 ... 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 ... 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 |
CREATE TABLE t2(a INT, b INT, ex TEXT); CREATE TABLE t3(a INT, b INT, ex TEXT); } do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { 0 0 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 0 0 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} 0 1 0 {SCAN TABLE t2} } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { 0 0 0 {SCAN TABLE t2} 0 1 1 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 0 1 1 {SEARCH TABLE t1 USING INDEX i2 (b=?)} } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { 0 0 0 {SCAN TABLE t3} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } do_eqp_test 1.7 { SELECT * FROM t3 JOIN (SELECT 1) } { 0 0 1 {SCAN SUBQUERY 1} 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} 0 0 1 {SCAN SUBQUERY 1} 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) } { 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (EXCEPT)} 0 0 1 {SCAN SUBQUERY 1} 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) } { 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (INTERSECT)} 0 0 1 {SCAN SUBQUERY 1} 0 1 0 {SCAN TABLE t3} } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) } { 3 0 0 {SCAN TABLE t3} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION ALL)} 0 0 1 {SCAN SUBQUERY 1} 0 1 0 {SCAN TABLE t3} } #------------------------------------------------------------------------- # Test cases eqp-2.* - tests for single select statements. # drop_all_tables do_execsql_test 2.1 { ................................................................................ CREATE TABLE t1(x INT, y INT, ex TEXT); CREATE TABLE t2(x INT, y INT, ex TEXT); CREATE INDEX t2i1 ON t2(x); } det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.3 "SELECT DISTINCT * FROM t1" { 0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { 0 0 0 {SCAN TABLE t1} 0 1 1 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { 0 0 1 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 1 0 {SCAN TABLE t1} } det 2.3.1 "SELECT max(x) FROM t2" { 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.2 "SELECT min(x) FROM t2" { 0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2i1} } det 2.3.3 "SELECT min(x), max(x) FROM t2" { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} } #------------------------------------------------------------------------- # Test cases eqp-3.* - tests for select statements that use sub-selects. # do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SCAN TABLE t1 AS sub} } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SCAN TABLE t1 AS sub} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.2.2 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1, (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 0 0 0 {SCAN SUBQUERY 1 AS x1} 0 1 1 {SCAN SUBQUERY 2 AS x2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE LIST SUBQUERY 1} 1 0 0 {SCAN TABLE t2} } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED LIST SUBQUERY 1} 1 0 0 {SCAN TABLE t2} } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { 0 0 0 {SCAN TABLE t1} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 1} 1 0 0 {SCAN TABLE t2} } #------------------------------------------------------------------------- # Test cases eqp-4.* - tests for composite select statements. # do_eqp_test 4.1.1 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } { 1 0 0 {SCAN TABLE t1} 2 0 0 {SCAN TABLE t2} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.1.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.1.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.1.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } do_eqp_test 4.2.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION)} } do_eqp_test 4.2.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (INTERSECT)} } do_eqp_test 4.2.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 } { 1 0 0 {SCAN TABLE t1} 1 0 0 {USE TEMP B-TREE FOR ORDER BY} 2 0 0 {SCAN TABLE t2 USING INDEX t2i1} 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } do_eqp_test 4.3.1 { SELECT x FROM t1 UNION SELECT x FROM t2 } { 1 0 0 {SCAN TABLE t1} 2 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.2 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 } { 2 0 0 {SCAN TABLE t1} 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 USING TEMP B-TREE (UNION)} 4 0 0 {SCAN TABLE t1} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 USING TEMP B-TREE (UNION)} } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 } { 2 0 0 {SCAN TABLE t1} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 3 0 0 {SCAN TABLE t2 USING COVERING INDEX t2i1} 1 0 0 {COMPOUND SUBQUERIES 2 AND 3 (UNION)} 4 0 0 {SCAN TABLE t1} 4 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 4 (UNION)} } #------------------------------------------------------------------------- # This next block of tests verifies that the examples on the # lang_explain.html page are correct. # drop_all_tables # EVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b # FROM t1 WHERE a=1; # 0|0|0|SCAN TABLE t1 # do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SCAN TABLE t1} } # EVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH TABLE t1 USING INDEX i1 # do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } # EVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} } # EVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|1|SCAN TABLE t2 # do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)} det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 1 {SCAN TABLE t2} } # EVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; # 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|0|SCAN TABLE t2 # det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 0 {SCAN TABLE t2} } # EVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) # do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # EVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN # SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN TABLE t2 # 0|0|0|USE TEMP B-TREE FOR ORDER BY # det 5.7 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # EVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN TABLE t2 USING INDEX i4 # do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN TABLE t2 USING INDEX i4} } # EVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; # 0|0|0|SCAN TABLE t2 # 0|0|0|EXECUTE SCALAR SUBQUERY 1 # 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 # 2|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) # ................................................................................ 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # EVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN # SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; # 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 # 0|0|0|SCAN SUBQUERY 1 # 0|0|0|USE TEMP B-TREE FOR GROUP BY # det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } # EVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN # SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1; # 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?) # 0|1|1|SCAN TABLE t1 # det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2} } # EVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 UNION SELECT c FROM t2; # 1|0|0|SCAN TABLE t1 # 2|0|0|SCAN TABLE t2 # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION) # det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } # EVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1; # 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 # 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) # det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } if {![nonzero_reserved_bytes]} { #------------------------------------------------------------------------- # The following tests - eqp-6.* - test that the example C code on # documentation page eqp.html works. The C code is duplicated in test1.c # and wrapped in Tcl command [print_explain_query_plan] # ................................................................................ } [string trimleft { 1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 2 0 0 SCAN TABLE t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] } #------------------------------------------------------------------------- # The following tests - eqp-7.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables ................................................................................ do_execsql_test 7.0 { CREATE TABLE t1(a INT, b INT, ex CHAR(100)); CREATE TABLE t2(a INT, b INT, ex CHAR(100)); CREATE INDEX i1 ON t2(a); } det 7.1 "SELECT count(*) FROM t1" { 0 0 0 {SCAN TABLE t1} } det 7.2 "SELECT count(*) FROM t2" { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} } do_execsql_test 7.3 { INSERT INTO t1(a,b) VALUES(1, 2); INSERT INTO t1(a,b) VALUES(3, 4); INSERT INTO t2(a,b) VALUES(1, 2); ................................................................................ ANALYZE; } db close sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { 0 0 0 {SCAN TABLE t1} } det 7.5 "SELECT count(*) FROM t2" { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i1} } #------------------------------------------------------------------------- # The following tests - eqp-8.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables ................................................................................ do_execsql_test 8.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; CREATE TABLE t2(a, b, c); } det 8.1.1 "SELECT * FROM t2" { 0 0 0 {SCAN TABLE t2} } det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { 0 0 0 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } det 8.1.3 "SELECT count(*) FROM t2" { 0 0 0 {SCAN TABLE t2} } det 8.2.1 "SELECT * FROM t1" { 0 0 0 {SCAN TABLE t1} } det 8.2.2 "SELECT * FROM t1 WHERE b=?" { 0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=?)} } det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { 0 0 0 {SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?)} } det 8.2.4 "SELECT count(*) FROM t1" { 0 0 0 {SCAN TABLE t1} } finish_test |
> | | | > | | | > | > | | > | > | | | > > > | | | > > > > > > | | > > > > > > | < | | > > > > > > | < | | > > > > > > | < | | > | | | | > | | | > | | > | | | > | | | | > | | > | > | > | > | > | | | > | | | > | | | | > | | | > > | | | | > > | | > | | | | > | | | > | | | > | | | > > > | > | < > > > | | > | | < > > > | | > | | < > > > | | > | | < > > > | | > | | < > > > | | > | < > > > | | > | | < > > > | | > | | < > > > | | > | | < > > > | > | < > > > | > | | | < > > > > > | | > | < > | | < > | | | | | | | | | | | | | < > > | > | > | > | > | > | > | > | > | > | > | |
39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 ... 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 ... 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 ... 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 ... 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 ... 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 ... 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 |
CREATE TABLE t2(a INT, b INT, ex TEXT); CREATE TABLE t3(a INT, b INT, ex TEXT); } do_eqp_test 1.2 { SELECT * FROM t2, t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--SEARCH TABLE t1 USING INDEX i1 (a=?) |--SEARCH TABLE t1 USING INDEX i2 (b=?) `--SCAN TABLE t2 } do_eqp_test 1.3 { SELECT * FROM t2 CROSS JOIN t1 WHERE t1.a=1 OR t1.b=2; } { QUERY PLAN |--SCAN TABLE t2 |--SEARCH TABLE t1 USING INDEX i1 (a=?) `--SEARCH TABLE t1 USING INDEX i2 (b=?) } do_eqp_test 1.3 { SELECT a FROM t1 ORDER BY a } { QUERY PLAN `--SCAN TABLE t1 USING COVERING INDEX i1 } do_eqp_test 1.4 { SELECT a FROM t1 ORDER BY +a } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX i1 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 1.5 { SELECT a FROM t1 WHERE a=4 } { QUERY PLAN `--SEARCH TABLE t1 USING COVERING INDEX i1 (a=?) } do_eqp_test 1.6 { SELECT DISTINCT count(*) FROM t3 GROUP BY a; } { QUERY PLAN |--SCAN TABLE t3 |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR DISTINCT } do_eqp_test 1.7 { SELECT * FROM t3 JOIN (SELECT 1) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.8 { SELECT * FROM t3 JOIN (SELECT 1 UNION SELECT 2) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION USING TEMP B-TREE | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.9 { SELECT * FROM t3 JOIN (SELECT 1 EXCEPT SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--EXCEPT USING TEMP B-TREE | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.10 { SELECT * FROM t3 JOIN (SELECT 1 INTERSECT SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--INTERSECT USING TEMP B-TREE | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } do_eqp_test 1.11 { SELECT * FROM t3 JOIN (SELECT 1 UNION ALL SELECT a FROM t3 LIMIT 17) } { QUERY PLAN |--MATERIALIZE xxxxxx | `--COMPOUND QUERY | |--LEFT-MOST SUBQUERY | | `--SCAN CONSTANT ROW | `--UNION ALL | `--SCAN TABLE t3 |--SCAN SUBQUERY xxxxxx `--SCAN TABLE t3 } #------------------------------------------------------------------------- # Test cases eqp-2.* - tests for single select statements. # drop_all_tables do_execsql_test 2.1 { ................................................................................ CREATE TABLE t1(x INT, y INT, ex TEXT); CREATE TABLE t2(x INT, y INT, ex TEXT); CREATE INDEX t2i1 ON t2(x); } det 2.2.1 "SELECT DISTINCT min(x), max(x) FROM t1 GROUP BY x ORDER BY 1" { QUERY PLAN |--SCAN TABLE t1 |--USE TEMP B-TREE FOR GROUP BY |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.2 "SELECT DISTINCT min(x), max(x) FROM t2 GROUP BY x ORDER BY 1" { QUERY PLAN |--SCAN TABLE t2 USING COVERING INDEX t2i1 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.3 "SELECT DISTINCT * FROM t1" { QUERY PLAN |--SCAN TABLE t1 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.4 "SELECT DISTINCT * FROM t1, t2" { QUERY PLAN |--SCAN TABLE t1 |--SCAN TABLE t2 `--USE TEMP B-TREE FOR DISTINCT } det 2.2.5 "SELECT DISTINCT * FROM t1, t2 ORDER BY t1.x" { QUERY PLAN |--SCAN TABLE t1 |--SCAN TABLE t2 |--USE TEMP B-TREE FOR DISTINCT `--USE TEMP B-TREE FOR ORDER BY } det 2.2.6 "SELECT DISTINCT t2.x FROM t1, t2 ORDER BY t2.x" { QUERY PLAN |--SCAN TABLE t2 USING COVERING INDEX t2i1 `--SCAN TABLE t1 } det 2.3.1 "SELECT max(x) FROM t2" { QUERY PLAN `--SEARCH TABLE t2 USING COVERING INDEX t2i1 } det 2.3.2 "SELECT min(x) FROM t2" { QUERY PLAN `--SEARCH TABLE t2 USING COVERING INDEX t2i1 } det 2.3.3 "SELECT min(x), max(x) FROM t2" { QUERY PLAN `--SCAN TABLE t2 USING COVERING INDEX t2i1 } det 2.4.1 "SELECT * FROM t1 WHERE rowid=?" { QUERY PLAN `--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) } #------------------------------------------------------------------------- # Test cases eqp-3.* - tests for select statements that use sub-selects. # do_eqp_test 3.1.1 { SELECT (SELECT x FROM t1 AS sub) FROM t1; } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY `--SCAN TABLE t1 AS sub } do_eqp_test 3.1.2 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub); } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY `--SCAN TABLE t1 AS sub } do_eqp_test 3.1.3 { SELECT * FROM t1 WHERE (SELECT x FROM t1 AS sub ORDER BY y); } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY |--SCAN TABLE t1 AS sub `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 3.1.4 { SELECT * FROM t1 WHERE (SELECT x FROM t2 ORDER BY x); } { QUERY PLAN |--SCAN TABLE t1 `--SCALAR SUBQUERY `--SCAN TABLE t2 USING COVERING INDEX t2i1 } det 3.2.1 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) ORDER BY y LIMIT 5 } { QUERY PLAN |--CO-ROUTINE xxxxxx | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY |--SCAN SUBQUERY xxxxxx `--USE TEMP B-TREE FOR ORDER BY } det 3.2.2 { SELECT * FROM (SELECT * FROM t1 ORDER BY x LIMIT 10) AS x1, (SELECT * FROM t2 ORDER BY x LIMIT 10) AS x2 ORDER BY x2.y LIMIT 5 } { QUERY PLAN |--MATERIALIZE xxxxxx | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY |--MATERIALIZE xxxxxx | `--SCAN TABLE t2 USING INDEX t2i1 |--SCAN SUBQUERY xxxxxx AS x1 |--SCAN SUBQUERY xxxxxx AS x2 `--USE TEMP B-TREE FOR ORDER BY } det 3.3.1 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2) } { QUERY PLAN |--SCAN TABLE t1 `--LIST SUBQUERY `--SCAN TABLE t2 } det 3.3.2 { SELECT * FROM t1 WHERE y IN (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN TABLE t1 `--CORRELATED LIST SUBQUERY `--SCAN TABLE t2 } det 3.3.3 { SELECT * FROM t1 WHERE EXISTS (SELECT y FROM t2 WHERE t1.x!=t2.x) } { QUERY PLAN |--SCAN TABLE t1 `--CORRELATED SCALAR SUBQUERY `--SCAN TABLE t2 } #------------------------------------------------------------------------- # Test cases eqp-4.* - tests for composite select statements. # do_eqp_test 4.1.1 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN TABLE t1 `--UNION ALL `--SCAN TABLE t2 } do_eqp_test 4.1.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (UNION) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (INTERSECT) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.1.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 2 } { QUERY PLAN `--MERGE (EXCEPT) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test 4.2.2 { SELECT * FROM t1 UNION ALL SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT `--SCAN TABLE t2 USING INDEX t2i1 } do_eqp_test 4.2.3 { SELECT * FROM t1 UNION SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.4 { SELECT * FROM t1 INTERSECT SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (INTERSECT) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.2.5 { SELECT * FROM t1 EXCEPT SELECT * FROM t2 ORDER BY 1 } { QUERY PLAN `--MERGE (EXCEPT) |--LEFT | |--SCAN TABLE t1 | `--USE TEMP B-TREE FOR ORDER BY `--RIGHT |--SCAN TABLE t2 USING INDEX t2i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_eqp_test 4.3.1 { SELECT x FROM t1 UNION SELECT x FROM t2 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN TABLE t1 `--UNION USING TEMP B-TREE `--SCAN TABLE t2 USING COVERING INDEX t2i1 } do_eqp_test 4.3.2 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 } { QUERY PLAN `--COMPOUND QUERY |--LEFT-MOST SUBQUERY | `--SCAN TABLE t1 |--UNION USING TEMP B-TREE | `--SCAN TABLE t2 USING COVERING INDEX t2i1 `--UNION USING TEMP B-TREE `--SCAN TABLE t1 } do_eqp_test 4.3.3 { SELECT x FROM t1 UNION SELECT x FROM t2 UNION SELECT x FROM t1 ORDER BY 1 } { QUERY PLAN `--MERGE (UNION) |--LEFT | `--MERGE (UNION) | |--LEFT | | |--SCAN TABLE t1 | | `--USE TEMP B-TREE FOR ORDER BY | `--RIGHT | `--SCAN TABLE t2 USING COVERING INDEX t2i1 `--RIGHT |--SCAN TABLE t1 `--USE TEMP B-TREE FOR ORDER BY } if 0 { #------------------------------------------------------------------------- # This next block of tests verifies that the examples on the # lang_explain.html page are correct. # drop_all_tables # XVIDENCE-OF: R-47779-47605 sqlite> EXPLAIN QUERY PLAN SELECT a, b # FROM t1 WHERE a=1; # 0|0|0|SCAN TABLE t1 # do_execsql_test 5.1.0 { CREATE TABLE t1(a INT, b INT, ex TEXT) } det 5.1.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SCAN TABLE t1} } # XVIDENCE-OF: R-55852-17599 sqlite> CREATE INDEX i1 ON t1(a); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH TABLE t1 USING INDEX i1 # do_execsql_test 5.2.0 { CREATE INDEX i1 ON t1(a) } det 5.2.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } # XVIDENCE-OF: R-21179-11011 sqlite> CREATE INDEX i2 ON t1(a, b); # sqlite> EXPLAIN QUERY PLAN SELECT a, b FROM t1 WHERE a=1; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # do_execsql_test 5.3.0 { CREATE INDEX i2 ON t1(a, b) } det 5.3.1 "SELECT a, b FROM t1 WHERE a=1" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} } # XVIDENCE-OF: R-09991-48941 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t1, t2 WHERE t1.a=1 AND t1.b>2; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|1|SCAN TABLE t2 # do_execsql_test 5.4.0 {CREATE TABLE t2(c INT, d INT, ex TEXT)} det 5.4.1 "SELECT t1.a, t2.c FROM t1, t2 WHERE t1.a=1 AND t1.b>2" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 1 {SCAN TABLE t2} } # XVIDENCE-OF: R-33626-61085 sqlite> EXPLAIN QUERY PLAN # SELECT t1.*, t2.* FROM t2, t1 WHERE t1.a=1 AND t1.b>2; # 0|0|1|SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?) # 0|1|0|SCAN TABLE t2 # det 5.5 "SELECT t1.a, t2.c FROM t2, t1 WHERE t1.a=1 AND t1.b>2" { 0 0 1 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=? AND b>?)} 0 1 0 {SCAN TABLE t2} } # XVIDENCE-OF: R-04002-25654 sqlite> CREATE INDEX i3 ON t1(b); # sqlite> EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a=1 OR b=2; # 0|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) # do_execsql_test 5.5.0 {CREATE INDEX i3 ON t1(b)} det 5.6.1 "SELECT a, b FROM t1 WHERE a=1 OR b=2" { 0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-24577-38891 sqlite> EXPLAIN QUERY PLAN # SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN TABLE t2 # 0|0|0|USE TEMP B-TREE FOR ORDER BY # det 5.7 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # XVIDENCE-OF: R-58157-12355 sqlite> CREATE INDEX i4 ON t2(c); # sqlite> EXPLAIN QUERY PLAN SELECT c, d FROM t2 ORDER BY c; # 0|0|0|SCAN TABLE t2 USING INDEX i4 # do_execsql_test 5.8.0 {CREATE INDEX i4 ON t2(c)} det 5.8.1 "SELECT c, d FROM t2 ORDER BY c" { 0 0 0 {SCAN TABLE t2 USING INDEX i4} } # XVIDENCE-OF: R-13931-10421 sqlite> EXPLAIN QUERY PLAN SELECT # (SELECT b FROM t1 WHERE a=0), (SELECT a FROM t1 WHERE b=t2.c) FROM t2; # 0|0|0|SCAN TABLE t2 # 0|0|0|EXECUTE SCALAR SUBQUERY 1 # 1|0|0|SEARCH TABLE t1 USING COVERING INDEX i2 (a=?) # 0|0|0|EXECUTE CORRELATED SCALAR SUBQUERY 2 # 2|0|0|SEARCH TABLE t1 USING INDEX i3 (b=?) # ................................................................................ 0 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {EXECUTE SCALAR SUBQUERY 1} 1 0 0 {SEARCH TABLE t1 USING COVERING INDEX i2 (a=?)} 0 0 0 {EXECUTE CORRELATED SCALAR SUBQUERY 2} 2 0 0 {SEARCH TABLE t1 USING INDEX i3 (b=?)} } # XVIDENCE-OF: R-50892-45943 sqlite> EXPLAIN QUERY PLAN # SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x; # 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 # 0|0|0|SCAN SUBQUERY 1 # 0|0|0|USE TEMP B-TREE FOR GROUP BY # det 5.10 { SELECT count(*) FROM (SELECT max(b) AS x FROM t1 GROUP BY a) GROUP BY x } { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} 0 0 0 {SCAN SUBQUERY 1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } # XVIDENCE-OF: R-46219-33846 sqlite> EXPLAIN QUERY PLAN # SELECT * FROM (SELECT * FROM t2 WHERE c=1), t1; # 0|0|0|SEARCH TABLE t2 USING INDEX i4 (c=?) # 0|1|1|SCAN TABLE t1 # det 5.11 "SELECT a, b FROM (SELECT * FROM t2 WHERE c=1), t1" { 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} 0 1 1 {SCAN TABLE t1 USING COVERING INDEX i2} } # XVIDENCE-OF: R-37879-39987 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 UNION SELECT c FROM t2; # 1|0|0|SCAN TABLE t1 # 2|0|0|SCAN TABLE t2 # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION) # det 5.12 "SELECT a,b FROM t1 UNION SELECT c, 99 FROM t2" { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i2} 2 0 0 {SCAN TABLE t2 USING COVERING INDEX i4} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 USING TEMP B-TREE (UNION)} } # XVIDENCE-OF: R-44864-63011 sqlite> EXPLAIN QUERY PLAN # SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1; # 1|0|0|SCAN TABLE t1 USING COVERING INDEX i2 # 2|0|0|SCAN TABLE t2 2|0|0|USE TEMP B-TREE FOR ORDER BY # 0|0|0|COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) # det 5.13 "SELECT a FROM t1 EXCEPT SELECT d FROM t2 ORDER BY 1" { 1 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 2 0 0 {SCAN TABLE t2} 2 0 0 {USE TEMP B-TREE FOR ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (EXCEPT)} } if {![nonzero_reserved_bytes]} { #------------------------------------------------------------------------- # The following tests - eqp-6.* - test that the example C code on # documentation page eqp.html works. The C code is duplicated in test1.c # and wrapped in Tcl command [print_explain_query_plan] # ................................................................................ } [string trimleft { 1 0 0 SCAN TABLE t1 USING COVERING INDEX i2 2 0 0 SCAN TABLE t2 2 0 0 USE TEMP B-TREE FOR ORDER BY 0 0 0 COMPOUND SUBQUERIES 1 AND 2 (EXCEPT) }] } } #------------------------------------------------------------------------- # The following tests - eqp-7.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables ................................................................................ do_execsql_test 7.0 { CREATE TABLE t1(a INT, b INT, ex CHAR(100)); CREATE TABLE t2(a INT, b INT, ex CHAR(100)); CREATE INDEX i1 ON t2(a); } det 7.1 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE t1 } det 7.2 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE t2 USING COVERING INDEX i1 } do_execsql_test 7.3 { INSERT INTO t1(a,b) VALUES(1, 2); INSERT INTO t1(a,b) VALUES(3, 4); INSERT INTO t2(a,b) VALUES(1, 2); ................................................................................ ANALYZE; } db close sqlite3 db test.db det 7.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE t1 } det 7.5 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE t2 USING COVERING INDEX i1 } #------------------------------------------------------------------------- # The following tests - eqp-8.* - test that queries that use the OP_Count # optimization return something sensible with EQP. # drop_all_tables ................................................................................ do_execsql_test 8.0 { CREATE TABLE t1(a, b, c, PRIMARY KEY(b, c)) WITHOUT ROWID; CREATE TABLE t2(a, b, c); } det 8.1.1 "SELECT * FROM t2" { QUERY PLAN `--SCAN TABLE t2 } det 8.1.2 "SELECT * FROM t2 WHERE rowid=?" { QUERY PLAN `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } det 8.1.3 "SELECT count(*) FROM t2" { QUERY PLAN `--SCAN TABLE t2 } det 8.2.1 "SELECT * FROM t1" { QUERY PLAN `--SCAN TABLE t1 } det 8.2.2 "SELECT * FROM t1 WHERE b=?" { QUERY PLAN `--SEARCH TABLE t1 USING PRIMARY KEY (b=?) } det 8.2.3 "SELECT * FROM t1 WHERE b=? AND c=?" { QUERY PLAN `--SEARCH TABLE t1 USING PRIMARY KEY (b=? AND c=?) } det 8.2.4 "SELECT count(*) FROM t1" { QUERY PLAN `--SCAN TABLE t1 } finish_test |
Changes to test/fts3aux1.test.
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 ... 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 ... 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 ... 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 |
db func rec rec # Use EQP to show that the WHERE expression "term='braid'" uses a different # index number (1) than "+term='braid'" (0). # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} } do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' } {0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. # do_test 2.1.2.1 { set cnt 0 execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND term='braid' } ................................................................................ # Special case: term=NULL # do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 2:} } do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 4:} } do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 6:} } do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} } do_test 2.2.2.1 { set cnt 0 execsql { SELECT * FROM terms WHERE rec('cnt', term) AND term>'brain' } set cnt } {18} do_test 2.2.2.2 { ................................................................................ 5 1 "ORDER BY documents" 6 1 "ORDER BY documents DESC" 7 1 "ORDER BY occurrences ASC" 8 1 "ORDER BY occurrences" 9 1 "ORDER BY occurrences DESC" } { set res [list 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:}] if {$sort} { lappend res 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } set sql "SELECT * FROM terms $orderby" do_execsql_test 2.3.1.$tn "EXPLAIN QUERY PLAN $sql" $res } #------------------------------------------------------------------------- # The next set of tests, fts3aux1-3.*, test error conditions in the ................................................................................ INSERT INTO x1 VALUES('f g h i j'); INSERT INTO x1 VALUES('k k l l a'); INSERT INTO x2 SELECT term FROM terms WHERE col = '*'; INSERT INTO x3 SELECT term FROM terms WHERE col = '*'; } proc do_plansql_test {tn sql r} { uplevel do_execsql_test $tn [list "EXPLAIN QUERY PLAN $sql ; $sql"] [list $r] } do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { 0 0 0 {SCAN TABLE x2} 0 1 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { 0 0 1 {SCAN TABLE x2} 0 1 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 1:} a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { 0 0 1 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} 0 1 0 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a b c d e f g h i j k l } do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { 0 0 0 {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} 0 1 1 {SEARCH TABLE x3 USING COVERING INDEX i1 (y=?)} a k l } #------------------------------------------------------------------------- # The following tests check that fts4aux can handle an fts table with an # odd name (one that requires quoting for use in SQL statements). And that # the argument to the fts4aux constructor is properly dequoted before use. |
| | | | | | | | | | > | > | > | | > > | | > > | | > > | | > |
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 ... 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 ... 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 ... 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 |
db func rec rec # Use EQP to show that the WHERE expression "term='braid'" uses a different # index number (1) than "+term='braid'" (0). # do_execsql_test 2.1.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term='braid' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 1:*/} do_execsql_test 2.1.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term='braid' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} # Now show that using "term='braid'" means the virtual table returns # only 1 row to SQLite, but "+term='braid'" means all 19 are returned. # do_test 2.1.2.1 { set cnt 0 execsql { SELECT * FROM terms_v WHERE rec('cnt', term) AND term='braid' } ................................................................................ # Special case: term=NULL # do_execsql_test 2.1.5 { SELECT * FROM terms WHERE term=NULL } {} do_execsql_test 2.2.1.1 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term>'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 2:*/} do_execsql_test 2.2.1.2 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term>'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.3 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term<'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 4:*/} do_execsql_test 2.2.1.4 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term<'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} do_execsql_test 2.2.1.5 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE term BETWEEN 'brags' AND 'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 6:*/} do_execsql_test 2.2.1.6 { EXPLAIN QUERY PLAN SELECT * FROM terms WHERE +term BETWEEN 'brags' AND 'brain' } {/*SCAN TABLE terms VIRTUAL TABLE INDEX 0:*/} do_test 2.2.2.1 { set cnt 0 execsql { SELECT * FROM terms WHERE rec('cnt', term) AND term>'brain' } set cnt } {18} do_test 2.2.2.2 { ................................................................................ 5 1 "ORDER BY documents" 6 1 "ORDER BY documents DESC" 7 1 "ORDER BY occurrences ASC" 8 1 "ORDER BY occurrences" 9 1 "ORDER BY occurrences DESC" } { set res {SCAN TABLE terms VIRTUAL TABLE INDEX 0:} if {$sort} { append res {*USE TEMP B-TREE FOR ORDER BY} } set res "/*$res*/" set sql "SELECT * FROM terms $orderby" do_execsql_test 2.3.1.$tn "EXPLAIN QUERY PLAN $sql" $res } #------------------------------------------------------------------------- # The next set of tests, fts3aux1-3.*, test error conditions in the ................................................................................ INSERT INTO x1 VALUES('f g h i j'); INSERT INTO x1 VALUES('k k l l a'); INSERT INTO x2 SELECT term FROM terms WHERE col = '*'; INSERT INTO x3 SELECT term FROM terms WHERE col = '*'; } proc do_plansql_test {tn sql r1 r2} { do_eqp_test $tn.eqp $sql $r1 do_execsql_test $tn $sql $r2 } do_plansql_test 4.2 { SELECT y FROM x2, terms WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN TABLE x2 `--SCAN TABLE terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } do_plansql_test 4.3 { SELECT y FROM terms, x2 WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN TABLE x2 `--SCAN TABLE terms VIRTUAL TABLE INDEX 1: } { a b c d e f g h i j k l } do_plansql_test 4.4 { SELECT y FROM x3, terms WHERE y = term AND col = '*' } { QUERY PLAN |--SCAN TABLE terms VIRTUAL TABLE INDEX 0: `--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) } { a b c d e f g h i j k l } do_plansql_test 4.5 { SELECT y FROM terms, x3 WHERE y = term AND occurrences>1 AND col = '*' } { QUERY PLAN |--SCAN TABLE terms VIRTUAL TABLE INDEX 0: `--SEARCH TABLE x3 USING COVERING INDEX i1 (y=?) } { a k l } #------------------------------------------------------------------------- # The following tests check that fts4aux can handle an fts table with an # odd name (one that requires quoting for use in SQL statements). And that # the argument to the fts4aux constructor is properly dequoted before use. |
Changes to test/fts3join.test.
92 93 94 95 96 97 98 99 100 101 102 103 104 |
do_eqp_test 4.2 { SELECT * FROM t4 LEFT JOIN ( SELECT docid, * FROM ft4 WHERE ft4 MATCH ? ) AS rr ON t4.rowid=rr.docid WHERE t4.y = ?; } { 1 0 0 {SCAN TABLE ft4 VIRTUAL TABLE INDEX 3:} 0 0 0 {SCAN TABLE t4} 0 1 1 {SEARCH SUBQUERY 1 AS rr USING AUTOMATIC COVERING INDEX (docid=?)} } finish_test |
> > | | | |
92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 |
do_eqp_test 4.2 { SELECT * FROM t4 LEFT JOIN ( SELECT docid, * FROM ft4 WHERE ft4 MATCH ? ) AS rr ON t4.rowid=rr.docid WHERE t4.y = ?; } { QUERY PLAN |--MATERIALIZE xxxxxx | `--SCAN TABLE ft4 VIRTUAL TABLE INDEX 3: |--SCAN TABLE t4 `--SEARCH SUBQUERY xxxxxx AS rr USING AUTOMATIC COVERING INDEX (docid=?) } finish_test |
Changes to test/fts3query.test.
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 |
CREATE VIRTUAL TABLE ft USING fts3(title); CREATE TABLE bt(title); } } {} do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 0 1 1 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} 0 1 0 {SCAN TABLE ft VIRTUAL TABLE INDEX 1:} } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1} 0 1 1 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { 0 0 1 {SCAN TABLE t1 USING COVERING INDEX i1} 0 1 0 {SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?)} } # Test that calling matchinfo() with the wrong number of arguments, or with # an invalid argument returns an error. # do_execsql_test 5.1 { |
> | | > | | > | | > | | |
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
CREATE VIRTUAL TABLE ft USING fts3(title); CREATE TABLE bt(title); } } {} do_eqp_test fts3query-4.2 { SELECT t1.number FROM t1, ft WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX i1 `--SCAN TABLE ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.3 { SELECT t1.number FROM ft, t1 WHERE t1.number=ft.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX i1 `--SCAN TABLE ft VIRTUAL TABLE INDEX 1: } do_eqp_test fts3query-4.4 { SELECT t1.number FROM t1, bt WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX i1 `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test fts3query-4.5 { SELECT t1.number FROM bt, t1 WHERE t1.number=bt.rowid ORDER BY t1.date } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX i1 `--SEARCH TABLE bt USING INTEGER PRIMARY KEY (rowid=?) } # Test that calling matchinfo() with the wrong number of arguments, or with # an invalid argument returns an error. # do_execsql_test 5.1 { |
Changes to test/index6.test.
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 |
INSERT INTO t8b VALUES('value', 3); INSERT INTO t8b VALUES('dummy', 4); } {} do_eqp_test index6-8.1 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { 0 0 0 {SCAN TABLE t8a} 0 1 1 {SEARCH TABLE t8b USING INDEX i8c (y=?)} } do_execsql_test index6-8.2 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { 1 one value 1 2 two {} {} |
> | | |
314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 |
INSERT INTO t8b VALUES('value', 3); INSERT INTO t8b VALUES('dummy', 4); } {} do_eqp_test index6-8.1 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { QUERY PLAN |--SCAN TABLE t8a `--SEARCH TABLE t8b USING INDEX i8c (y=?) } do_execsql_test index6-8.2 { SELECT * FROM t8a LEFT JOIN t8b ON (x = 'value' AND y = a) } { 1 one value 1 2 two {} {} |
Changes to test/index7.test.
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 |
INSERT INTO t4 VALUES('def', 'xyz'); SELECT * FROM v4 WHERE d='xyz' AND c='def' } { def xyz } do_eqp_test index7-6.4 { SELECT * FROM v4 WHERE d='xyz' AND c='def' } { 0 0 0 {SEARCH TABLE t4 USING INDEX i4 (c=?)} } do_catchsql_test index7-6.5 { CREATE INDEX t5a ON t5(a) WHERE a=#1; } {1 {near "#1": syntax error}} finish_test |
< | | |
317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 |
INSERT INTO t4 VALUES('def', 'xyz');
SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {
def xyz
}
do_eqp_test index7-6.4 {
SELECT * FROM v4 WHERE d='xyz' AND c='def'
} {SEARCH TABLE t4 USING INDEX i4 (c=?)}
do_catchsql_test index7-6.5 {
CREATE INDEX t5a ON t5(a) WHERE a=#1;
} {1 {near "#1": syntax error}}
finish_test
|
Changes to test/indexedby.test.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 ... 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 ... 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 ... 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 ... 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 ... 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 |
# proc EQP {sql} { uplevel "execsql {EXPLAIN QUERY PLAN $sql}" } # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. # do_execsql_test indexedby-1.2 { EXPLAIN QUERY PLAN select * from t1 WHERE a = 10; } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-1.3 { EXPLAIN QUERY PLAN select * from t1 ; } {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-1.4 { EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10; } { 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} 0 1 0 {SCAN TABLE t1} } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be # attached to a table in the FROM clause, but not to a sub-select or # SQL view. Also test that specifying an index that does not exist or # is attached to a different table is detected as an error. # ................................................................................ # # EVIDENCE-OF: R-37002-28871 The "NOT INDEXED" clause specifies that no # index shall be used when accessing the preceding table, including # implied indices create by UNIQUE and PRIMARY KEY constraints. However, # the rowid can still be used to look up entries even when "NOT INDEXED" # is specified. # do_execsql_test indexedby-3.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE a = 'one' AND b = 'two' } {/SEARCH TABLE t1 USING INDEX/} do_execsql_test indexedby-3.1.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' } {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-3.1.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE rowid=1 } {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/} do_execsql_test indexedby-3.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-3.3 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {1 {no query solution}} do_test indexedby-3.5 { catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } } {1 {no query solution}} do_test indexedby-3.6 { catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } } {0 {}} do_test indexedby-3.7 { catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a } } {0 {}} do_execsql_test indexedby-3.8 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e } {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}} do_execsql_test indexedby-3.9 { EXPLAIN QUERY PLAN SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 } {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } } {1 {no query solution}} do_test indexedby-3.11 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } } {1 {no such index: sqlite_autoindex_t3_2}} # Tests for multiple table cases. # do_execsql_test indexedby-4.1 { EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)} } do_execsql_test indexedby-4.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { 0 0 1 {SCAN TABLE t2} 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} } do_test indexedby-4.3 { catchsql { SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c } } {1 {no query solution}} do_test indexedby-4.4 { ................................................................................ # Test embedding an INDEXED BY in a CREATE VIEW statement. This block # also tests that nothing bad happens if an index refered to by # a CREATE VIEW statement is dropped and recreated. # do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } } {1 {no such index: i1}} do_test indexedby-5.4 { # Recreate index i1 in such a way as it cannot be used by the view query. execsql { CREATE INDEX i1 ON t1(b) } ................................................................................ # be used by the query. execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) } catchsql { SELECT * FROM v2 } } {0 {}} # Test that "NOT INDEXED" may use the rowid index, but not others. # do_execsql_test indexedby-6.1 { EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_execsql_test indexedby-6.2 { EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } {0 0 0 {SCAN TABLE t1}} # EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite # query planner to use a particular named index on a DELETE, SELECT, or # UPDATE statement. # # Test that "INDEXED BY" can be used in a DELETE statement. # do_execsql_test indexedby-7.1 { EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-7.2 { EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5 } {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-7.3 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-7.4 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-7.5 { EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {1 {no query solution}} # Test that "INDEXED BY" can be used in an UPDATE statement. # do_execsql_test indexedby-8.1 { EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.2 { EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 } {0 0 0 {SCAN TABLE t1}} do_execsql_test indexedby-8.3 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}} do_execsql_test indexedby-8.4 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_execsql_test indexedby-8.5 { EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {1 {no query solution}} # Test that bug #3560 is fixed. # do_test indexedby-9.1 { ................................................................................ SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; } {1 1 3} do_execsql_test 11.4 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {1 1 3} do_eqp_test 11.5 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}} do_execsql_test 11.6 { CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); CREATE INDEX x2i ON x2(a, b); INSERT INTO x2 VALUES(1, 1, 1); INSERT INTO x2 VALUES(2, 1, 1); INSERT INTO x2 VALUES(3, 1, 1); ................................................................................ SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3'; } {1 1 3} do_execsql_test 11.9 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {1 1 3} do_eqp_test 11.10 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}} #------------------------------------------------------------------------- # Check INDEXED BY works (throws an exception) with partial indexes that # cannot be used. do_execsql_test 12.1 { CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z); CREATE INDEX p1 ON o1(z); |
| | | | | | | | > | | | | | | | | | | < | | < | | < | | < | | | > | | | | > | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | | < | | < | | | |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 ... 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 ... 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 ... 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 ... 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 ... 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 |
# proc EQP {sql} { uplevel "execsql {EXPLAIN QUERY PLAN $sql}" } # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected. # do_eqp_test indexedby-1.2 { select * from t1 WHERE a = 10; } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-1.3 { select * from t1 ; } {SCAN TABLE t1} do_eqp_test indexedby-1.4 { select * from t1, t2 WHERE c = 10; } { QUERY PLAN |--SEARCH TABLE t2 USING INDEX i3 (c=?) `--SCAN TABLE t1 } # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be # attached to a table in the FROM clause, but not to a sub-select or # SQL view. Also test that specifying an index that does not exist or # is attached to a different table is detected as an error. # ................................................................................ # # EVIDENCE-OF: R-37002-28871 The "NOT INDEXED" clause specifies that no # index shall be used when accessing the preceding table, including # implied indices create by UNIQUE and PRIMARY KEY constraints. However, # the rowid can still be used to look up entries even when "NOT INDEXED" # is specified. # do_eqp_test indexedby-3.1 { SELECT * FROM t1 WHERE a = 'one' AND b = 'two' } {/SEARCH TABLE t1 USING INDEX/} do_eqp_test indexedby-3.1.1 { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two' } {SCAN TABLE t1} do_eqp_test indexedby-3.1.2 { SELECT * FROM t1 NOT INDEXED WHERE rowid=1 } {/SEARCH TABLE t1 USING INTEGER PRIMARY KEY .rowid=/} do_eqp_test indexedby-3.2 { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two' } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-3.3 { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two' } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-3.4 { catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' } } {1 {no query solution}} do_test indexedby-3.5 { catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a } } {1 {no query solution}} do_test indexedby-3.6 { catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' } } {0 {}} do_test indexedby-3.7 { catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a } } {0 {}} do_eqp_test indexedby-3.8 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e } {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1} do_eqp_test indexedby-3.9 { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10 } {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)} do_test indexedby-3.10 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 } } {1 {no query solution}} do_test indexedby-3.11 { catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 } } {1 {no such index: sqlite_autoindex_t3_2}} # Tests for multiple table cases. # do_eqp_test indexedby-4.1 { SELECT * FROM t1, t2 WHERE a = c } { QUERY PLAN |--SCAN TABLE t1 `--SEARCH TABLE t2 USING INDEX i3 (c=?) } do_eqp_test indexedby-4.2 { SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c } { QUERY PLAN |--SCAN TABLE t2 `--SEARCH TABLE t1 USING INDEX i1 (a=?) } do_test indexedby-4.3 { catchsql { SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c } } {1 {no query solution}} do_test indexedby-4.4 { ................................................................................ # Test embedding an INDEXED BY in a CREATE VIEW statement. This block # also tests that nothing bad happens if an index refered to by # a CREATE VIEW statement is dropped and recreated. # do_execsql_test indexedby-5.1 { CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5; EXPLAIN QUERY PLAN SELECT * FROM v2 } {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/} do_execsql_test indexedby-5.2 { EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10 } {/*SEARCH TABLE t1 USING INDEX i1 (a>?)*/} do_test indexedby-5.3 { execsql { DROP INDEX i1 } catchsql { SELECT * FROM v2 } } {1 {no such index: i1}} do_test indexedby-5.4 { # Recreate index i1 in such a way as it cannot be used by the view query. execsql { CREATE INDEX i1 ON t1(b) } ................................................................................ # be used by the query. execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) } catchsql { SELECT * FROM v2 } } {0 {}} # Test that "NOT INDEXED" may use the rowid index, but not others. # do_eqp_test indexedby-6.1 { SELECT * FROM t1 WHERE b = 10 ORDER BY rowid } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_eqp_test indexedby-6.2 { SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid } {SCAN TABLE t1} # EVIDENCE-OF: R-40297-14464 The INDEXED BY phrase forces the SQLite # query planner to use a particular named index on a DELETE, SELECT, or # UPDATE statement. # # Test that "INDEXED BY" can be used in a DELETE statement. # do_eqp_test indexedby-7.1 { DELETE FROM t1 WHERE a = 5 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.2 { DELETE FROM t1 NOT INDEXED WHERE a = 5 } {SCAN TABLE t1} do_eqp_test indexedby-7.3 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.4 { DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-7.5 { DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-7.6 { catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5} } {1 {no query solution}} # Test that "INDEXED BY" can be used in an UPDATE statement. # do_eqp_test indexedby-8.1 { UPDATE t1 SET rowid=rowid+1 WHERE a = 5 } {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.2 { UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5 } {SCAN TABLE t1} do_eqp_test indexedby-8.3 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 } {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)} do_eqp_test indexedby-8.4 { UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test indexedby-8.5 { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10 } {SEARCH TABLE t1 USING INDEX i2 (b=?)} do_test indexedby-8.6 { catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5} } {1 {no query solution}} # Test that bug #3560 is fixed. # do_test indexedby-9.1 { ................................................................................ SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3'; } {1 1 3} do_execsql_test 11.4 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {1 1 3} do_eqp_test 11.5 { SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0'; } {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)} do_execsql_test 11.6 { CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT); CREATE INDEX x2i ON x2(a, b); INSERT INTO x2 VALUES(1, 1, 1); INSERT INTO x2 VALUES(2, 1, 1); INSERT INTO x2 VALUES(3, 1, 1); ................................................................................ SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3'; } {1 1 3} do_execsql_test 11.9 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {1 1 3} do_eqp_test 11.10 { SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0'; } {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)} #------------------------------------------------------------------------- # Check INDEXED BY works (throws an exception) with partial indexes that # cannot be used. do_execsql_test 12.1 { CREATE TABLE o1(x INTEGER PRIMARY KEY, y, z); CREATE INDEX p1 ON o1(z); |
Changes to test/indexexpr2.test.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 |
ifcapable json1 { do_eqp_test 3.3.1 { SELECT json_extract(x, '$.b') FROM t2 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } { 0 0 0 {SCAN TABLE t2} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } do_execsql_test 3.3.2 { CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b')); } {} do_eqp_test 3.3.3 { SELECT json_extract(x, '$.b') FROM t3 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } { 0 0 0 {SEARCH TABLE t3 USING INDEX i3 (<expr>=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} } } do_execsql_test 3.4.0 { CREATE TABLE t4(a, b); INSERT INTO t4 VALUES('.ABC', 1); INSERT INTO t4 VALUES('.abc', 2); INSERT INTO t4 VALUES('.ABC', 3); |
| > | | | | > | | | |
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
ifcapable json1 { do_eqp_test 3.3.1 { SELECT json_extract(x, '$.b') FROM t2 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN |--SCAN TABLE t2 `--USE TEMP B-TREE FOR GROUP BY }] do_execsql_test 3.3.2 { CREATE INDEX i3 ON t3(json_extract(x, '$.a'), json_extract(x, '$.b')); } {} do_eqp_test 3.3.3 { SELECT json_extract(x, '$.b') FROM t3 WHERE json_extract(x, '$.b') IS NOT NULL AND json_extract(x, '$.a') IS NULL GROUP BY json_extract(x, '$.b') COLLATE nocase ORDER BY json_extract(x, '$.b') COLLATE nocase; } [string map {"\n " \n} { QUERY PLAN |--SEARCH TABLE t3 USING INDEX i3 (<expr>=?) `--USE TEMP B-TREE FOR GROUP BY }] } do_execsql_test 3.4.0 { CREATE TABLE t4(a, b); INSERT INTO t4 VALUES('.ABC', 1); INSERT INTO t4 VALUES('.abc', 2); INSERT INTO t4 VALUES('.ABC', 3); |
Changes to test/join2.test.
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 ... 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 ... 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 ... 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
CREATE TABLE t3_1(k3 PRIMARY KEY, v3) WITHOUT ROWID; CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID; } do_eqp_test 3.1 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3); } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test 3.2 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3); } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?)} } #------------------------------------------------------------------------- # Test that tables other than the rightmost can be omitted from a # LEFT JOIN query. # do_execsql_test 4.0 { ................................................................................ do_execsql_test 4.1.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { 0 0 0 {SCAN TABLE c1} 0 1 1 {SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?)} 0 2 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)} } do_eqp_test 4.1.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { 0 0 0 {SCAN TABLE c1} 0 1 2 {SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test 4.2.0 { DROP TABLE c1; DROP TABLE c2; DROP TABLE c3; CREATE TABLE c1(k UNIQUE, v1); ................................................................................ do_execsql_test 4.2.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { 0 0 0 {SCAN TABLE c1} 0 1 1 {SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?)} 0 2 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)} } do_eqp_test 4.2.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { 0 0 0 {SCAN TABLE c1} 0 1 2 {SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?)} } # 2017-11-23 (Thanksgiving day) # OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code. # do_execsql_test 4.3.0 { DROP TABLE IF EXISTS t1; ................................................................................ CREATE TABLE s1 (a INTEGER PRIMARY KEY); CREATE TABLE s2 (a INTEGER PRIMARY KEY); CREATE TABLE s3 (a INTEGER); CREATE UNIQUE INDEX ndx on s3(a); } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); } { 0 0 0 {SCAN TABLE s1} } do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); } { 0 0 0 {SCAN TABLE s1} } do_execsql_test 6.0 { CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX u1ab ON u1(b, c); } do_eqp_test 6.1 { SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c ); } { 0 0 0 {SCAN TABLE u2} } db close sqlite3 db :memory: do_execsql_test 7.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2),(3,4),(5,6); CREATE TABLE t2(c,d); INSERT INTO t2 VALUES(2,4),(3,6); CREATE TABLE t3(x); INSERT INTO t3 VALUES(9); |
> | | > | | > | | | > | | > | | | > | | < | | < | < < | < |
108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 ... 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 ... 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 ... 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 |
CREATE TABLE t3_1(k3 PRIMARY KEY, v3) WITHOUT ROWID; CREATE TABLE t3_2(v3, k3 PRIMARY KEY) WITHOUT ROWID; } do_eqp_test 3.1 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_1 USING (k3); } { QUERY PLAN |--SCAN TABLE t1 `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 3.2 { SELECT v2 FROM t1 LEFT JOIN t2 USING (k2) LEFT JOIN t3_2 USING (k3); } { QUERY PLAN |--SCAN TABLE t1 `--SEARCH TABLE t2 USING INTEGER PRIMARY KEY (rowid=?) } #------------------------------------------------------------------------- # Test that tables other than the rightmost can be omitted from a # LEFT JOIN query. # do_execsql_test 4.0 { ................................................................................ do_execsql_test 4.1.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.1.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN |--SCAN TABLE c1 |--SEARCH TABLE c2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test 4.1.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN |--SCAN TABLE c1 `--SEARCH TABLE c3 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test 4.2.0 { DROP TABLE c1; DROP TABLE c2; DROP TABLE c3; CREATE TABLE c1(k UNIQUE, v1); ................................................................................ do_execsql_test 4.2.4 { SELECT v1, v3 FROM c1 LEFT JOIN c2 LEFT JOIN c3 ON (c3.k=v1+1); } {2 v3 2 v3 1112 {} 1112 {}} do_eqp_test 4.2.5 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v2); } { QUERY PLAN |--SCAN TABLE c1 |--SEARCH TABLE c2 USING INDEX sqlite_autoindex_c2_1 (k=?) `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } do_eqp_test 4.2.6 { SELECT v1, v3 FROM c1 LEFT JOIN c2 ON (c2.k=v1) LEFT JOIN c3 ON (c3.k=v1+1); } { QUERY PLAN |--SCAN TABLE c1 `--SEARCH TABLE c3 USING INDEX sqlite_autoindex_c3_1 (k=?) } # 2017-11-23 (Thanksgiving day) # OSSFuzz found an assertion fault in the new LEFT JOIN eliminator code. # do_execsql_test 4.3.0 { DROP TABLE IF EXISTS t1; ................................................................................ CREATE TABLE s1 (a INTEGER PRIMARY KEY); CREATE TABLE s2 (a INTEGER PRIMARY KEY); CREATE TABLE s3 (a INTEGER); CREATE UNIQUE INDEX ndx on s3(a); } do_eqp_test 5.1 { SELECT s1.a FROM s1 left join s2 using (a); } {SCAN TABLE s1} do_eqp_test 5.2 { SELECT s1.a FROM s1 left join s3 using (a); } {SCAN TABLE s1} do_execsql_test 6.0 { CREATE TABLE u1(a INTEGER PRIMARY KEY, b, c); CREATE TABLE u2(a INTEGER PRIMARY KEY, b, c); CREATE INDEX u1ab ON u1(b, c); } do_eqp_test 6.1 { SELECT u2.* FROM u2 LEFT JOIN u1 ON( u1.a=u2.a AND u1.b=u2.b AND u1.c=u2.c ); } {SCAN TABLE u2} db close sqlite3 db :memory: do_execsql_test 7.0 { CREATE TABLE t1(a,b); INSERT INTO t1 VALUES(1,2),(3,4),(5,6); CREATE TABLE t2(c,d); INSERT INTO t2 VALUES(2,4),(3,6); CREATE TABLE t3(x); INSERT INTO t3 VALUES(9); |
Changes to test/join5.test.
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
...
281
282
283
284
285
286
287
288
289
290
291
292
293
|
} do_eqp_test 7.2 { SELECT * FROM t1 LEFT JOIN t2 ON ( t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL)) ); } { 0 0 0 {SCAN TABLE t1} 0 1 1 {SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?)} } do_execsql_test 7.3 { CREATE TABLE t3(x); CREATE TABLE t4(x, y, z); CREATE INDEX t4xy ON t4(x, y); ................................................................................ ANALYZE; } do_eqp_test 7.4 { SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?); } { 0 0 0 {SCAN TABLE t3} 0 1 1 {SEARCH TABLE t4 USING INDEX t4xz (x=?)} } finish_test |
>
|
|
|
>
|
|
<
|
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
...
282
283
284
285
286
287
288
289
290
291
292
293
294
|
} do_eqp_test 7.2 { SELECT * FROM t1 LEFT JOIN t2 ON ( t2.x = t1.x AND (t2.y=? OR (t2.y=? AND t2.z IS NOT NULL)) ); } { QUERY PLAN |--SCAN TABLE t1 |--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?) `--SEARCH TABLE t2 USING INDEX t2xy (x=? AND y=?) } do_execsql_test 7.3 { CREATE TABLE t3(x); CREATE TABLE t4(x, y, z); CREATE INDEX t4xy ON t4(x, y); ................................................................................ ANALYZE; } do_eqp_test 7.4 { SELECT * FROM t3 LEFT JOIN t4 ON (t4.x = t3.x) WHERE (t4.y = ? OR t4.z = ?); } { QUERY PLAN |--SCAN TABLE t3 `--SEARCH TABLE t4 USING INDEX t4xz (x=?) } finish_test |
Changes to test/mallocK.test.
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 |
SELECT 'x' > '.'; } {1} ifcapable stat4 { do_eqp_test 6.1 { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; } { 0 0 0 {SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND b<?)} 0 0 0 {USE TEMP B-TREE FOR DISTINCT} } } do_faultsim_test 6 -faults oom* -body { db cache flush db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' } } -test { faultsim_test_result {0 {12 13 14 15}} |
| > | | | |
117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
SELECT 'x' > '.'; } {1} ifcapable stat4 { do_eqp_test 6.1 { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx'; } [string map {"\n " \n} { QUERY PLAN |--SEARCH TABLE t3 USING INDEX i3 (ANY(a) AND b>? AND b<?) `--USE TEMP B-TREE FOR DISTINCT }] } do_faultsim_test 6 -faults oom* -body { db cache flush db eval { SELECT DISTINCT c FROM t3 WHERE b BETWEEN '.xx..' AND '.xxxx' } } -test { faultsim_test_result {0 {12 13 14 15}} |
Changes to test/orderby1.test.
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
...
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
|
SELECT b, y FROM t41 CROSS JOIN t42 ON x=a ORDER BY b, y; } } {1 13 1 14 1 15 1 16} # No sorting of queries that omit the FROM clause. # do_execsql_test 5.0 { EXPLAIN QUERY PLAN SELECT 5 ORDER BY 1 } {} do_execsql_test 5.1 { EXPLAIN QUERY PLAN SELECT 5 UNION ALL SELECT 3 ORDER BY 1 } {~/B-TREE/} do_execsql_test 5.2 { SELECT 5 UNION ALL SELECT 3 ORDER BY 1 } {3 5} do_execsql_test 5.3 { ................................................................................ CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } do_eqp_test 8.1 { SELECT * FROM t1 ORDER BY a, b; } { 0 0 0 {SCAN TABLE t1 USING INDEX i1} 0 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} } do_execsql_test 8.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000 ) INSERT INTO t1 SELECT i%2, randomblob(500) FROM cnt; |
|
|
|
>
>
>
>
|
|
|
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
...
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
|
SELECT b, y FROM t41 CROSS JOIN t42 ON x=a ORDER BY b, y; } } {1 13 1 14 1 15 1 16} # No sorting of queries that omit the FROM clause. # do_eqp_test 5.0 { SELECT 5 ORDER BY 1 } { QUERY PLAN `--SCAN CONSTANT ROW } do_execsql_test 5.1 { EXPLAIN QUERY PLAN SELECT 5 UNION ALL SELECT 3 ORDER BY 1 } {~/B-TREE/} do_execsql_test 5.2 { SELECT 5 UNION ALL SELECT 3 ORDER BY 1 } {3 5} do_execsql_test 5.3 { ................................................................................ CREATE TABLE t1(a, b); CREATE INDEX i1 ON t1(a); } do_eqp_test 8.1 { SELECT * FROM t1 ORDER BY a, b; } { QUERY PLAN |--SCAN TABLE t1 USING INDEX i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_execsql_test 8.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt WHERE i<10000 ) INSERT INTO t1 SELECT i%2, randomblob(500) FROM cnt; |
Changes to test/rollback2.test.
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
} #-------------------------------------------------------------------- # Try with some index scans # do_eqp_test 3.1 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; } {0 0 0 {SCAN TABLE t1 USING INDEX i1}} do_rollback_test 3.2 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC; } -result { 40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2 ................................................................................ # Now with some index scans that feature overflow keys. # set leader [string repeat "abcdefghij" 70] do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; } do_eqp_test 4.2 { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; } {0 0 0 {SCAN TABLE t1 USING INDEX i1}} do_rollback_test 4.3 -setup { BEGIN; DELETE FROM t1 WHERE (i%2)==1; } -select { SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC; } -result { 2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40 |
|
|
|
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
...
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
|
}
#--------------------------------------------------------------------
# Try with some index scans
#
do_eqp_test 3.1 {
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} {SCAN TABLE t1 USING INDEX i1}
do_rollback_test 3.2 -setup {
BEGIN;
DELETE FROM t1 WHERE (i%2)==1;
} -select {
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h DESC;
} -result {
40 38 36 34 32 30 28 26 24 22 20 18 16 14 12 10 8 6 4 2
................................................................................
# Now with some index scans that feature overflow keys.
#
set leader [string repeat "abcdefghij" 70]
do_execsql_test 4.1 { UPDATE t1 SET h = $leader || h; }
do_eqp_test 4.2 {
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} {SCAN TABLE t1 USING INDEX i1}
do_rollback_test 4.3 -setup {
BEGIN;
DELETE FROM t1 WHERE (i%2)==1;
} -select {
SELECT i FROM t1 WHERE (i%2)==0 ORDER BY h ASC;
} -result {
2 4 6 8 10 12 14 16 18 20 22 24 26 28 30 32 34 36 38 40
|
Changes to test/rowvalue.test.
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
INSERT INTO xy VALUES(3, 3, 3); INSERT INTO xy VALUES(4, 4, 4); } foreach {tn sql res eqp} { 1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid=?)}" 2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2} "0 0 0 {SCAN TABLE xy}" 3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2} "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid<?)}" 4 "SELECT * FROM xy WHERE (i, j) > (2, 1)" {2 2 2 3 3 3 4 4 4} "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}" 5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4} "0 0 0 {SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)}" } { do_eqp_test 7.$tn.1 $sql $eqp do_execsql_test 7.$tn.2 $sql $res } do_execsql_test 8.0 { |
| | | | | |
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 |
INSERT INTO xy VALUES(3, 3, 3); INSERT INTO xy VALUES(4, 4, 4); } foreach {tn sql res eqp} { 1 "SELECT * FROM xy WHERE (i, j) IS (2, 2)" {2 2 2} "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid=?)" 2 "SELECT * FROM xy WHERE (k, j) < (2, 3)" {1 1 1 2 2 2} "SCAN TABLE xy" 3 "SELECT * FROM xy WHERE (i, j) < (2, 3)" {1 1 1 2 2 2} "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid<?)" 4 "SELECT * FROM xy WHERE (i, j) > (2, 1)" {2 2 2 3 3 3 4 4 4} "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)" 5 "SELECT * FROM xy WHERE (i, j) > ('2', 1)" {2 2 2 3 3 3 4 4 4} "SEARCH TABLE xy USING INTEGER PRIMARY KEY (rowid>?)" } { do_eqp_test 7.$tn.1 $sql $eqp do_execsql_test 7.$tn.2 $sql $res } do_execsql_test 8.0 { |
Changes to test/rowvalue4.test.
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
...
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
|
INSERT INTO c1(c, d) SELECT a, b FROM c1; CREATE INDEX c1ab ON c1(a, b); CREATE INDEX c1cd ON c1(c, d); ANALYZE; } do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c=?)} } do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c=?)} } do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)} } do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1cd (c>?)} } do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)} } do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)} } do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)} } do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))} } do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } { 0 0 0 {SEARCH TABLE c1 USING INDEX c1ab (a=?)} } } #------------------------------------------------------------------------ do_execsql_test 5.0 { CREATE TABLE d1(x, y); CREATE TABLE d2(a, b, c); ................................................................................ } do_eqp_test 5.1 { SELECT * FROM d2 WHERE (a, b) IN (SELECT x, y FROM d1) AND (c) IN (SELECT y FROM d1) } { 0 0 0 {SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?)} 0 0 0 {EXECUTE LIST SUBQUERY 1} 1 0 0 {SCAN TABLE d1} 0 0 0 {EXECUTE LIST SUBQUERY 2} 2 0 0 {SCAN TABLE d1} } do_execsql_test 6.0 { CREATE TABLE e1(a, b, c, d, e); CREATE INDEX e1ab ON e1(a, b); CREATE INDEX e1cde ON e1(c, d, e); } do_eqp_test 6.1 { SELECT * FROM e1 WHERE (a, b) > (?, ?) } { 0 0 0 {SEARCH TABLE e1 USING INDEX e1ab ((a,b)>(?,?))} } do_eqp_test 6.2 { SELECT * FROM e1 WHERE (a, b) < (?, ?) } { 0 0 0 {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))} } do_eqp_test 6.3 { SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?) } { 0 0 0 {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} } do_eqp_test 6.4 { SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?) } { 0 0 0 {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} } do_eqp_test 6.5 { SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ? } { 0 0 0 {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))} } #------------------------------------------------------------------------- do_execsql_test 7.1 { CREATE TABLE f1(a, b, c); CREATE INDEX f1ab ON f1(a, b); } |
|
|
|
|
|
|
|
|
|
<
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
>
|
|
|
|
|
<
|
|
<
|
|
<
|
|
<
|
<
<
<
|
<
|
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
...
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
|
INSERT INTO c1(c, d) SELECT a, b FROM c1; CREATE INDEX c1ab ON c1(a, b); CREATE INDEX c1cd ON c1(c, d); ANALYZE; } do_eqp_test 3.1.1 { SELECT * FROM c1 WHERE a=1 AND c=2 } \ {SEARCH TABLE c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.2 { SELECT * FROM c1 WHERE a=1 AND b>'d' AND c=2 } \ {SEARCH TABLE c1 USING INDEX c1cd (c=?)} do_eqp_test 3.1.3 { SELECT * FROM c1 WHERE a=1 AND b>'l' AND c=2 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=? AND b>?)} do_eqp_test 3.2.1 { SELECT * FROM c1 WHERE a=1 AND c>1 } \ {SEARCH TABLE c1 USING INDEX c1cd (c>?)} do_eqp_test 3.2.2 { SELECT * FROM c1 WHERE a=1 AND c>0 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.3 { SELECT * FROM c1 WHERE a=1 AND c>=1 } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.4 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'c') } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} do_eqp_test 3.2.5 { SELECT * FROM c1 WHERE a=1 AND (c, d)>(1, 'o') } \ {SEARCH TABLE c1 USING INDEX c1cd ((c,d)>(?,?))} do_eqp_test 3.2.6 { SELECT * FROM c1 WHERE a=1 AND (c, +b)>(1, 'c') } \ {SEARCH TABLE c1 USING INDEX c1ab (a=?)} } #------------------------------------------------------------------------ do_execsql_test 5.0 { CREATE TABLE d1(x, y); CREATE TABLE d2(a, b, c); ................................................................................ } do_eqp_test 5.1 { SELECT * FROM d2 WHERE (a, b) IN (SELECT x, y FROM d1) AND (c) IN (SELECT y FROM d1) } { QUERY PLAN |--SEARCH TABLE d2 USING INDEX d2ab (a=? AND b=?) |--LIST SUBQUERY | `--SCAN TABLE d1 `--LIST SUBQUERY `--SCAN TABLE d1 } do_execsql_test 6.0 { CREATE TABLE e1(a, b, c, d, e); CREATE INDEX e1ab ON e1(a, b); CREATE INDEX e1cde ON e1(c, d, e); } do_eqp_test 6.1 { SELECT * FROM e1 WHERE (a, b) > (?, ?) } {SEARCH TABLE e1 USING INDEX e1ab ((a,b)>(?,?))} do_eqp_test 6.2 { SELECT * FROM e1 WHERE (a, b) < (?, ?) } {SEARCH TABLE e1 USING INDEX e1ab ((a,b)<(?,?))} do_eqp_test 6.3 { SELECT * FROM e1 WHERE c = ? AND (d, e) > (?, ?) } {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?))} do_eqp_test 6.4 { SELECT * FROM e1 WHERE c = ? AND (d, e) < (?, ?) } {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)<(?,?))} do_eqp_test 6.5 { SELECT * FROM e1 WHERE (d, e) BETWEEN (?, ?) AND (?, ?) AND c = ? } {SEARCH TABLE e1 USING INDEX e1cde (c=? AND (d,e)>(?,?) AND (d,e)<(?,?))} #------------------------------------------------------------------------- do_execsql_test 7.1 { CREATE TABLE f1(a, b, c); CREATE INDEX f1ab ON f1(a, b); } |
Changes to test/scanstatus.test.
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
...
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
|
do_scanstatus_test 5.2.2 { nLoop 1 nVisit 2 nEst 2.0 zName sqlite_autoindex_t1_1 zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} } do_eqp_test 5.3.1 { SELECT count(*) FROM t2 WHERE y = 'j'; } {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)}} do_execsql_test 5.3.2 { SELECT count(*) FROM t2 WHERE y = 'j'; } {19} do_scanstatus_test 5.3.3 { nLoop 1 nVisit 19 nEst 56.0 zName t2xy zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.4.1 { SELECT count(*) FROM t1, t2 WHERE y = c; } { 0 0 0 {SCAN TABLE t1 USING COVERING INDEX t1bc} 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_execsql_test 5.4.2 { SELECT count(*) FROM t1, t2 WHERE y = c; } {200} do_scanstatus_test 5.4.3 { nLoop 1 nVisit 10 nEst 10.0 zName t1bc zExplain {SCAN TABLE t1 USING COVERING INDEX t1bc} ................................................................................ nLoop 10 nVisit 200 nEst 56.0 zName t2xy zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.5.1 { SELECT count(*) FROM t1, t3 WHERE y = c; } { 0 0 1 {SCAN TABLE t3} 0 1 0 {SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?)} } do_execsql_test 5.5.2 { SELECT count(*) FROM t1, t3 WHERE y = c; } {200} do_scanstatus_test 5.5.3 { nLoop 1 nVisit 501 nEst 480.0 zName t3 zExplain {SCAN TABLE t3} nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain |
|
>
|
|
>
|
|
|
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
...
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
|
do_scanstatus_test 5.2.2 { nLoop 1 nVisit 2 nEst 2.0 zName sqlite_autoindex_t1_1 zExplain {SEARCH TABLE t1 USING COVERING INDEX sqlite_autoindex_t1_1 (a=?)} } do_eqp_test 5.3.1 { SELECT count(*) FROM t2 WHERE y = 'j'; } {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} do_execsql_test 5.3.2 { SELECT count(*) FROM t2 WHERE y = 'j'; } {19} do_scanstatus_test 5.3.3 { nLoop 1 nVisit 19 nEst 56.0 zName t2xy zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.4.1 { SELECT count(*) FROM t1, t2 WHERE y = c; } { QUERY PLAN |--SCAN TABLE t1 USING COVERING INDEX t1bc `--SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?) } do_execsql_test 5.4.2 { SELECT count(*) FROM t1, t2 WHERE y = c; } {200} do_scanstatus_test 5.4.3 { nLoop 1 nVisit 10 nEst 10.0 zName t1bc zExplain {SCAN TABLE t1 USING COVERING INDEX t1bc} ................................................................................ nLoop 10 nVisit 200 nEst 56.0 zName t2xy zExplain {SEARCH TABLE t2 USING COVERING INDEX t2xy (ANY(x) AND y=?)} } do_eqp_test 5.5.1 { SELECT count(*) FROM t1, t3 WHERE y = c; } { QUERY PLAN |--SCAN TABLE t3 `--SEARCH TABLE t1 USING AUTOMATIC COVERING INDEX (c=?) } do_execsql_test 5.5.2 { SELECT count(*) FROM t1, t3 WHERE y = c; } {200} do_scanstatus_test 5.5.3 { nLoop 1 nVisit 501 nEst 480.0 zName t3 zExplain {SCAN TABLE t3} nLoop 501 nVisit 200 nEst 20.0 zName auto-index zExplain |
Changes to test/selectA.test.
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 |
do_eqp_test 4.1.2 { SELECT c, d FROM t5 UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 } { 1 0 0 {SCAN TABLE t5 USING INDEX i2} 1 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 2 0 0 {SCAN TABLE t4 USING INDEX i1} 2 0 0 {USE TEMP B-TREE FOR RIGHT PART OF ORDER BY} 0 0 0 {COMPOUND SUBQUERIES 1 AND 2 (UNION ALL)} } do_execsql_test 4.1.3 { SELECT c, d FROM t5 UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 |
> > > | | > | | < |
1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 |
do_eqp_test 4.1.2 { SELECT c, d FROM t5 UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 } { QUERY PLAN `--MERGE (UNION ALL) |--LEFT | |--SCAN TABLE t5 USING INDEX i2 | `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY `--RIGHT |--SCAN TABLE t4 USING INDEX i1 `--USE TEMP B-TREE FOR RIGHT PART OF ORDER BY } do_execsql_test 4.1.3 { SELECT c, d FROM t5 UNION ALL SELECT a, b FROM t4 WHERE f()==f() ORDER BY 1,2 |
Changes to test/selectD.test.
165 166 167 168 169 170 171 172 173 174 |
SELECT * FROM t41 LEFT JOIN (SELECT count(*) AS cnt, x1.d FROM (t42 INNER JOIN t43 ON d=g) AS x1 WHERE x1.d>5 GROUP BY x1.d) AS x2 ON t41.b=x2.d; } {/.*SEARCH SUBQUERY 1 AS x2 USING AUTOMATIC.*/} finish_test |
| |
165 166 167 168 169 170 171 172 173 174 |
SELECT *
FROM t41
LEFT JOIN (SELECT count(*) AS cnt, x1.d
FROM (t42 INNER JOIN t43 ON d=g) AS x1
WHERE x1.d>5
GROUP BY x1.d) AS x2
ON t41.b=x2.d;
} {/*SEARCH SUBQUERY 0x* AS x2 USING AUTOMATIC*/}
finish_test
|
Changes to test/skipscan2.test.
195 196 197 198 199 200 201 202 203 204 205 |
for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } } execsql { ANALYZE } } {} do_eqp_test skipscan2-3.3eqp { SELECT * FROM t3 WHERE b=42; } {0 0 0 {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)}} finish_test |
| |
195 196 197 198 199 200 201 202 203 204 205 |
for {set i 0} {$i < 1000} {incr i} { execsql { INSERT INTO t3 VALUES($i%2, $i, 'xyz') } } execsql { ANALYZE } } {} do_eqp_test skipscan2-3.3eqp { SELECT * FROM t3 WHERE b=42; } {SEARCH TABLE t3 USING PRIMARY KEY (ANY(a) AND b=?)} finish_test |
Changes to test/skipscan6.test.
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 |
t3 t3_ba {100 20 1 1} } # Use index "t3_a", as (a=?) is expected to match only a single row. # do_eqp_test 3.1 { SELECT * FROM t3 WHERE a = ? AND c = ? } { 0 0 0 {SEARCH TABLE t3 USING INDEX t3_a (a=?)} } # The same query on table t2. This should use index "t2_a", for the # same reason. At one point though, it was mistakenly using a skip-scan. # do_eqp_test 3.2 { SELECT * FROM t2 WHERE a = ? AND c = ? } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2_a (a=?)} } finish_test finish_test |
< | < < | | < < < < < < |
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 |
t3 t3_ba {100 20 1 1} } # Use index "t3_a", as (a=?) is expected to match only a single row. # do_eqp_test 3.1 { SELECT * FROM t3 WHERE a = ? AND c = ? } {SEARCH TABLE t3 USING INDEX t3_a (a=?)} # The same query on table t2. This should use index "t2_a", for the # same reason. At one point though, it was mistakenly using a skip-scan. # do_eqp_test 3.2 { SELECT * FROM t2 WHERE a = ? AND c = ? } {SEARCH TABLE t2 USING INDEX t2_a (a=?)} finish_test |
Changes to test/tester.tcl.
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 |
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result] } proc do_timed_execsql_test {testname sql {result {}}} { fix_testname testname uplevel do_test [list $testname] [list "execsql_timed {$sql}"]\ [list [list {*}$result]] } proc do_eqp_test {name sql res} { uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res] } #------------------------------------------------------------------------- # Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST # # Where switches are: # # -errorformat FMTSTRING |
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > |
955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 |
uplevel do_test [list $testname] [list "catchsql {$sql}"] [list $result] } proc do_timed_execsql_test {testname sql {result {}}} { fix_testname testname uplevel do_test [list $testname] [list "execsql_timed {$sql}"]\ [list [list {*}$result]] } # Run an EXPLAIN QUERY PLAN $sql in database "db". Then rewrite the output # as an ASCII-art graph and return a string that is that graph. # # Hexadecimal literals in the output text are converted into "xxxxxx" since those # literals are pointer values that might very from one run of the test to the # next, yet we want the output to be consistent. # proc query_plan_graph {sql} { db eval "EXPLAIN QUERY PLAN $sql" { set dx($id) $detail lappend cx($parent) $id } set a "\n QUERY PLAN\n" append a [append_graph " " dx cx 0] return [regsub -all { 0x[A-F0-9]+\y} $a { xxxxxx}] } # Helper routine for [query_plan_graph SQL]: # # Output rows of the graph that are children of $level. # # prefix: Prepend to every output line # # dxname: Name of an array variable that stores text describe # The description for $id is $dx($id) # # cxname: Name of an array variable holding children of item. # Children of $id are $cx($id) # # level: Render all lines that are children of $level # proc append_graph {prefix dxname cxname level} { upvar $dxname dx $cxname cx set a "" set x $cx($level) set n [llength $x] for {set i 0} {$i<$n} {incr i} { set id [lindex $x $i] if {$i==$n-1} { set p1 "`--" set p2 " " } else { set p1 "|--" set p2 "| " } append a $prefix$p1$dx($id)\n if {[info exists cx($id)]} { append a [append_graph "$prefix$p2" dx cx $id] } } return $a } # Do an EXPLAIN QUERY PLAN test on input $sql with expected results $res # # If $res begins with a "\s+QUERY PLAN\n" then it is assumed to be the # complete graph which must match the output of [query_plan_graph $sql] # exactly. # # If $res does not begin with "\s+QUERY PLAN\n" then take it is a string # that must be found somewhere in the query plan output. # proc do_eqp_test {name sql res} { if {[regexp {^\s+QUERY PLAN\n} $res]} { uplevel do_test $name [list [list query_plan_graph $sql]] [list $res] } else { if {[string index $res 0]!="/"} { set res "/*$res*/" } uplevel do_execsql_test $name [list "EXPLAIN QUERY PLAN $sql"] [list $res] } } #------------------------------------------------------------------------- # Usage: do_select_tests PREFIX ?SWITCHES? TESTLIST # # Where switches are: # # -errorformat FMTSTRING |
Changes to test/tkt-385a5b56b9.test.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
do_execsql_test 2.0 { CREATE TABLE t2(x, y NOT NULL); CREATE UNIQUE INDEX t2x ON t2(x); CREATE UNIQUE INDEX t2y ON t2(y); } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2x} } do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } { 0 0 0 {SCAN TABLE t2 USING COVERING INDEX t2y} } do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2y (y=?)} } do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } { 0 0 0 {SEARCH TABLE t2 USING INDEX t2x (x=?)} } finish_test |
| | | < | | | < | | | < | | | |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
do_execsql_test 2.0 { CREATE TABLE t2(x, y NOT NULL); CREATE UNIQUE INDEX t2x ON t2(x); CREATE UNIQUE INDEX t2y ON t2(y); } do_eqp_test 2.1 { SELECT DISTINCT x FROM t2 } \ {SCAN TABLE t2 USING COVERING INDEX t2x} do_eqp_test 2.2 { SELECT DISTINCT y FROM t2 } \ {SCAN TABLE t2 USING COVERING INDEX t2y} do_eqp_test 2.3 { SELECT DISTINCT x, y FROM t2 WHERE y=10 } \ {SEARCH TABLE t2 USING INDEX t2y (y=?)} do_eqp_test 2.4 { SELECT DISTINCT x, y FROM t2 WHERE x=10 } \ {SEARCH TABLE t2 USING INDEX t2x (x=?)} finish_test |
Changes to test/tkt-78e04e52ea.test.
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 |
} {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0} do_test tkt-78e04-1.3 { execsql { CREATE INDEX i1 ON ""("" COLLATE nocase); } } {} do_test tkt-78e04-1.4 { execsql { EXPLAIN QUERY PLAN SELECT "" FROM "" WHERE "" LIKE '1abc%'; } } {0 0 0 {SCAN TABLE USING COVERING INDEX i1}} do_test tkt-78e04-1.5 { execsql { DROP TABLE ""; SELECT name FROM sqlite_master; } } {t2} do_test tkt-78e04-2.1 { execsql { CREATE INDEX "" ON t2(x); EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5; } } {0 0 0 {SEARCH TABLE t2 USING COVERING INDEX (x=?)}} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } } {0 0 0 {SCAN TABLE t2}} finish_test |
< | < | | | |
37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
} {0 {} {} 0 {} 0 1 x CHAR(100) 0 {} 0} do_test tkt-78e04-1.3 { execsql { CREATE INDEX i1 ON ""("" COLLATE nocase); } } {} do_test tkt-78e04-1.4 { db eval {EXPLAIN QUERY PLAN SELECT "" FROM "" WHERE "" LIKE '1abc%';} } {/*SCAN TABLE USING COVERING INDEX i1*/} do_test tkt-78e04-1.5 { execsql { DROP TABLE ""; SELECT name FROM sqlite_master; } } {t2} do_test tkt-78e04-2.1 { execsql { CREATE INDEX "" ON t2(x); EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=5; } } {/*SEARCH TABLE t2 USING COVERING INDEX (x=?)*/} do_test tkt-78e04-2.2 { execsql { DROP INDEX ""; EXPLAIN QUERY PLAN SELECT * FROM t2 WHERE x=2; } } {/*SCAN TABLE t2*/} finish_test |
Changes to test/tkt-b75a9ca6b0.test.
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
INSERT INTO t1 VALUES (3, 1); } do_execsql_test 1.1 { CREATE INDEX i1 ON t1(x, y); } set idxscan {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}} set tblscan {0 0 0 {SCAN TABLE t1}} set grpsort {0 0 0 {USE TEMP B-TREE FOR GROUP BY}} set sort {0 0 0 {USE TEMP B-TREE FOR ORDER BY}} foreach {tn q res eqp} [subst -nocommands { 1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y" {1 3 2 2 3 1} {$idxscan} 2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x" {1 3 2 2 3 1} {$idxscan $sort} 3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x" {3 1 2 2 1 3} {$idxscan $sort} 4 "SELECT * FROM t1 GROUP BY x ORDER BY x" {1 3 2 2 3 1} {$idxscan} 5 "SELECT * FROM t1 GROUP BY y ORDER BY y" {3 1 2 2 1 3} {$tblscan $grpsort} 6 "SELECT * FROM t1 GROUP BY y ORDER BY x" {1 3 2 2 3 1} {$tblscan $grpsort $sort} 7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC" {1 3 2 2 3 1} {$idxscan $sort} 8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC" {3 1 2 2 1 3} {$idxscan $sort} 9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC" {1 3 2 2 3 1} {$idxscan} 10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y" {1 3 2 2 3 1} {$idxscan $sort} }] { do_execsql_test 1.$tn.1 $q $res do_eqp_test 1.$tn.2 $q $eqp } finish_test |
| | | | | | | | | | | |
28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
INSERT INTO t1 VALUES (3, 1); } do_execsql_test 1.1 { CREATE INDEX i1 ON t1(x, y); } set idxscan {SCAN TABLE t1 USING COVERING INDEX i1} set tblscan {SCAN TABLE t1} set grpsort {USE TEMP B-TREE FOR GROUP BY} set sort {USE TEMP B-TREE FOR ORDER BY} foreach {tn q res eqp} [subst -nocommands { 1 "SELECT * FROM t1 GROUP BY x, y ORDER BY x,y" {1 3 2 2 3 1} {$idxscan} 2 "SELECT * FROM t1 GROUP BY x, y ORDER BY x" {1 3 2 2 3 1} {$idxscan*$sort} 3 "SELECT * FROM t1 GROUP BY y, x ORDER BY y, x" {3 1 2 2 1 3} {$idxscan*$sort} 4 "SELECT * FROM t1 GROUP BY x ORDER BY x" {1 3 2 2 3 1} {$idxscan} 5 "SELECT * FROM t1 GROUP BY y ORDER BY y" {3 1 2 2 1 3} {$tblscan*$grpsort} 6 "SELECT * FROM t1 GROUP BY y ORDER BY x" {1 3 2 2 3 1} {$tblscan*$grpsort*$sort} 7 "SELECT * FROM t1 GROUP BY x, y ORDER BY x, y DESC" {1 3 2 2 3 1} {$idxscan*$sort} 8 "SELECT * FROM t1 GROUP BY x, y ORDER BY x DESC, y DESC" {3 1 2 2 1 3} {$idxscan*$sort} 9 "SELECT * FROM t1 GROUP BY x, y ORDER BY x ASC, y ASC" {1 3 2 2 3 1} {$idxscan} 10 "SELECT * FROM t1 GROUP BY x, y ORDER BY x COLLATE nocase, y" {1 3 2 2 3 1} {$idxscan*$sort} }] { do_execsql_test 1.$tn.1 $q $res do_eqp_test 1.$tn.2 $q $eqp } finish_test |
Changes to test/tkt3442.test.
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
id TEXT, node INTEGER ); CREATE UNIQUE INDEX ididx ON listhash(id); } } {} # Explain Query Plan # proc EQP {sql} { uplevel "execsql {EXPLAIN QUERY PLAN $sql}" } # These tests perform an EXPLAIN QUERY PLAN on both versions of the # SELECT referenced in ticket #3442 (both '5000' and "5000") # and verify that the query plan is the same. # ifcapable explain { do_test tkt3442-1.2 { EQP { SELECT node FROM listhash WHERE id='5000' LIMIT 1; } } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} do_test tkt3442-1.3 { EQP { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } # Some extra tests testing other permutations of 5000. # ifcapable explain { do_test tkt3442-1.4 { EQP { SELECT node FROM listhash WHERE id=5000 LIMIT 1; } } {0 0 0 {SEARCH TABLE listhash USING INDEX ididx (id=?)}} } do_test tkt3442-1.5 { catchsql { SELECT node FROM listhash WHERE id=[5000] LIMIT 1; } } {1 {no such column: 5000}} finish_test |
< < < < < < < < < | | | | | | < < | | | | |
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
id TEXT, node INTEGER ); CREATE UNIQUE INDEX ididx ON listhash(id); } } {} # These tests perform an EXPLAIN QUERY PLAN on both versions of the # SELECT referenced in ticket #3442 (both '5000' and "5000") # and verify that the query plan is the same. # do_eqp_test tkt3442-1.2 { SELECT node FROM listhash WHERE id='5000' LIMIT 1; } {SEARCH TABLE listhash USING INDEX ididx (id=?)} do_eqp_test tkt3442-1.3 { SELECT node FROM listhash WHERE id="5000" LIMIT 1; } {SEARCH TABLE listhash USING INDEX ididx (id=?)} # Some extra tests testing other permutations of 5000. # do_eqp_test tkt3442-1.4 { SELECT node FROM listhash WHERE id=5000 LIMIT 1; } {SEARCH TABLE listhash USING INDEX ididx (id=?)} do_test tkt3442-1.5 { catchsql { SELECT node FROM listhash WHERE id=[5000] LIMIT 1; } } {1 {no such column: 5000}} finish_test |
Changes to test/tpch01.test.
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
183
184
185
186
187
188
189
190
191
192
|
and p_type = 'LARGE PLATED STEEL' ) as all_nations group by o_year order by o_year;}] set ::eqpres } {/0 0 0 {SEARCH TABLE part USING INDEX bootleg_pti .P_TYPE=..} 0 1 2 {SEARCH TABLE lineitem USING INDEX lpki2 .L_PARTKEY=..}.*/} do_test tpch01-1.1b { set ::eqpres } {/.* customer .* nation AS n1 .*/} do_test tpch01-1.1c { set ::eqpres } {/.* supplier .* nation AS n2 .*/} ................................................................................ c_custkey = o_custkey and l_orderkey = o_orderkey and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month') and l_returnflag = 'R' and c_nationkey = n_nationkey group by c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment order by revenue desc; } {0 0 1 {SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?)} 0 1 0 {SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?)} 0 2 3 {SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?)} 0 3 2 {SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?)} 0 0 0 {USE TEMP B-TREE FOR GROUP BY} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} finish_test |
|
>
>
|
>
>
>
>
>
|
>
|
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
...
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
|
and p_type = 'LARGE PLATED STEEL' ) as all_nations group by o_year order by o_year;}] set ::eqpres } {/*SEARCH TABLE part USING INDEX bootleg_pti *SEARCH TABLE lineitem USING INDEX lpki2*/} do_test tpch01-1.1b { set ::eqpres } {/.* customer .* nation AS n1 .*/} do_test tpch01-1.1c { set ::eqpres } {/.* supplier .* nation AS n2 .*/} ................................................................................ c_custkey = o_custkey and l_orderkey = o_orderkey and o_orderdate >= '1994-08-01' and o_orderdate < date('1994-08-01', '+3 month') and l_returnflag = 'R' and c_nationkey = n_nationkey group by c_custkey, c_name, c_acctbal, c_phone, n_name, c_address, c_comment order by revenue desc; } { QUERY PLAN |--SEARCH TABLE orders USING INDEX odi (O_ORDERDATE>? AND O_ORDERDATE<?) |--SEARCH TABLE customer USING INDEX cpki (C_CUSTKEY=?) |--SEARCH TABLE nation USING INDEX npki (N_NATIONKEY=?) |--SEARCH TABLE lineitem USING INDEX lpki (L_ORDERKEY=?) |--USE TEMP B-TREE FOR GROUP BY `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/unordered.test.
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 |
if {$idxmode == "unordered"} { execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' } } db close sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" {0 0 0 {SCAN TABLE t1 USING INDEX i1}} {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} 2 "SELECT * FROM t1 WHERE a > 100" {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} {0 0 0 {SCAN TABLE t1}} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY}} 4 "SELECT max(a) FROM t1" {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1}} {0 0 0 {SEARCH TABLE t1}} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" {0 0 0 {SCAN TABLE t1 USING INDEX i1}} {0 0 0 {SCAN TABLE t1} 0 0 0 {USE TEMP B-TREE FOR GROUP BY}} 6 "SELECT * FROM t1 WHERE a = ?" {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} 7 "SELECT count(*) FROM t1" {0 0 0 {SCAN TABLE t1 USING COVERING INDEX i1}} {0 0 0 {SCAN TABLE t1}} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } } finish_test |
| | | | | | < | | | | | | | | |
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
if {$idxmode == "unordered"} { execsql { UPDATE sqlite_stat1 SET stat = stat || ' unordered' } } db close sqlite3 db test.db foreach {tn sql r(ordered) r(unordered)} { 1 "SELECT * FROM t1 ORDER BY a" {SCAN TABLE t1 USING INDEX i1} {SCAN TABLE t1*USE TEMP B-TREE FOR ORDER BY} 2 "SELECT * FROM t1 WHERE a > 100" {SEARCH TABLE t1 USING INDEX i1 (a>?)} {SCAN TABLE t1} 3 "SELECT * FROM t1 WHERE a = ? ORDER BY rowid" {SEARCH TABLE t1 USING INDEX i1 (a=?)} {SEARCH TABLE t1 USING INDEX i1 (a=?)*USE TEMP B-TREE FOR ORDER BY} 4 "SELECT max(a) FROM t1" {SEARCH TABLE t1 USING COVERING INDEX i1} {SEARCH TABLE t1} 5 "SELECT group_concat(b) FROM t1 GROUP BY a" {SCAN TABLE t1 USING INDEX i1} {SCAN TABLE t1*USE TEMP B-TREE FOR GROUP BY} 6 "SELECT * FROM t1 WHERE a = ?" {SEARCH TABLE t1 USING INDEX i1 (a=?)} {SEARCH TABLE t1 USING INDEX i1 (a=?)} 7 "SELECT count(*) FROM t1" {SCAN TABLE t1 USING COVERING INDEX i1} {SCAN TABLE t1} } { do_eqp_test 1.$idxmode.$tn $sql $r($idxmode) } } finish_test |
Changes to test/where3.test.
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
...
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
|
CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c); CREATE INDEX t301c ON t301(c); INSERT INTO t301 VALUES(1,2,3); INSERT INTO t301 VALUES(2,2,3); CREATE TABLE t302(x, y); INSERT INTO t302 VALUES(4,5); ANALYZE; explain query plan SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { 0 0 0 {SCAN TABLE t302} 0 1 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test where3-3.1 { explain query plan SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { 0 0 1 {SCAN TABLE t302} 0 1 0 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} } do_execsql_test where3-3.2 { SELECT * FROM t301 WHERE c=3 AND a IS NULL; } {} do_execsql_test where3-3.3 { SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL; } {1 2 3 2 2 3} ................................................................................ fk INTEGER DEFAULT NULL, parent INTEGER, position INTEGER, title LONGVARCHAR, keyword_id INTEGER, folder_type TEXT, dateAdded INTEGER, lastModified INTEGER); CREATE INDEX bbb_111 ON bbb (fk, type); CREATE INDEX bbb_222 ON bbb (parent, position); CREATE INDEX bbb_333 ON bbb (fk, lastModified); EXPLAIN QUERY PLAN SELECT bbb.title AS tag_title FROM aaa JOIN bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} 0 1 1 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.1 { EXPLAIN QUERY PLAN SELECT bbb.title AS tag_title FROM aaa JOIN aaa AS bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { 0 0 0 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} 0 1 1 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.2 { EXPLAIN QUERY PLAN SELECT bbb.title AS tag_title FROM bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} 0 1 0 {SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } do_execsql_test where3-5.3 { EXPLAIN QUERY PLAN SELECT bbb.title AS tag_title FROM aaa AS bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { 0 0 1 {SEARCH TABLE aaa USING INDEX aaa_333 (fk=?)} 0 1 0 {SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } # Name resolution with NATURAL JOIN and USING # do_test where3-6.setup { db eval { CREATE TABLE t6w(a, w); |
>
>
|
>
|
|
|
<
>
|
|
|
|
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
<
>
|
|
|
|
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
...
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
|
CREATE TABLE t301(a INTEGER PRIMARY KEY,b,c); CREATE INDEX t301c ON t301(c); INSERT INTO t301 VALUES(1,2,3); INSERT INTO t301 VALUES(2,2,3); CREATE TABLE t302(x, y); INSERT INTO t302 VALUES(4,5); ANALYZE; } do_eqp_test where3-3.0a { SELECT * FROM t302, t301 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN |--SCAN TABLE t302 `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) } do_eqp_test where3-3.1 { SELECT * FROM t301, t302 WHERE t302.x=5 AND t301.a=t302.y; } { QUERY PLAN |--SCAN TABLE t302 `--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) } do_execsql_test where3-3.2 { SELECT * FROM t301 WHERE c=3 AND a IS NULL; } {} do_execsql_test where3-3.3 { SELECT * FROM t301 WHERE c=3 AND a IS NOT NULL; } {1 2 3 2 2 3} ................................................................................ fk INTEGER DEFAULT NULL, parent INTEGER, position INTEGER, title LONGVARCHAR, keyword_id INTEGER, folder_type TEXT, dateAdded INTEGER, lastModified INTEGER); CREATE INDEX bbb_111 ON bbb (fk, type); CREATE INDEX bbb_222 ON bbb (parent, position); CREATE INDEX bbb_333 ON bbb (fk, lastModified); } do_eqp_test where3-5.0a { SELECT bbb.title AS tag_title FROM aaa JOIN bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.1 { SELECT bbb.title AS tag_title FROM aaa JOIN aaa AS bbb ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.2 { SELECT bbb.title AS tag_title FROM bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } do_eqp_test where3-5.3 { SELECT bbb.title AS tag_title FROM aaa AS bbb JOIN aaa ON bbb.id = aaa.parent WHERE aaa.fk = 'constant' AND LENGTH(bbb.title) > 0 AND bbb.parent = 4 ORDER BY bbb.title COLLATE NOCASE ASC; } { QUERY PLAN |--SEARCH TABLE aaa USING INDEX aaa_333 (fk=?) |--SEARCH TABLE aaa AS bbb USING INTEGER PRIMARY KEY (rowid=?) `--USE TEMP B-TREE FOR ORDER BY } # Name resolution with NATURAL JOIN and USING # do_test where3-6.setup { db eval { CREATE TABLE t6w(a, w); |
Changes to test/where7.test.
23337 23338 23339 23340 23341 23342 23343 23344 23345 23346 23347 23348 23349 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 |
c2 INTEGER, c4 INTEGER, FOREIGN KEY (c8) REFERENCES t301(c8) ); CREATE INDEX t302_c3 on t302(c3); CREATE INDEX t302_c8_c3 on t302(c8, c3); CREATE INDEX t302_c5 on t302(c5); EXPLAIN QUERY PLAN SELECT t302.c1 FROM t302 JOIN t301 ON t302.c8 = +t301.c8 WHERE t302.c2 = 19571 AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { 0 0 1 {SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?)} 0 0 1 {SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?)} 0 1 0 {SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?)} 0 0 0 {USE TEMP B-TREE FOR ORDER BY} } finish_test |
| | > | | | | |
23337 23338 23339 23340 23341 23342 23343 23344 23345 23346 23347 23348 23349 23350 23351 23352 23353 23354 23355 23356 23357 23358 23359 23360 23361 |
c2 INTEGER, c4 INTEGER, FOREIGN KEY (c8) REFERENCES t301(c8) ); CREATE INDEX t302_c3 on t302(c3); CREATE INDEX t302_c8_c3 on t302(c8, c3); CREATE INDEX t302_c5 on t302(c5); } do_eqp_test where7-3.2 { SELECT t302.c1 FROM t302 JOIN t301 ON t302.c8 = +t301.c8 WHERE t302.c2 = 19571 AND t302.c3 > 1287603136 AND (t301.c4 = 1407449685622784 OR t301.c8 = 1407424651264000) ORDER BY t302.c5 LIMIT 200; } { QUERY PLAN |--SEARCH TABLE t301 USING COVERING INDEX t301_c4 (c4=?) |--SEARCH TABLE t301 USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE t302 USING INDEX t302_c8_c3 (c8=? AND c3>?) `--USE TEMP B-TREE FOR ORDER BY } finish_test |
Changes to test/where9.test.
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
|
WHERE t1.a=t3.y OR t1.b=t3.y*11 OR (t1.c=27027 AND round(t1.d)==80) ORDER BY 1, 2, 3 } } {1 80 2 1 80 28 1 80 54 1 80 80 2 80 2 2 80 28 2 80 54 2 80 80 scan 1 sort 1} ifcapable explain { do_execsql_test where9-3.1 { EXPLAIN QUERY PLAN SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } { 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } do_execsql_test where9-3.2 { EXPLAIN QUERY PLAN SELECT coalesce(t2.a,9999) FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f WHERE t1.a=80 } { 0 0 0 {SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?)} 0 1 1 {SEARCH TABLE t2 USING INDEX t2d (d=?)} 0 1 1 {SEARCH TABLE t2 USING COVERING INDEX t2f (f=?)} } } # Make sure that INDEXED BY and multi-index OR clauses play well with # one another. # do_test where9-4.1 { count_steps { ................................................................................ SELECT a FROM t1 INDEXED BY t1d WHERE b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {1 {no query solution}} ifcapable explain { # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because # the former is an equality test which is expected to return fewer rows. # do_execsql_test where9-5.1 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1c (c=?)} 0 0 0 {SEARCH TABLE t1 USING INDEX t1d (d=?)} } # In contrast, b=1000 is preferred over any OR-clause. # do_execsql_test where9-5.2 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b=?)} } # Likewise, inequalities in an AND are preferred over inequalities in # an OR. # do_execsql_test where9-5.3 { EXPLAIN QUERY PLAN SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) } { 0 0 0 {SEARCH TABLE t1 USING INDEX t1b (b>?)} } } ############################################################################ # Make sure OR-clauses work correctly on UPDATE and DELETE statements. do_test where9-6.2.1 { db eval {SELECT count(*) FROM t1 UNION ALL SELECT a FROM t1 WHERE a>=85} } {99 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99} |
|
<
>
|
|
|
|
|
|
<
>
|
|
|
|
|
<
|
|
|
|
|
|
>
|
|
|
|
|
|
|
<
|
|
<
|
|
|
|
|
<
|
<
<
|
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
...
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
|
WHERE t1.a=t3.y OR t1.b=t3.y*11 OR (t1.c=27027 AND round(t1.d)==80) ORDER BY 1, 2, 3 } } {1 80 2 1 80 28 1 80 54 1 80 80 2 80 2 2 80 28 2 80 54 2 80 80 scan 1 sort 1} ifcapable explain { do_eqp_test where9-3.1 { SELECT t2.a FROM t1, t2 WHERE t1.a=80 AND ((t1.c=t2.c AND t1.d=t2.d) OR t1.f=t2.f) } [string map {"\n " \n} { QUERY PLAN |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE t2 USING INDEX t2d (d=?) `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) }] do_eqp_test where9-3.2 { SELECT coalesce(t2.a,9999) FROM t1 LEFT JOIN t2 ON (t1.c+1=t2.c AND t1.d=t2.d) OR (t1.f||'x')=t2.f WHERE t1.a=80 } [string map {"\n " \n} { QUERY PLAN |--SEARCH TABLE t1 USING INTEGER PRIMARY KEY (rowid=?) |--SEARCH TABLE t2 USING INDEX t2d (d=?) `--SEARCH TABLE t2 USING COVERING INDEX t2f (f=?) }] } # Make sure that INDEXED BY and multi-index OR clauses play well with # one another. # do_test where9-4.1 { count_steps { ................................................................................ SELECT a FROM t1 INDEXED BY t1d WHERE b>1000 AND (c=31031 OR d IS NULL) ORDER BY +a } } {1 {no query solution}} # The (c=31031 OR d IS NULL) clause is preferred over b>1000 because # the former is an equality test which is expected to return fewer rows. # do_eqp_test where9-5.1 { SELECT a FROM t1 WHERE b>1000 AND (c=31031 OR d IS NULL) } { QUERY PLAN |--SEARCH TABLE t1 USING INDEX t1c (c=?) `--SEARCH TABLE t1 USING INDEX t1d (d=?) } # In contrast, b=1000 is preferred over any OR-clause. # do_eqp_test where9-5.2 { SELECT a FROM t1 WHERE b=1000 AND (c=31031 OR d IS NULL) } {SEARCH TABLE t1 USING INDEX t1b (b=?)} # Likewise, inequalities in an AND are preferred over inequalities in # an OR. # do_eqp_test where9-5.3 { SELECT a FROM t1 WHERE b>1000 AND (c>=31031 OR d IS NULL) } {SEARCH TABLE t1 USING INDEX t1b (b>?)} ############################################################################ # Make sure OR-clauses work correctly on UPDATE and DELETE statements. do_test where9-6.2.1 { db eval {SELECT count(*) FROM t1 UNION ALL SELECT a FROM t1 WHERE a>=85} } {99 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99} |
Changes to test/whereG.test.
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
} {} do_eqp_test whereG-1.1 { SELECT DISTINCT aname FROM album, composer, track WHERE unlikely(cname LIKE '%bach%') AND composer.cid=track.cid AND album.aid=track.aid; } {/.*composer.*track.*album.*/} do_execsql_test whereG-1.2 { SELECT DISTINCT aname FROM album, composer, track WHERE unlikely(cname LIKE '%bach%') AND composer.cid=track.cid AND album.aid=track.aid; } {{Mass in B Minor, BWV 232}} ................................................................................ do_execsql_test 5.1 { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a, b); } do_eqp_test 5.1.2 { SELECT * FROM t1 WHERE a>? } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}} do_eqp_test 5.1.3 { SELECT * FROM t1 WHERE likelihood(a>?, 0.9) } {0 0 0 {SCAN TABLE t1}} do_eqp_test 5.1.4 { SELECT * FROM t1 WHERE likely(a>?) } {0 0 0 {SCAN TABLE t1}} do_test 5.2 { for {set i 0} {$i < 100} {incr i} { execsql { INSERT INTO t1 VALUES('abc', $i, $i); } } execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; } execsql { ANALYZE } } {} do_eqp_test 5.2.2 { SELECT * FROM t1 WHERE likelihood(b>?, 0.01) } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)}} do_eqp_test 5.2.3 { SELECT * FROM t1 WHERE likelihood(b>?, 0.9) } {0 0 0 {SCAN TABLE t1}} do_eqp_test 5.2.4 { SELECT * FROM t1 WHERE likely(b>?) } {0 0 0 {SCAN TABLE t1}} do_eqp_test 5.3.1 { SELECT * FROM t1 WHERE a=? } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}} do_eqp_test 5.3.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.9) } {0 0 0 {SCAN TABLE t1}} do_eqp_test 5.3.3 { SELECT * FROM t1 WHERE likely(a=?) } {0 0 0 {SCAN TABLE t1}} # 2015-06-18 # Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70] # do_execsql_test 6.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(i int, x, y, z); |
|
|
|
|
|
|
|
|
|
|
|
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
...
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
|
} {} do_eqp_test whereG-1.1 { SELECT DISTINCT aname FROM album, composer, track WHERE unlikely(cname LIKE '%bach%') AND composer.cid=track.cid AND album.aid=track.aid; } {composer*track*album} do_execsql_test whereG-1.2 { SELECT DISTINCT aname FROM album, composer, track WHERE unlikely(cname LIKE '%bach%') AND composer.cid=track.cid AND album.aid=track.aid; } {{Mass in B Minor, BWV 232}} ................................................................................ do_execsql_test 5.1 { CREATE TABLE t1(a, b, c); CREATE INDEX i1 ON t1(a, b); } do_eqp_test 5.1.2 { SELECT * FROM t1 WHERE a>? } {SEARCH TABLE t1 USING INDEX i1 (a>?)} do_eqp_test 5.1.3 { SELECT * FROM t1 WHERE likelihood(a>?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.1.4 { SELECT * FROM t1 WHERE likely(a>?) } {SCAN TABLE t1} do_test 5.2 { for {set i 0} {$i < 100} {incr i} { execsql { INSERT INTO t1 VALUES('abc', $i, $i); } } execsql { INSERT INTO t1 SELECT 'def', b, c FROM t1; } execsql { ANALYZE } } {} do_eqp_test 5.2.2 { SELECT * FROM t1 WHERE likelihood(b>?, 0.01) } {SEARCH TABLE t1 USING INDEX i1 (ANY(a) AND b>?)} do_eqp_test 5.2.3 { SELECT * FROM t1 WHERE likelihood(b>?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.2.4 { SELECT * FROM t1 WHERE likely(b>?) } {SCAN TABLE t1} do_eqp_test 5.3.1 { SELECT * FROM t1 WHERE a=? } {SEARCH TABLE t1 USING INDEX i1 (a=?)} do_eqp_test 5.3.2 { SELECT * FROM t1 WHERE likelihood(a=?, 0.9) } {SCAN TABLE t1} do_eqp_test 5.3.3 { SELECT * FROM t1 WHERE likely(a=?) } {SCAN TABLE t1} # 2015-06-18 # Ticket [https://www.sqlite.org/see/tktview/472f0742a1868fb58862bc588ed70] # do_execsql_test 6.0 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(i int, x, y, z); |
Changes to test/whereI.test.
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
..
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
CREATE INDEX i1 ON t1(b); CREATE INDEX i2 ON t1(c); } do_eqp_test 1.1 { SELECT a FROM t1 WHERE b='b' OR c='x' } { 0 0 0 {SEARCH TABLE t1 USING INDEX i1 (b=?)} 0 0 0 {SEARCH TABLE t1 USING INDEX i2 (c=?)} } do_execsql_test 1.2 { SELECT a FROM t1 WHERE b='b' OR c='x' } {2 3} do_execsql_test 1.3 { ................................................................................ CREATE INDEX i3 ON t2(b); CREATE INDEX i4 ON t2(c); } do_eqp_test 2.1 { SELECT a FROM t2 WHERE b='b' OR c='x' } { 0 0 0 {SEARCH TABLE t2 USING INDEX i3 (b=?)} 0 0 0 {SEARCH TABLE t2 USING INDEX i4 (c=?)} } do_execsql_test 2.2 { SELECT a FROM t2 WHERE b='b' OR c='x' } {ii iii} do_execsql_test 2.3 { |
>
|
|
>
|
|
|
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
..
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
|
CREATE INDEX i1 ON t1(b); CREATE INDEX i2 ON t1(c); } do_eqp_test 1.1 { SELECT a FROM t1 WHERE b='b' OR c='x' } { QUERY PLAN |--SEARCH TABLE t1 USING INDEX i1 (b=?) `--SEARCH TABLE t1 USING INDEX i2 (c=?) } do_execsql_test 1.2 { SELECT a FROM t1 WHERE b='b' OR c='x' } {2 3} do_execsql_test 1.3 { ................................................................................ CREATE INDEX i3 ON t2(b); CREATE INDEX i4 ON t2(c); } do_eqp_test 2.1 { SELECT a FROM t2 WHERE b='b' OR c='x' } { QUERY PLAN |--SEARCH TABLE t2 USING INDEX i3 (b=?) `--SEARCH TABLE t2 USING INDEX i4 (c=?) } do_execsql_test 2.2 { SELECT a FROM t2 WHERE b='b' OR c='x' } {ii iii} do_execsql_test 2.3 { |
Changes to test/whereJ.test.
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 |
# This one should use index "idx_c". do_eqp_test 3.4 { SELECT * FROM t1 WHERE a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows AND c BETWEEN 150 AND 160 -- Matches 10 rows } { 0 0 0 {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)} } # This one should use index "idx_ab". do_eqp_test 3.5 { SELECT * FROM t1 WHERE a = 5 AND b BETWEEN 20 AND 80 -- Matches 1 row AND c BETWEEN 150 AND 160 -- Matches 10 rows } { 0 0 0 {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)} } ########################################################################################### # Reset the database and setup for a test case derived from actual SQLite users # db close sqlite3 db test.db |
< | < < | < |
398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 |
# This one should use index "idx_c". do_eqp_test 3.4 { SELECT * FROM t1 WHERE a = 4 AND b BETWEEN 20 AND 80 -- Matches 80 rows AND c BETWEEN 150 AND 160 -- Matches 10 rows } {SEARCH TABLE t1 USING INDEX idx_c (c>? AND c<?)} # This one should use index "idx_ab". do_eqp_test 3.5 { SELECT * FROM t1 WHERE a = 5 AND b BETWEEN 20 AND 80 -- Matches 1 row AND c BETWEEN 150 AND 160 -- Matches 10 rows } {SEARCH TABLE t1 USING INDEX idx_ab (a=? AND b>? AND b<?)} ########################################################################################### # Reset the database and setup for a test case derived from actual SQLite users # db close sqlite3 db test.db |
Changes to test/with1.test.
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 |
FROM xyz ORDER BY 1 ) SELECT 1 FROM xyz; } 1 # EXPLAIN QUERY PLAN on a self-join of a CTE # do_execsql_test 19.1 { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); EXPLAIN QUERY PLAN WITH x1(a) AS (values(100)) INSERT INTO t1(x) SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2); SELECT * FROM t1; } {0 0 0 {SCAN SUBQUERY 1} 0 1 1 {SCAN SUBQUERY 1}} # 2017-10-28. # See check-in https://sqlite.org/src/info/0926df095faf72c2 # Tried to optimize co-routine processing by changing a Copy opcode # into SCopy. But OSSFuzz found two (similar) cases where that optimization # does not work. # |
| < > > > > > > | > > |
988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 |
FROM xyz ORDER BY 1 ) SELECT 1 FROM xyz; } 1 # EXPLAIN QUERY PLAN on a self-join of a CTE # do_execsql_test 19.1a { DROP TABLE IF EXISTS t1; CREATE TABLE t1(x); } do_eqp_test 19.1b { WITH x1(a) AS (values(100)) INSERT INTO t1(x) SELECT * FROM (WITH x2(y) AS (SELECT * FROM x1) SELECT y+a FROM x1, x2); SELECT * FROM t1; } { QUERY PLAN |--MATERIALIZE xxxxxx | `--SCAN CONSTANT ROW |--SCAN SUBQUERY xxxxxx `--SCAN SUBQUERY xxxxxx } # 2017-10-28. # See check-in https://sqlite.org/src/info/0926df095faf72c2 # Tried to optimize co-routine processing by changing a Copy opcode # into SCopy. But OSSFuzz found two (similar) cases where that optimization # does not work. # |
Changes to test/with3.test.
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 |
ANALYZE; } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } { 3 0 0 {SCAN TABLE cnt} 1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)} 0 0 0 {SCAN SUBQUERY 1} 0 1 1 {SEARCH TABLE y1 USING INDEX y1a (a=?)} } do_eqp_test 3.1.3 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000) SELECT * FROM cnt, y1 WHERE i=a } { 3 0 0 {SCAN TABLE cnt} 1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)} 0 0 1 {SCAN TABLE y1} 0 1 0 {SEARCH SUBQUERY 1 USING AUTOMATIC COVERING INDEX (i=?)} } } do_execsql_test 3.2.1 { CREATE TABLE w1(pk INTEGER PRIMARY KEY, x INTEGER); CREATE TABLE w2(pk INTEGER PRIMARY KEY); } do_eqp_test 3.2.2 { WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1) UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1) SELECT * FROM c, w2, w1 WHERE c.id=w2.pk AND c.id=w1.pk; } { 2 0 0 {EXECUTE SCALAR SUBQUERY 3} 3 0 0 {SCAN TABLE w2} 4 0 0 {SCAN TABLE w1} 4 1 1 {SCAN TABLE c} 1 0 0 {COMPOUND SUBQUERIES 0 AND 0 (UNION ALL)} 0 0 0 {SCAN SUBQUERY 1} 0 1 1 {SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?)} 0 2 2 {SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?)} } finish_test |
| > > > > > | < | | | < > > > > > > | < | | | > > > > | | > | | < > | | |
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 |
ANALYZE; } do_eqp_test 3.1.2 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--MATERIALIZE xxxxxx | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN TABLE cnt |--SCAN SUBQUERY xxxxxx `--SEARCH TABLE y1 USING INDEX y1a (a=?) }] do_eqp_test 3.1.3 { WITH cnt(i) AS ( SELECT 1 UNION ALL SELECT i+1 FROM cnt LIMIT 1000000) SELECT * FROM cnt, y1 WHERE i=a } [string map {"\n " \n} { QUERY PLAN |--MATERIALIZE xxxxxx | |--SETUP | | `--SCAN CONSTANT ROW | `--RECURSIVE STEP | `--SCAN TABLE cnt |--SCAN TABLE y1 `--SEARCH SUBQUERY xxxxxx USING AUTOMATIC COVERING INDEX (i=?) }] } do_execsql_test 3.2.1 { CREATE TABLE w1(pk INTEGER PRIMARY KEY, x INTEGER); CREATE TABLE w2(pk INTEGER PRIMARY KEY); } do_eqp_test 3.2.2 { WITH RECURSIVE c(w,id) AS (SELECT 0, (SELECT pk FROM w2 LIMIT 1) UNION ALL SELECT c.w + 1, x FROM w1, c LIMIT 1) SELECT * FROM c, w2, w1 WHERE c.id=w2.pk AND c.id=w1.pk; } { QUERY PLAN |--MATERIALIZE xxxxxx | |--SETUP | | |--SCAN CONSTANT ROW | | `--SCALAR SUBQUERY | | `--SCAN TABLE w2 | `--RECURSIVE STEP | |--SCAN TABLE w1 | `--SCAN TABLE c |--SCAN SUBQUERY xxxxxx |--SEARCH TABLE w2 USING INTEGER PRIMARY KEY (rowid=?) `--SEARCH TABLE w1 USING INTEGER PRIMARY KEY (rowid=?) } finish_test |
Changes to test/without_rowid1.test.
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
INSERT INTO t45 VALUES(5, 'two', 'x'); INSERT INTO t45 VALUES(7, 'two', 'x'); INSERT INTO t45 VALUES(9, 'two', 'x'); } do_eqp_test 5.1 { SELECT * FROM t45 WHERE b=? AND a>? } {/*USING INDEX i45 (b=? AND a>?)*/} do_execsql_test 5.2 { SELECT * FROM t45 WHERE b='two' AND a>4 } {5 two x 7 two x 9 two x} do_execsql_test 5.3 { SELECT * FROM t45 WHERE b='one' AND a<8 ................................................................................ WITH r(x) AS ( SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100 ) INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r; } set queries { 1 2 "c = 5 AND a = 1" {/*i46 (c=? AND a=?)*/} 2 6 "c = 4 AND a < 3" {/*i46 (c=? AND a<?)*/} 3 4 "c = 2 AND a >= 3" {/*i46 (c=? AND a>?)*/} 4 1 "c = 2 AND a = 1 AND b<10" {/*i46 (c=? AND a=? AND b<?)*/} 5 1 "c = 0 AND a = 0 AND b>5" {/*i46 (c=? AND a=? AND b>?)*/} } foreach {tn cnt where eqp} $queries { do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt } do_execsql_test 5.6 { |
|
|
|
|
|
|
|
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
...
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
|
INSERT INTO t45 VALUES(5, 'two', 'x');
INSERT INTO t45 VALUES(7, 'two', 'x');
INSERT INTO t45 VALUES(9, 'two', 'x');
}
do_eqp_test 5.1 {
SELECT * FROM t45 WHERE b=? AND a>?
} {USING INDEX i45 (b=? AND a>?)}
do_execsql_test 5.2 {
SELECT * FROM t45 WHERE b='two' AND a>4
} {5 two x 7 two x 9 two x}
do_execsql_test 5.3 {
SELECT * FROM t45 WHERE b='one' AND a<8
................................................................................
WITH r(x) AS (
SELECT 1 UNION ALL SELECT x+1 FROM r WHERE x<100
)
INSERT INTO t46 SELECT x / 20, x % 20, x % 10, x FROM r;
}
set queries {
1 2 "c = 5 AND a = 1" {i46 (c=? AND a=?)}
2 6 "c = 4 AND a < 3" {i46 (c=? AND a<?)}
3 4 "c = 2 AND a >= 3" {i46 (c=? AND a>?)}
4 1 "c = 2 AND a = 1 AND b<10" {i46 (c=? AND a=? AND b<?)}
5 1 "c = 0 AND a = 0 AND b>5" {i46 (c=? AND a=? AND b>?)}
}
foreach {tn cnt where eqp} $queries {
do_execsql_test 5.5.$tn.1 "SELECT count(*) FROM t46 WHERE $where" $cnt
}
do_execsql_test 5.6 {
|