indexedby.test 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324
  1. # 2008 October 4
  2. #
  3. # The author disclaims copyright to this source code. In place of
  4. # a legal notice, here is a blessing:
  5. #
  6. # May you do good and not evil.
  7. # May you find forgiveness for yourself and forgive others.
  8. # May you share freely, never taking more than you give.
  9. #
  10. #***********************************************************************
  11. #
  12. # $Id: indexedby.test,v 1.5 2009/03/22 20:36:19 drh Exp $
  13. set testdir [file dirname $argv0]
  14. source $testdir/tester.tcl
  15. set ::testprefix indexedby
  16. # Create a schema with some indexes.
  17. #
  18. do_test indexedby-1.1 {
  19. execsql {
  20. CREATE TABLE t1(a, b);
  21. CREATE INDEX i1 ON t1(a);
  22. CREATE INDEX i2 ON t1(b);
  23. CREATE TABLE t2(c, d);
  24. CREATE INDEX i3 ON t2(c);
  25. CREATE INDEX i4 ON t2(d);
  26. CREATE TABLE t3(e PRIMARY KEY, f);
  27. CREATE VIEW v1 AS SELECT * FROM t1;
  28. }
  29. } {}
  30. # Explain Query Plan
  31. #
  32. proc EQP {sql} {
  33. uplevel "execsql {EXPLAIN QUERY PLAN $sql}"
  34. }
  35. # These tests are to check that "EXPLAIN QUERY PLAN" is working as expected.
  36. #
  37. do_execsql_test indexedby-1.2 {
  38. EXPLAIN QUERY PLAN select * from t1 WHERE a = 10;
  39. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
  40. do_execsql_test indexedby-1.3 {
  41. EXPLAIN QUERY PLAN select * from t1 ;
  42. } {0 0 0 {SCAN TABLE t1}}
  43. do_execsql_test indexedby-1.4 {
  44. EXPLAIN QUERY PLAN select * from t1, t2 WHERE c = 10;
  45. } {
  46. 0 0 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)}
  47. 0 1 0 {SCAN TABLE t1}
  48. }
  49. # Parser tests. Test that an INDEXED BY or NOT INDEX clause can be
  50. # attached to a table in the FROM clause, but not to a sub-select or
  51. # SQL view. Also test that specifying an index that does not exist or
  52. # is attached to a different table is detected as an error.
  53. #
  54. do_test indexedby-2.1 {
  55. execsql { SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'}
  56. } {}
  57. do_test indexedby-2.2 {
  58. execsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'}
  59. } {}
  60. do_test indexedby-2.3 {
  61. execsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'}
  62. } {}
  63. do_test indexedby-2.4 {
  64. catchsql { SELECT * FROM t1 INDEXED BY i3 WHERE a = 'one' AND b = 'two'}
  65. } {1 {no such index: i3}}
  66. do_test indexedby-2.5 {
  67. catchsql { SELECT * FROM t1 INDEXED BY i5 WHERE a = 'one' AND b = 'two'}
  68. } {1 {no such index: i5}}
  69. do_test indexedby-2.6 {
  70. catchsql { SELECT * FROM t1 INDEXED BY WHERE a = 'one' AND b = 'two'}
  71. } {1 {near "WHERE": syntax error}}
  72. do_test indexedby-2.7 {
  73. catchsql { SELECT * FROM v1 INDEXED BY i1 WHERE a = 'one' }
  74. } {1 {no such index: i1}}
  75. # Tests for single table cases.
  76. #
  77. do_execsql_test indexedby-3.1 {
  78. EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE a = 'one' AND b = 'two'
  79. } {0 0 0 {SCAN TABLE t1}}
  80. do_execsql_test indexedby-3.2 {
  81. EXPLAIN QUERY PLAN
  82. SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' AND b = 'two'
  83. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
  84. do_execsql_test indexedby-3.3 {
  85. EXPLAIN QUERY PLAN
  86. SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' AND b = 'two'
  87. } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
  88. do_test indexedby-3.4 {
  89. catchsql { SELECT * FROM t1 INDEXED BY i2 WHERE a = 'one' }
  90. } {1 {no query solution}}
  91. do_test indexedby-3.5 {
  92. catchsql { SELECT * FROM t1 INDEXED BY i2 ORDER BY a }
  93. } {1 {no query solution}}
  94. do_test indexedby-3.6 {
  95. catchsql { SELECT * FROM t1 INDEXED BY i1 WHERE a = 'one' }
  96. } {0 {}}
  97. do_test indexedby-3.7 {
  98. catchsql { SELECT * FROM t1 INDEXED BY i1 ORDER BY a }
  99. } {0 {}}
  100. do_execsql_test indexedby-3.8 {
  101. EXPLAIN QUERY PLAN
  102. SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 ORDER BY e
  103. } {0 0 0 {SCAN TABLE t3 USING INDEX sqlite_autoindex_t3_1}}
  104. do_execsql_test indexedby-3.9 {
  105. EXPLAIN QUERY PLAN
  106. SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE e = 10
  107. } {0 0 0 {SEARCH TABLE t3 USING INDEX sqlite_autoindex_t3_1 (e=?)}}
  108. do_test indexedby-3.10 {
  109. catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_1 WHERE f = 10 }
  110. } {1 {no query solution}}
  111. do_test indexedby-3.11 {
  112. catchsql { SELECT * FROM t3 INDEXED BY sqlite_autoindex_t3_2 WHERE f = 10 }
  113. } {1 {no such index: sqlite_autoindex_t3_2}}
  114. # Tests for multiple table cases.
  115. #
  116. do_execsql_test indexedby-4.1 {
  117. EXPLAIN QUERY PLAN SELECT * FROM t1, t2 WHERE a = c
  118. } {
  119. 0 0 0 {SCAN TABLE t1}
  120. 0 1 1 {SEARCH TABLE t2 USING INDEX i3 (c=?)}
  121. }
  122. do_execsql_test indexedby-4.2 {
  123. EXPLAIN QUERY PLAN SELECT * FROM t1 INDEXED BY i1, t2 WHERE a = c
  124. } {
  125. 0 0 1 {SCAN TABLE t2}
  126. 0 1 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}
  127. }
  128. do_test indexedby-4.3 {
  129. catchsql {
  130. SELECT * FROM t1 INDEXED BY i1, t2 INDEXED BY i3 WHERE a=c
  131. }
  132. } {1 {no query solution}}
  133. do_test indexedby-4.4 {
  134. catchsql {
  135. SELECT * FROM t2 INDEXED BY i3, t1 INDEXED BY i1 WHERE a=c
  136. }
  137. } {1 {no query solution}}
  138. # Test embedding an INDEXED BY in a CREATE VIEW statement. This block
  139. # also tests that nothing bad happens if an index refered to by
  140. # a CREATE VIEW statement is dropped and recreated.
  141. #
  142. do_execsql_test indexedby-5.1 {
  143. CREATE VIEW v2 AS SELECT * FROM t1 INDEXED BY i1 WHERE a > 5;
  144. EXPLAIN QUERY PLAN SELECT * FROM v2
  145. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
  146. do_execsql_test indexedby-5.2 {
  147. EXPLAIN QUERY PLAN SELECT * FROM v2 WHERE b = 10
  148. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a>?)}}
  149. do_test indexedby-5.3 {
  150. execsql { DROP INDEX i1 }
  151. catchsql { SELECT * FROM v2 }
  152. } {1 {no such index: i1}}
  153. do_test indexedby-5.4 {
  154. # Recreate index i1 in such a way as it cannot be used by the view query.
  155. execsql { CREATE INDEX i1 ON t1(b) }
  156. catchsql { SELECT * FROM v2 }
  157. } {1 {no query solution}}
  158. do_test indexedby-5.5 {
  159. # Drop and recreate index i1 again. This time, create it so that it can
  160. # be used by the query.
  161. execsql { DROP INDEX i1 ; CREATE INDEX i1 ON t1(a) }
  162. catchsql { SELECT * FROM v2 }
  163. } {0 {}}
  164. # Test that "NOT INDEXED" may use the rowid index, but not others.
  165. #
  166. do_execsql_test indexedby-6.1 {
  167. EXPLAIN QUERY PLAN SELECT * FROM t1 WHERE b = 10 ORDER BY rowid
  168. } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
  169. do_execsql_test indexedby-6.2 {
  170. EXPLAIN QUERY PLAN SELECT * FROM t1 NOT INDEXED WHERE b = 10 ORDER BY rowid
  171. } {0 0 0 {SCAN TABLE t1}}
  172. # Test that "INDEXED BY" can be used in a DELETE statement.
  173. #
  174. do_execsql_test indexedby-7.1 {
  175. EXPLAIN QUERY PLAN DELETE FROM t1 WHERE a = 5
  176. } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
  177. do_execsql_test indexedby-7.2 {
  178. EXPLAIN QUERY PLAN DELETE FROM t1 NOT INDEXED WHERE a = 5
  179. } {0 0 0 {SCAN TABLE t1}}
  180. do_execsql_test indexedby-7.3 {
  181. EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5
  182. } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
  183. do_execsql_test indexedby-7.4 {
  184. EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i1 WHERE a = 5 AND b = 10
  185. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
  186. do_execsql_test indexedby-7.5 {
  187. EXPLAIN QUERY PLAN DELETE FROM t1 INDEXED BY i2 WHERE a = 5 AND b = 10
  188. } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
  189. do_test indexedby-7.6 {
  190. catchsql { DELETE FROM t1 INDEXED BY i2 WHERE a = 5}
  191. } {1 {no query solution}}
  192. # Test that "INDEXED BY" can be used in an UPDATE statement.
  193. #
  194. do_execsql_test indexedby-8.1 {
  195. EXPLAIN QUERY PLAN UPDATE t1 SET rowid=rowid+1 WHERE a = 5
  196. } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
  197. do_execsql_test indexedby-8.2 {
  198. EXPLAIN QUERY PLAN UPDATE t1 NOT INDEXED SET rowid=rowid+1 WHERE a = 5
  199. } {0 0 0 {SCAN TABLE t1}}
  200. do_execsql_test indexedby-8.3 {
  201. EXPLAIN QUERY PLAN UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5
  202. } {0 0 0 {SEARCH TABLE t1 USING COVERING INDEX i1 (a=?)}}
  203. do_execsql_test indexedby-8.4 {
  204. EXPLAIN QUERY PLAN
  205. UPDATE t1 INDEXED BY i1 SET rowid=rowid+1 WHERE a = 5 AND b = 10
  206. } {0 0 0 {SEARCH TABLE t1 USING INDEX i1 (a=?)}}
  207. do_execsql_test indexedby-8.5 {
  208. EXPLAIN QUERY PLAN
  209. UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5 AND b = 10
  210. } {0 0 0 {SEARCH TABLE t1 USING INDEX i2 (b=?)}}
  211. do_test indexedby-8.6 {
  212. catchsql { UPDATE t1 INDEXED BY i2 SET rowid=rowid+1 WHERE a = 5}
  213. } {1 {no query solution}}
  214. # Test that bug #3560 is fixed.
  215. #
  216. do_test indexedby-9.1 {
  217. execsql {
  218. CREATE TABLE maintable( id integer);
  219. CREATE TABLE joinme(id_int integer, id_text text);
  220. CREATE INDEX joinme_id_text_idx on joinme(id_text);
  221. CREATE INDEX joinme_id_int_idx on joinme(id_int);
  222. }
  223. } {}
  224. do_test indexedby-9.2 {
  225. catchsql {
  226. select * from maintable as m inner join
  227. joinme as j indexed by joinme_id_text_idx
  228. on ( m.id = j.id_int)
  229. }
  230. } {1 {no query solution}}
  231. do_test indexedby-9.3 {
  232. catchsql { select * from maintable, joinme INDEXED by joinme_id_text_idx }
  233. } {1 {no query solution}}
  234. # Make sure we can still create tables, indices, and columns whose name
  235. # is "indexed".
  236. #
  237. do_test indexedby-10.1 {
  238. execsql {
  239. CREATE TABLE indexed(x,y);
  240. INSERT INTO indexed VALUES(1,2);
  241. SELECT * FROM indexed;
  242. }
  243. } {1 2}
  244. do_test indexedby-10.2 {
  245. execsql {
  246. CREATE INDEX i10 ON indexed(x);
  247. SELECT * FROM indexed indexed by i10 where x>0;
  248. }
  249. } {1 2}
  250. do_test indexedby-10.3 {
  251. execsql {
  252. DROP TABLE indexed;
  253. CREATE TABLE t10(indexed INTEGER);
  254. INSERT INTO t10 VALUES(1);
  255. CREATE INDEX indexed ON t10(indexed);
  256. SELECT * FROM t10 indexed by indexed WHERE indexed>0
  257. }
  258. } {1}
  259. #-------------------------------------------------------------------------
  260. # Ensure that the rowid at the end of each index entry may be used
  261. # for equality constraints in the same way as other indexed fields.
  262. #
  263. do_execsql_test 11.1 {
  264. CREATE TABLE x1(a, b TEXT);
  265. CREATE INDEX x1i ON x1(a, b);
  266. INSERT INTO x1 VALUES(1, 1);
  267. INSERT INTO x1 VALUES(1, 1);
  268. INSERT INTO x1 VALUES(1, 1);
  269. INSERT INTO x1 VALUES(1, 1);
  270. }
  271. do_execsql_test 11.2 {
  272. SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid=3;
  273. } {1 1 3}
  274. do_execsql_test 11.3 {
  275. SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3';
  276. } {1 1 3}
  277. do_execsql_test 11.4 {
  278. SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
  279. } {1 1 3}
  280. do_eqp_test 11.5 {
  281. SELECT a,b,rowid FROM x1 INDEXED BY x1i WHERE a=1 AND b=1 AND rowid='3.0';
  282. } {0 0 0 {SEARCH TABLE x1 USING COVERING INDEX x1i (a=? AND b=? AND rowid=?)}}
  283. do_execsql_test 11.6 {
  284. CREATE TABLE x2(c INTEGER PRIMARY KEY, a, b TEXT);
  285. CREATE INDEX x2i ON x2(a, b);
  286. INSERT INTO x2 VALUES(1, 1, 1);
  287. INSERT INTO x2 VALUES(2, 1, 1);
  288. INSERT INTO x2 VALUES(3, 1, 1);
  289. INSERT INTO x2 VALUES(4, 1, 1);
  290. }
  291. do_execsql_test 11.7 {
  292. SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c=3;
  293. } {1 1 3}
  294. do_execsql_test 11.8 {
  295. SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3';
  296. } {1 1 3}
  297. do_execsql_test 11.9 {
  298. SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
  299. } {1 1 3}
  300. do_eqp_test 11.10 {
  301. SELECT a,b,c FROM x2 INDEXED BY x2i WHERE a=1 AND b=1 AND c='3.0';
  302. } {0 0 0 {SEARCH TABLE x2 USING COVERING INDEX x2i (a=? AND b=? AND rowid=?)}}
  303. finish_test