Merge branch 'prerelease' of ssh://github.com/sqlcipher/sqlcipher into prerelease
[sqlcipher.git] / test / distinct.test
blob3a3354456102bf8dba26122e501be903232f59ec
1 # 2011 July 1
3 # The author disclaims copyright to this source code.  In place of
4 # a legal notice, here is a blessing:
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.
10 #***********************************************************************
11 # This file implements regression tests for SQLite library.  The
12 # focus of this script is the DISTINCT modifier.
15 set testdir [file dirname $argv0]
16 source $testdir/tester.tcl
18 ifcapable !compound {
19   finish_test
20   return
23 set testprefix distinct
26 proc is_distinct_noop {sql} {
27   set sql1 $sql
28   set sql2 [string map {DISTINCT ""} $sql]
30   set program1 [list]
31   set program2 [list]
32   db eval "EXPLAIN $sql1" {
33     if {$opcode != "Noop"} { lappend program1 $opcode }
34   }
35   db eval "EXPLAIN $sql2" {
36     if {$opcode != "Noop"} { lappend program2 $opcode }
37   }
39   return [expr {$program1==$program2}]
42 proc do_distinct_noop_test {tn sql} {
43   uplevel [list do_test $tn [list is_distinct_noop $sql] 1]
45 proc do_distinct_not_noop_test {tn sql} {
46   uplevel [list do_test $tn [list is_distinct_noop $sql] 0]
49 proc do_temptables_test {tn sql temptables} {
50   uplevel [list do_test $tn [subst -novar {
51     set ret ""
52     db eval "EXPLAIN [set sql]" {
53       if {$opcode == "OpenEphemeral" || $opcode == "SorterOpen"} { 
54         if {$p5 != "08" && $p5!="00"} { error "p5 = $p5" }
55         if {$p5 == "08"} {
56           lappend ret hash
57         } else {
58           lappend ret btree
59         }
60       }
61     }
62     set ret
63   }] $temptables]
67 #-------------------------------------------------------------------------
68 # The following tests - distinct-1.* - check that the planner correctly 
69 # detects cases where a UNIQUE index means that a DISTINCT clause is 
70 # redundant. Currently the planner only detects such cases when there
71 # is a single table in the FROM clause.
73 do_execsql_test 1.0 {
74   CREATE TABLE t1(a, b, c, d);
75   CREATE UNIQUE INDEX i1 ON t1(b, c);
76   CREATE UNIQUE INDEX i2 ON t1(d COLLATE nocase);
78   CREATE TABLE t2(x INTEGER PRIMARY KEY, y);
80   CREATE TABLE t3(c1 PRIMARY KEY NOT NULL, c2 NOT NULL);
81   CREATE INDEX i3 ON t3(c2);
83   CREATE TABLE t4(a, b NOT NULL, c NOT NULL, d NOT NULL);
84   CREATE UNIQUE INDEX t4i1 ON t4(b, c);
85   CREATE UNIQUE INDEX t4i2 ON t4(d COLLATE nocase);
87 foreach {tn noop sql} {
89   1.1 0   "SELECT DISTINCT b, c FROM t1"
90   1.2 1   "SELECT DISTINCT b, c FROM t4"
91   2.1 0   "SELECT DISTINCT c FROM t1 WHERE b = ?"
92   2.2 1   "SELECT DISTINCT c FROM t4 WHERE b = ?"
93   3   1   "SELECT DISTINCT rowid FROM t1"
94   4   1   "SELECT DISTINCT rowid, a FROM t1"
95   5   1   "SELECT DISTINCT x FROM t2"
96   6   1   "SELECT DISTINCT * FROM t2"
97   7   1   "SELECT DISTINCT * FROM (SELECT * FROM t2)"
99   8.1 0   "SELECT DISTINCT * FROM t1"
100   8.2 1   "SELECT DISTINCT * FROM t4"
102   8   0   "SELECT DISTINCT a, b FROM t1"
104   9   0   "SELECT DISTINCT c FROM t1 WHERE b IN (1,2)"
105   10  0   "SELECT DISTINCT c FROM t1"
106   11  0   "SELECT DISTINCT b FROM t1"
108   12.1 0   "SELECT DISTINCT a, d FROM t1"
109   12.2 0   "SELECT DISTINCT a, d FROM t4"
110   13.1 0   "SELECT DISTINCT a, b, c COLLATE nocase FROM t1"
111   13.2 0   "SELECT DISTINCT a, b, c COLLATE nocase FROM t4"
112   14.1 0   "SELECT DISTINCT a, d COLLATE nocase FROM t1"
113   14.2 1   "SELECT DISTINCT a, d COLLATE nocase FROM t4"
115   15   0   "SELECT DISTINCT a, d COLLATE binary FROM t1"
116   16.1 0   "SELECT DISTINCT a, b, c COLLATE binary FROM t1"
117   16.2 1   "SELECT DISTINCT a, b, c COLLATE binary FROM t4"
119   16  0   "SELECT DISTINCT t1.rowid FROM t1, t2"
120   17  0   { /* Technically, it would be possible to detect that DISTINCT
121             ** is a no-op in cases like the following. But SQLite does not
122             ** do so. */
123             SELECT DISTINCT t1.rowid FROM t1, t2 WHERE t1.rowid=t2.rowid }
125   18  1   "SELECT DISTINCT c1, c2 FROM t3"
126   19  1   "SELECT DISTINCT c1 FROM t3"
127   20  1   "SELECT DISTINCT * FROM t3"
128   21  0   "SELECT DISTINCT c2 FROM t3"
130   22  0   "SELECT DISTINCT * FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
131   23  1   "SELECT DISTINCT rowid FROM (SELECT 1, 2, 3 UNION SELECT 4, 5, 6)"
133   24  0   "SELECT DISTINCT rowid/2 FROM t1"
134   25  1   "SELECT DISTINCT rowid/2, rowid FROM t1"
135   26.1  0   "SELECT DISTINCT rowid/2, b FROM t1 WHERE c = ?"
136   26.2  1   "SELECT DISTINCT rowid/2, b FROM t4 WHERE c = ?"
137 } {
138   if {$noop} {
139     do_distinct_noop_test 1.$tn $sql
140   } else {
141     do_distinct_not_noop_test 1.$tn $sql
142   }
145 #-------------------------------------------------------------------------
146 # The following tests - distinct-2.* - test cases where an index is
147 # used to deliver results in order of the DISTINCT expressions. 
149 drop_all_tables
150 do_execsql_test 2.0 {
151   CREATE TABLE t1(a, b, c);
153   CREATE INDEX i1 ON t1(a, b);
154   CREATE INDEX i2 ON t1(b COLLATE nocase, c COLLATE nocase);
156   INSERT INTO t1 VALUES('a', 'b', 'c');
157   INSERT INTO t1 VALUES('A', 'B', 'C');
158   INSERT INTO t1 VALUES('a', 'b', 'c');
159   INSERT INTO t1 VALUES('A', 'B', 'C');
162 foreach {tn sql temptables res} {
163   1   "a, b FROM t1"                                       {}      {A B a b}
164   2   "b, a FROM t1"                                       {}      {B A b a}
165   3   "a, b, c FROM t1"                                    {hash}  {a b c A B C}
166   4   "a, b, c FROM t1 ORDER BY a, b, c"                   {btree} {A B C a b c}
167   5   "b FROM t1 WHERE a = 'a'"                            {}      {b}
168   6   "b FROM t1"                                          {hash}  {b B}
169   7   "a FROM t1"                                          {}      {A a}
170   8   "b COLLATE nocase FROM t1"                           {}      {b}
171   9   "b COLLATE nocase FROM t1 ORDER BY b COLLATE nocase" {}      {B}
172 } {
173   do_execsql_test    2.$tn.1 "SELECT DISTINCT $sql" $res
174   do_temptables_test 2.$tn.2 "SELECT DISTINCT $sql" $temptables
177 do_execsql_test 2.A {
178   SELECT (SELECT DISTINCT o.a FROM t1 AS i) FROM t1 AS o;
179 } {a A a A}
184 finish_test