1 | #include "catch.hpp" |
2 | #include "test_helpers.hpp" |
3 | |
4 | using namespace duckdb; |
5 | using namespace std; |
6 | |
7 | TEST_CASE("Test case insensitive collation" , "[collate]" ) { |
8 | unique_ptr<QueryResult> result; |
9 | DuckDB db(nullptr); |
10 | Connection con(db); |
11 | |
12 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOCASE)" )); |
13 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('hello'), ('WoRlD'), ('world'), ('Mühleisen')" )); |
14 | |
15 | // collate in equality |
16 | result = con.Query("SELECT * FROM collate_test WHERE s='HeLlo'" ); |
17 | REQUIRE(CHECK_COLUMN(result, 0, {"hello" })); |
18 | result = con.Query("SELECT * FROM collate_test WHERE s='MÜhleisen'" ); |
19 | REQUIRE(CHECK_COLUMN(result, 0, {"Mühleisen" })); |
20 | result = con.Query("SELECT * FROM collate_test WHERE s='world'" ); |
21 | REQUIRE(CHECK_COLUMN(result, 0, {"WoRlD" , "world" })); |
22 | |
23 | // join with collation |
24 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_join_table(s VARCHAR, i INTEGER)" )); |
25 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_join_table VALUES ('HeLlO', 1), ('mÜHLEISEN', 3)" )); |
26 | |
27 | result = con.Query("SELECT collate_test.s, collate_join_table.s, i FROM collate_test JOIN collate_join_table ON " |
28 | "(collate_test.s=collate_join_table.s) ORDER BY i" ); |
29 | REQUIRE(CHECK_COLUMN(result, 0, {"hello" , "Mühleisen" })); |
30 | REQUIRE(CHECK_COLUMN(result, 1, {"HeLlO" , "mÜHLEISEN" })); |
31 | REQUIRE(CHECK_COLUMN(result, 2, {1, 3})); |
32 | |
33 | // ORDER BY with collation |
34 | REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test" )); |
35 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOCASE)" )); |
36 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hallo'), ('ham'), ('HELLO'), ('hElp')" )); |
37 | |
38 | result = con.Query("SELECT * FROM collate_test ORDER BY s" ); |
39 | REQUIRE(CHECK_COLUMN(result, 0, {"Hallo" , "ham" , "HELLO" , "hElp" })); |
40 | |
41 | // DISTINCT with collation |
42 | REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test" )); |
43 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOCASE)" )); |
44 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hallo'), ('hallo')" )); |
45 | |
46 | result = con.Query("SELECT DISTINCT s FROM collate_test" ); |
47 | REQUIRE(CHECK_COLUMN(result, 0, {"Hallo" })); |
48 | |
49 | // LIKE with collation: not yet supported |
50 | // REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test")); |
51 | // REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOCASE)")); |
52 | // REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hallo'), ('hallo')")); |
53 | |
54 | // result = con.Query("SELECT * FROM collate_test WHERE s LIKE 'h%'"); |
55 | // REQUIRE(CHECK_COLUMN(result, 0, {"Hallo", "hallo"})); |
56 | // result = con.Query("SELECT * FROM collate_test WHERE s LIKE 'HA%'"); |
57 | // REQUIRE(CHECK_COLUMN(result, 0, {"Hallo", "hallo"})); |
58 | } |
59 | |
60 | TEST_CASE("Test accent insensitive collation" , "[collate]" ) { |
61 | unique_ptr<QueryResult> result; |
62 | DuckDB db(nullptr); |
63 | Connection con(db); |
64 | |
65 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT)" )); |
66 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Mühleisen'), ('Hëllö')" )); |
67 | |
68 | // collate in equality |
69 | result = con.Query("SELECT * FROM collate_test WHERE s='Muhleisen'" ); |
70 | REQUIRE(CHECK_COLUMN(result, 0, {"Mühleisen" })); |
71 | result = con.Query("SELECT * FROM collate_test WHERE s='mühleisen'" ); |
72 | REQUIRE(CHECK_COLUMN(result, 0, {})); |
73 | result = con.Query("SELECT * FROM collate_test WHERE s='Hello'" ); |
74 | REQUIRE(CHECK_COLUMN(result, 0, {"Hëllö" })); |
75 | |
76 | // join with collation |
77 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_join_table(s VARCHAR, i INTEGER)" )); |
78 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_join_table VALUES ('Hello', 1), ('Muhleisen', 3)" )); |
79 | |
80 | result = con.Query("SELECT collate_test.s, collate_join_table.s, i FROM collate_test JOIN collate_join_table ON " |
81 | "(collate_test.s=collate_join_table.s) ORDER BY 1" ); |
82 | REQUIRE(CHECK_COLUMN(result, 0, {"Hëllö" , "Mühleisen" })); |
83 | REQUIRE(CHECK_COLUMN(result, 1, {"Hello" , "Muhleisen" })); |
84 | REQUIRE(CHECK_COLUMN(result, 2, {1, 3})); |
85 | |
86 | // ORDER BY with collation |
87 | REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test" )); |
88 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT)" )); |
89 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hällo'), ('Hallo'), ('Hello')" )); |
90 | |
91 | result = con.Query("SELECT * FROM collate_test ORDER BY s" ); |
92 | REQUIRE(CHECK_COLUMN(result, 0, {"Hällo" , "Hallo" , "Hello" })); |
93 | |
94 | // DISTINCT with collation |
95 | REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test" )); |
96 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT)" )); |
97 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hällo'), ('Hallo')" )); |
98 | |
99 | result = con.Query("SELECT DISTINCT s FROM collate_test" ); |
100 | REQUIRE(CHECK_COLUMN(result, 0, {"Hällo" })); |
101 | |
102 | // LIKE with collation: not yet supported |
103 | // REQUIRE_NO_FAIL(con.Query("DROP TABLE collate_test")); |
104 | // REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT)")); |
105 | // REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Hällo'), ('Hallö')")); |
106 | |
107 | // result = con.Query("SELECT * FROM collate_test WHERE s LIKE '%a%'"); |
108 | // REQUIRE(CHECK_COLUMN(result, 0, {"Hällo", "Hallö"})); |
109 | // result = con.Query("SELECT * FROM collate_test WHERE s LIKE '%_ö'"); |
110 | // REQUIRE(CHECK_COLUMN(result, 0, {"Hällo", "Hallö"})); |
111 | // result = con.Query("SELECT * FROM collate_test WHERE s LIKE '%_ó'"); |
112 | // REQUIRE(CHECK_COLUMN(result, 0, {"Hällo", "Hallö"})); |
113 | } |
114 | |
115 | TEST_CASE("Test combined collations" , "[collate]" ) { |
116 | unique_ptr<QueryResult> result; |
117 | DuckDB db(nullptr); |
118 | Connection con(db); |
119 | |
120 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT.NOCASE)" )); |
121 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('Mühleisen'), ('Hëllö')" )); |
122 | |
123 | // collate in equality |
124 | result = con.Query("SELECT * FROM collate_test WHERE s='Muhleisen'" ); |
125 | REQUIRE(CHECK_COLUMN(result, 0, {"Mühleisen" })); |
126 | result = con.Query("SELECT * FROM collate_test WHERE s='muhleisen'" ); |
127 | REQUIRE(CHECK_COLUMN(result, 0, {"Mühleisen" })); |
128 | result = con.Query("SELECT * FROM collate_test WHERE s='hEllô'" ); |
129 | REQUIRE(CHECK_COLUMN(result, 0, {"Hëllö" })); |
130 | } |
131 | |
132 | TEST_CASE("Test COLLATE in individual expressions" , "[collate]" ) { |
133 | unique_ptr<QueryResult> result; |
134 | DuckDB db(nullptr); |
135 | Connection con(db); |
136 | |
137 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR)" )); |
138 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('hEllO'), ('WöRlD'), ('wozld')" )); |
139 | |
140 | // collate in equality |
141 | result = con.Query("SELECT 'hëllo' COLLATE NOACCENT='hello'" ); |
142 | REQUIRE(CHECK_COLUMN(result, 0, {true})); |
143 | result = con.Query("SELECT * FROM collate_test WHERE s='hello'" ); |
144 | REQUIRE(CHECK_COLUMN(result, 0, {})); |
145 | result = con.Query("SELECT * FROM collate_test WHERE s='hello' COLLATE NOCASE" ); |
146 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" })); |
147 | result = con.Query("SELECT * FROM collate_test WHERE s COLLATE NOCASE='hello'" ); |
148 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" })); |
149 | |
150 | // conflict in collate statements results in an error |
151 | REQUIRE_FAIL(con.Query("SELECT * FROM collate_test WHERE s COLLATE NOCASE='hello' COLLATE NOACCENT" )); |
152 | |
153 | // we can also do this in the order |
154 | result = con.Query("SELECT * FROM collate_test ORDER BY s COLLATE NOCASE" ); |
155 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" , "wozld" , "WöRlD" })); |
156 | result = con.Query("SELECT * FROM collate_test ORDER BY s COLLATE NOCASE.NOACCENT" ); |
157 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" , "WöRlD" , "wozld" })); |
158 | } |
159 | |
160 | TEST_CASE("Test default collations" , "[collate]" ) { |
161 | unique_ptr<QueryResult> result; |
162 | DBConfig config; |
163 | config.collation = "NOCASE" ; |
164 | DuckDB db(nullptr, &config); |
165 | Connection con(db); |
166 | |
167 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR)" )); |
168 | REQUIRE_NO_FAIL(con.Query("INSERT INTO collate_test VALUES ('hEllO'), ('WöRlD'), ('wozld')" )); |
169 | |
170 | // collate in equality |
171 | result = con.Query("SELECT COUNT(*) FROM collate_test WHERE 'BlA'='bLa'" ); |
172 | REQUIRE(CHECK_COLUMN(result, 0, {3})); |
173 | result = con.Query("SELECT * FROM collate_test WHERE s='hello'" ); |
174 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" })); |
175 | |
176 | // collate in order |
177 | result = con.Query("SELECT * FROM collate_test ORDER BY s" ); |
178 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" , "wozld" , "WöRlD" })); |
179 | |
180 | // switch default collate using pragma |
181 | REQUIRE_NO_FAIL(con.Query("PRAGMA default_collation='NOCASE.NOACCENT'" )); |
182 | |
183 | result = con.Query("SELECT * FROM collate_test ORDER BY s" ); |
184 | REQUIRE(CHECK_COLUMN(result, 0, {"hEllO" , "WöRlD" , "wozld" })); |
185 | } |
186 | |
187 | TEST_CASE("Get list of collations" , "[collate]" ) { |
188 | unique_ptr<QueryResult> result; |
189 | DuckDB db(nullptr); |
190 | Connection con(db); |
191 | |
192 | result = con.Query("PRAGMA collations" ); |
193 | REQUIRE(CHECK_COLUMN(result, 0, {"noaccent" , "nocase" })); |
194 | |
195 | REQUIRE_FAIL(con.Query("PRAGMA collations=3" )); |
196 | } |
197 | |
198 | TEST_CASE("Test unsupported collations" , "[collate]" ) { |
199 | unique_ptr<QueryResult> result; |
200 | DuckDB db(nullptr); |
201 | Connection con(db); |
202 | |
203 | REQUIRE_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE blabla)" )); |
204 | REQUIRE_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE NOACCENT.NOACCENT)" )); |
205 | REQUIRE_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE 1)" )); |
206 | REQUIRE_FAIL(con.Query("CREATE TABLE collate_test(s VARCHAR COLLATE 'hello')" )); |
207 | |
208 | REQUIRE_FAIL(con.Query("PRAGMA default_collation='blabla'" )); |
209 | } |
210 | |