1 | #include "catch.hpp" |
2 | #include "duckdb/common/file_system.hpp" |
3 | #include "dbgen.hpp" |
4 | #include "test_helpers.hpp" |
5 | |
6 | #include "duckdb.hpp" |
7 | #include "duckdb/parser/parsed_data/create_table_function_info.hpp" |
8 | #include "duckdb/function/table_function.hpp" |
9 | #include "duckdb/function/scalar_function.hpp" |
10 | #include "duckdb/execution/operator/list.hpp" |
11 | #include "duckdb/catalog/catalog_entry/list.hpp" |
12 | #include "duckdb/function/function.hpp" |
13 | #include "duckdb/planner/expression/list.hpp" |
14 | #include "duckdb/parser/expression/function_expression.hpp" |
15 | #include "duckdb/main/client_context.hpp" |
16 | #include "duckdb/function/aggregate_function.hpp" |
17 | #include "duckdb/parser/parsed_data/create_aggregate_function_info.hpp" |
18 | |
19 | using namespace duckdb; |
20 | using namespace std; |
21 | |
22 | TEST_CASE("Test scalar lists" , "[nested]" ) { |
23 | DuckDB db(nullptr); |
24 | Connection con(db); |
25 | con.EnableQueryVerification(); |
26 | unique_ptr<QueryResult> result; |
27 | |
28 | con.Query("CREATE TABLE list_data (g INTEGER, e INTEGER)" ); |
29 | con.Query("INSERT INTO list_data VALUES (1, 1), (1, 2), (2, 3), (2, 4), (2, 5), (3, 6), (5, NULL)" ); |
30 | |
31 | result = con.Query("SELECT LIST_VALUE(1, 2, 3, '4') a, LIST_VALUE('a','b','c') b, LIST_VALUE(42, NULL) c, " |
32 | "LIST_VALUE(NULL, NULL, NULL) d, LIST_VALUE() e" ); |
33 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({1, 2, 3, 4})})); |
34 | REQUIRE(CHECK_COLUMN(result, 1, {Value::LIST({"a" , "b" , "c" })})); |
35 | REQUIRE(CHECK_COLUMN(result, 2, {Value::LIST({42, Value()})})); |
36 | REQUIRE(CHECK_COLUMN(result, 3, {Value::LIST({Value(), Value(), Value()})})); |
37 | REQUIRE(CHECK_COLUMN(result, 4, {Value::LIST({})})); |
38 | |
39 | result = con.Query( |
40 | "SELECT a FROM (VALUES (LIST_VALUE(1, 2, 3, 4)), (LIST_VALUE()), (LIST_VALUE(NULL)), (LIST_VALUE(42))) lv(a)" ); |
41 | REQUIRE(CHECK_COLUMN(result, 0, |
42 | {Value::LIST({1, 2, 3, 4}), Value::LIST({}), Value::LIST({Value()}), Value::LIST({42})})); |
43 | |
44 | result = con.Query("SELECT * FROM (VALUES ((LIST_VALUE()), (LIST_VALUE(NULL)), LIST_VALUE(1, 2))) lv(a)" ); |
45 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({})})); |
46 | REQUIRE(CHECK_COLUMN(result, 1, {Value::LIST({Value()})})); |
47 | REQUIRE(CHECK_COLUMN(result, 2, {Value::LIST({Value::INTEGER(1), Value::INTEGER(2)})})); |
48 | |
49 | result = con.Query("SELECT * FROM (VALUES (LIST_VALUE(1, 2)), (LIST_VALUE()), (LIST_VALUE(NULL))) lv(a)" ); |
50 | REQUIRE(CHECK_COLUMN( |
51 | result, 0, {Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}), Value::LIST({}), Value::LIST({Value()})})); |
52 | |
53 | // casting null to list or empty list to something else should work |
54 | result = con.Query("SELECT LIST_VALUE(1, 2, 3) UNION ALL SELECT LIST_VALUE(NULL) UNION ALL SELECT LIST_VALUE() " |
55 | "UNION ALL SELECT NULL" ); |
56 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({1, 2, 3}), Value::LIST({Value()}), Value::LIST({}), Value()})); |
57 | |
58 | result = con.Query(" SELECT NULL UNION ALL SELECT LIST_VALUE() UNION ALL SELECT LIST_VALUE(NULL) UNION ALL SELECT " |
59 | "LIST_VALUE(1, 2, 3)" ); |
60 | REQUIRE(CHECK_COLUMN(result, 0, {Value(), Value::LIST({}), Value::LIST({Value()}), Value::LIST({1, 2, 3})})); |
61 | |
62 | // empty list should not abort UNNEST |
63 | result = con.Query("SELECT UNNEST(a) ua FROM (VALUES (LIST_VALUE(1, 2, 3, 4)), (LIST_VALUE()), (LIST_VALUE(NULL)), " |
64 | "(LIST_VALUE(42))) lv(a)" ); |
65 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 4, Value(), 42})); |
66 | |
67 | // TODO this should work but does not. its also kind of obscure |
68 | // result = con.Query("SELECT UNNEST(a) ua FROM (VALUES (LIST_VALUE()), (LIST_VALUE(1, 2, 3, 4)), |
69 | //(LIST_VALUE(NULL)), " |
70 | // "(LIST_VALUE(42))) lv(a)"); |
71 | // REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 4, Value(), 42})); |
72 | // |
73 | // list child type mismatch |
74 | REQUIRE_FAIL(con.Query("SELECT * FROM (VALUES (LIST_VALUE(1, 2)), (LIST_VALUE()), (LIST_VALUE('a'))) lv(a)" )); |
75 | |
76 | // can't cast lists to stuff |
77 | REQUIRE_FAIL(con.Query("SELECT CAST(LIST_VALUE(42) AS INTEGER)" )); |
78 | |
79 | // can't add a number to a list |
80 | REQUIRE_FAIL(con.Query("SELECT LIST_VALUE(42) + 4" )); |
81 | |
82 | // can't add a number to a list |
83 | REQUIRE_FAIL(con.Query("SELECT LIST_VALUE(42, 'a')" )); |
84 | |
85 | // can have unnest anywhere |
86 | result = con.Query("SELECT CAST(UNNEST(LIST_VALUE(42))+2 AS INTEGER)" ); |
87 | REQUIRE(CHECK_COLUMN(result, 0, {44})); |
88 | |
89 | result = con.Query("SELECT LIST_VALUE(g, e, 42, NULL) FROM list_data WHERE g > 2" ); |
90 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({3, 6, 42, Value()}), Value::LIST({5, Value(), 42, Value()})})); |
91 | |
92 | result = con.Query("SELECT CASE WHEN g = 2 THEN LIST_VALUE(g, e, 42) ELSE LIST_VALUE(84, NULL) END FROM list_data " |
93 | "WHERE g > 1 UNION ALL SELECT LIST_VALUE(NULL)" ); |
94 | REQUIRE(CHECK_COLUMN(result, 0, |
95 | {Value::LIST({2, 3, 42}), Value::LIST({2, 4, 42}), Value::LIST({2, 5, 42}), |
96 | Value::LIST({84, Value()}), Value::LIST({84, Value()}), Value::LIST({Value()})})); |
97 | |
98 | // this should fail because the list child types do not match |
99 | REQUIRE_FAIL(con.Query( |
100 | "SELECT CASE WHEN g = 2 THEN LIST_VALUE(g, e, 42) ELSE LIST_VALUE('eeek') END FROM list_data WHERE g > 1" )); |
101 | } |
102 | |
103 | TEST_CASE("Test filter and projection of nested lists" , "[nested]" ) { |
104 | DuckDB db(nullptr); |
105 | Connection con(db); |
106 | con.EnableQueryVerification(); |
107 | unique_ptr<QueryResult> result; |
108 | |
109 | con.Query("CREATE TABLE list_data (g INTEGER, e INTEGER)" ); |
110 | con.Query("INSERT INTO list_data VALUES (1, 1), (1, 2), (2, 3), (2, 4), (2, 5), (3, 6), (5, NULL)" ); |
111 | |
112 | result = con.Query("SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 (a)" ); |
113 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)})})); |
114 | |
115 | result = con.Query("SELECT UNNEST(l1) FROM (SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 (a)) t1" ); |
116 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3})); |
117 | |
118 | result = con.Query("SELECT * FROM (SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 (a)) t1, (SELECT LIST(b) l2 " |
119 | "FROM (VALUES (4), (5), (6), (7)) AS t2 (b)) t2" ); |
120 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)})})); |
121 | REQUIRE(CHECK_COLUMN(result, 1, |
122 | {Value::LIST({Value::INTEGER(4), Value::INTEGER(5), Value::INTEGER(6), Value::INTEGER(7)})})); |
123 | |
124 | result = con.Query("SELECT UNNEST(l1) u1, UNNEST(l2) u2 FROM (SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 " |
125 | "(a)) t1, (SELECT LIST(b) l2 FROM (VALUES (4), (5), (6), (7)) AS t2 (b)) t2" ); |
126 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, Value()})); |
127 | REQUIRE(CHECK_COLUMN(result, 1, {4, 5, 6, 7})); |
128 | |
129 | result = con.Query("SELECT UNNEST(l1), l2 FROM (SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 (a)) t1, " |
130 | "(SELECT LIST(b) l2 FROM (VALUES (4), (5), (6), (7)) AS t2 (b)) t2" ); |
131 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3})); |
132 | REQUIRE(CHECK_COLUMN(result, 1, |
133 | {Value::LIST({Value::INTEGER(4), Value::INTEGER(5), Value::INTEGER(6), Value::INTEGER(7)}), |
134 | Value::LIST({Value::INTEGER(4), Value::INTEGER(5), Value::INTEGER(6), Value::INTEGER(7)}), |
135 | Value::LIST({Value::INTEGER(4), Value::INTEGER(5), Value::INTEGER(6), Value::INTEGER(7)})})); |
136 | |
137 | result = con.Query("SELECT l1, UNNEST(l2) FROM (SELECT LIST(a) l1 FROM (VALUES (1), (2), (3)) AS t1 (a)) t1, " |
138 | "(SELECT LIST(b) l2 FROM (VALUES (4), (5), (6), (7)) AS t2 (b)) t2" ); |
139 | REQUIRE(CHECK_COLUMN(result, 0, |
140 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)}), |
141 | Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)}), |
142 | Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)}), |
143 | Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3)})})); |
144 | REQUIRE(CHECK_COLUMN(result, 1, {4, 5, 6, 7})); |
145 | |
146 | result = con.Query("SELECT UNNEST(LIST(e)) ue, LIST(g) from list_data" ); |
147 | REQUIRE(CHECK_COLUMN(result, 0, |
148 | {Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5), |
149 | Value::INTEGER(6), Value()})); |
150 | REQUIRE(CHECK_COLUMN(result, 1, |
151 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
152 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
153 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
154 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
155 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
156 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
157 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
158 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
159 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
160 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
161 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
162 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)}), |
163 | Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
164 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)})})); |
165 | |
166 | result = con.Query("SELECT g, LIST(e) from list_data GROUP BY g ORDER BY g" ); |
167 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 5})); |
168 | REQUIRE(CHECK_COLUMN(result, 1, |
169 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}), |
170 | Value::LIST({Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5)}), |
171 | Value::LIST({Value::INTEGER(6)}), Value::LIST({Value()})})); |
172 | |
173 | result = con.Query("SELECT g, LIST(e) l1, LIST(e) l2 from list_data GROUP BY g ORDER BY g" ); |
174 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 5})); |
175 | REQUIRE(CHECK_COLUMN(result, 1, |
176 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}), |
177 | Value::LIST({Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5)}), |
178 | Value::LIST({Value::INTEGER(6)}), Value::LIST({Value()})})); |
179 | REQUIRE(CHECK_COLUMN(result, 2, |
180 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}), |
181 | Value::LIST({Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5)}), |
182 | Value::LIST({Value::INTEGER(6)}), Value::LIST({Value()})})); |
183 | |
184 | result = con.Query("SELECT g, LIST(e/2.0) from list_data GROUP BY g order by g" ); |
185 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 5})); |
186 | REQUIRE(CHECK_COLUMN(result, 1, |
187 | {Value::LIST({Value::DOUBLE(0.5), Value::DOUBLE(1)}), |
188 | Value::LIST({Value::DOUBLE(1.5), Value::DOUBLE(2), Value::DOUBLE(2.5)}), |
189 | Value::LIST({Value::DOUBLE(3)}), Value::LIST({Value()})})); |
190 | |
191 | result = con.Query("SELECT g, LIST(CAST(e AS VARCHAR)) from list_data GROUP BY g order by g" ); |
192 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 5})); |
193 | REQUIRE(CHECK_COLUMN(result, 1, |
194 | {Value::LIST({Value("1" ), Value("2" )}), Value::LIST({Value("3" ), Value("4" ), Value("5" )}), |
195 | Value::LIST({Value("6" )}), Value::LIST({Value()})})); |
196 | |
197 | result = con.Query("SELECT LIST(e) from list_data" ); |
198 | REQUIRE(CHECK_COLUMN(result, 0, |
199 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(4), |
200 | Value::INTEGER(5), Value::INTEGER(6), Value()})})); |
201 | |
202 | result = con.Query("SELECT UNNEST(LIST(e)) ue from list_data ORDER BY ue" ); |
203 | REQUIRE(CHECK_COLUMN(result, 0, {Value(), 1, 2, 3, 4, 5, 6})); |
204 | |
205 | result = con.Query("SELECT LIST(e), LIST(g) from list_data" ); |
206 | REQUIRE(CHECK_COLUMN(result, 0, |
207 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(4), |
208 | Value::INTEGER(5), Value::INTEGER(6), Value()})})); |
209 | REQUIRE(CHECK_COLUMN(result, 1, |
210 | {Value::LIST({Value::INTEGER(1), Value::INTEGER(1), Value::INTEGER(2), Value::INTEGER(2), |
211 | Value::INTEGER(2), Value::INTEGER(3), Value::INTEGER(5)})})); |
212 | |
213 | result = con.Query("SELECT LIST(42)" ); |
214 | REQUIRE(CHECK_COLUMN(result, 0, {Value::LIST({Value::INTEGER(42)})})); |
215 | |
216 | result = con.Query("SELECT LIST(42) FROM list_data" ); |
217 | REQUIRE(CHECK_COLUMN(result, 0, |
218 | {Value::LIST({Value::INTEGER(42), Value::INTEGER(42), Value::INTEGER(42), Value::INTEGER(42), |
219 | Value::INTEGER(42), Value::INTEGER(42), Value::INTEGER(42)})})); |
220 | |
221 | result = con.Query("SELECT UNNEST(LIST(42))" ); |
222 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
223 | |
224 | // unlist is alias of unnest for symmetry reasons |
225 | result = con.Query("SELECT UNLIST(LIST(42))" ); |
226 | REQUIRE(CHECK_COLUMN(result, 0, {42})); |
227 | |
228 | result = con.Query("SELECT UNNEST(LIST(e)) ue, UNNEST(LIST(g)) ug from list_data ORDER BY ue" ); |
229 | REQUIRE(CHECK_COLUMN(result, 0, {Value(), 1, 2, 3, 4, 5, 6})); |
230 | REQUIRE(CHECK_COLUMN(result, 1, {5, 1, 1, 2, 2, 2, 3})); |
231 | |
232 | result = con.Query("SELECT g, UNNEST(LIST(e)) ue, UNNEST(LIST(e+1)) ue2 from list_data GROUP BY g ORDER BY ue" ); |
233 | REQUIRE(CHECK_COLUMN(result, 0, {5, 1, 1, 2, 2, 2, 3})); |
234 | REQUIRE(CHECK_COLUMN(result, 1, {Value(), 1, 2, 3, 4, 5, 6})); |
235 | REQUIRE(CHECK_COLUMN(result, 2, {Value(), 2, 3, 4, 5, 6, 7})); |
236 | |
237 | result = con.Query("SELECT g, UNNEST(l) u FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1 ORDER BY u" ); |
238 | REQUIRE(CHECK_COLUMN(result, 0, {5, 1, 1, 2, 2, 2, 3})); |
239 | REQUIRE(CHECK_COLUMN(result, 1, {Value(), 1, 2, 3, 4, 5, 6})); |
240 | |
241 | result = con.Query("SELECT g, UNNEST(l)+1 u FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1 ORDER BY u" ); |
242 | REQUIRE(CHECK_COLUMN(result, 0, {5, 1, 1, 2, 2, 2, 3})); |
243 | REQUIRE(CHECK_COLUMN(result, 1, {Value(), 2, 3, 4, 5, 6, 7})); |
244 | |
245 | // omg omg, list of structs, structs of lists |
246 | |
247 | result = |
248 | con.Query("SELECT g, STRUCT_PACK(a := g, b := le) sl FROM (SELECT g, LIST(e) le from list_data GROUP BY g) " |
249 | "xx WHERE g < 3 ORDER BY g" ); |
250 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2})); |
251 | REQUIRE(CHECK_COLUMN( |
252 | result, 1, |
253 | {Value::STRUCT( |
254 | {make_pair("a" , Value::INTEGER(1)), make_pair("b" , Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}))}), |
255 | Value::STRUCT({make_pair("a" , Value::INTEGER(2)), |
256 | make_pair("b" , Value::LIST({Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5)}))})})); |
257 | |
258 | result = con.Query("SELECT LIST(STRUCT_PACK(a := g, b := le)) mind_blown FROM (SELECT g, LIST(e) le from list_data " |
259 | " GROUP BY g ORDER BY g) xx" ); |
260 | |
261 | REQUIRE(CHECK_COLUMN( |
262 | result, 0, |
263 | {Value::LIST( |
264 | {Value::STRUCT({make_pair("a" , Value::INTEGER(1)), |
265 | make_pair("b" , Value::LIST({Value::INTEGER(1), Value::INTEGER(2)}))}), |
266 | Value::STRUCT({make_pair("a" , Value::INTEGER(2)), |
267 | make_pair("b" , Value::LIST({Value::INTEGER(3), Value::INTEGER(4), Value::INTEGER(5)}))}), |
268 | Value::STRUCT({make_pair("a" , Value::INTEGER(3)), make_pair("b" , Value::LIST({Value::INTEGER(6)}))}), |
269 | Value::STRUCT({make_pair("a" , Value::INTEGER(5)), make_pair("b" , Value::LIST({Value()}))})})})); |
270 | |
271 | result = con.Query("SELECT g, LIST(STRUCT_PACK(a := e, b := e+1)) ls from list_data GROUP BY g ORDER BY g" ); |
272 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 3, 5})); |
273 | // TODO check second col |
274 | |
275 | result = |
276 | con.Query("SELECT g, LIST(STRUCT_PACK(a := e, b := e+1)) ls from list_data WHERE g > 2GROUP BY g ORDER BY g" ); |
277 | REQUIRE(CHECK_COLUMN(result, 0, {3, 5})); |
278 | REQUIRE(CHECK_COLUMN( |
279 | result, 1, |
280 | {Value::LIST({Value::STRUCT({make_pair("a" , Value::INTEGER(6)), make_pair("b" , Value::INTEGER(7))})}), |
281 | Value::LIST({Value::STRUCT({make_pair("a" , Value()), make_pair("b" , Value())})})})); |
282 | |
283 | // list of list of int |
284 | result = con.Query( |
285 | "SELECT g2, LIST(le) FROM (SELECT g % 2 g2, LIST(e) le from list_data GROUP BY g ORDER BY g) sq GROUP " |
286 | "BY g2 ORDER BY g2" ); |
287 | REQUIRE(CHECK_COLUMN(result, 0, {0, 1})); |
288 | |
289 | REQUIRE(CHECK_COLUMN(result, 1, |
290 | {Value::LIST({Value::LIST({3, 4, 5})}), |
291 | Value::LIST({Value::LIST({1, 2}), Value::LIST({6}), Value::LIST({Value()})})})); |
292 | |
293 | result = con.Query("SELECT SUM(ue) FROM (SELECT UNNEST(le) ue FROM (SELECT g, LIST(e) le from list_data " |
294 | " GROUP BY g ORDER BY g) xx) xy" ); |
295 | REQUIRE(CHECK_COLUMN(result, 0, {21})); |
296 | // this is technically equivalent but is not supported |
297 | REQUIRE_FAIL(con.Query("SELECT SUM(UNNEST(le)) FROM ( SELECT g, LIST(e) le from list_data " |
298 | " GROUP BY g ORDER BY g) xx" )); |
299 | |
300 | // you're holding it wrong |
301 | REQUIRE_FAIL(con.Query("SELECT LIST(LIST(42))" )); |
302 | REQUIRE_FAIL(con.Query("SELECT UNNEST(UNNEST(LIST(42))" )); |
303 | |
304 | REQUIRE_FAIL(con.Query("SELECT LIST()" )); |
305 | REQUIRE_FAIL(con.Query("SELECT LIST() FROM list_data" )); |
306 | REQUIRE_FAIL(con.Query("SELECT LIST(e, g) FROM list_data" )); |
307 | |
308 | REQUIRE_FAIL(con.Query("SELECT g, UNNEST(l+1) u FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1" )); |
309 | REQUIRE_FAIL(con.Query("SELECT g, UNNEST(g) u FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1" )); |
310 | REQUIRE_FAIL(con.Query("SELECT g, UNNEST() u FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1" )); |
311 | |
312 | REQUIRE_FAIL(con.Query("SELECT UNNEST(42)" )); |
313 | REQUIRE_FAIL(con.Query("SELECT UNNEST()" )); |
314 | REQUIRE_FAIL(con.Query("SELECT UNNEST(42) from list_data" )); |
315 | REQUIRE_FAIL(con.Query("SELECT UNNEST() from list_data" )); |
316 | REQUIRE_FAIL(con.Query("SELECT g FROM (SELECT g, LIST(e) l FROM list_data GROUP BY g) u1 where UNNEST(l) > 42" )); |
317 | } |
318 | |
319 | TEST_CASE("Test packing and unpacking lineitem into lists" , "[nested][.]" ) { |
320 | DuckDB db(nullptr); |
321 | Connection con(db); |
322 | unique_ptr<MaterializedQueryResult> result; |
323 | con.EnableQueryVerification(); // FIXME something odd happening here |
324 | auto sf = 0.01; |
325 | // TODO this has a small limit in it right now because of performance issues. Fix this. |
326 | tpch::dbgen(sf, db, DEFAULT_SCHEMA, "_org" ); |
327 | |
328 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE lineitem_small AS SELECT * FROM lineitem_org LIMIT 1050;" )); |
329 | |
330 | REQUIRE_NO_FAIL(con.Query("CREATE OR REPLACE VIEW lineitem AS SELECT * FROM lineitem_small" )); |
331 | // run the regular Q1 on the small lineitem set |
332 | result = con.Query(tpch::get_query(1)); |
333 | // construct the expected values from the regular query |
334 | vector<vector<Value>> expected_values; |
335 | for (idx_t col_idx = 0; col_idx < result->sql_types.size(); col_idx++) { |
336 | vector<Value> column_list; |
337 | for (idx_t row_idx = 0; row_idx < result->collection.count; row_idx++) { |
338 | column_list.push_back(result->GetValue(col_idx, row_idx)); |
339 | } |
340 | expected_values.push_back(column_list); |
341 | } |
342 | |
343 | REQUIRE_NO_FAIL(con.Query( |
344 | "CREATE OR REPLACE VIEW lineitem AS SELECT l_orderkey, STRUCT_EXTRACT(struct, 'l_partkey') l_partkey, " |
345 | "STRUCT_EXTRACT(struct, 'l_suppkey') l_suppkey, STRUCT_EXTRACT(struct, 'l_linenumber') l_linenumber, " |
346 | "STRUCT_EXTRACT(struct, 'l_quantity') l_quantity, STRUCT_EXTRACT(struct, 'l_extendedprice') l_extendedprice, " |
347 | "STRUCT_EXTRACT(struct, 'l_discount') l_discount, STRUCT_EXTRACT(struct, 'l_tax') l_tax, " |
348 | "STRUCT_EXTRACT(struct, 'l_returnflag') l_returnflag, STRUCT_EXTRACT(struct, 'l_linestatus') l_linestatus, " |
349 | "STRUCT_EXTRACT(struct, 'l_shipdate') l_shipdate, STRUCT_EXTRACT(struct, 'l_commitdate') l_commitdate, " |
350 | "STRUCT_EXTRACT(struct, 'l_receiptdate') l_receiptdate, STRUCT_EXTRACT(struct, 'l_shipinstruct') " |
351 | "l_shipinstruct, STRUCT_EXTRACT(struct, 'l_shipmode') l_shipmode, STRUCT_EXTRACT(struct, 'l_comment') " |
352 | "l_comment FROM (SELECT l_orderkey, UNLIST(rest) struct FROM (SELECT l_orderkey, LIST(STRUCT_PACK(l_partkey " |
353 | ",l_suppkey ,l_linenumber ,l_quantity ,l_extendedprice ,l_discount ,l_tax ,l_returnflag ,l_linestatus " |
354 | ",l_shipdate ,l_commitdate ,l_receiptdate ,l_shipinstruct ,l_shipmode ,l_comment)) rest FROM (SELECT * FROM " |
355 | "lineitem_small ) lss GROUP BY l_orderkey) s1) s2;" )); |
356 | result = con.Query(tpch::get_query(1)); |
357 | for (idx_t col_idx = 0; col_idx < expected_values.size(); col_idx++) { |
358 | REQUIRE(CHECK_COLUMN(result, col_idx, expected_values[col_idx])); |
359 | } |
360 | |
361 | // database as-a-value |
362 | REQUIRE_NO_FAIL(con.Query( |
363 | "CREATE OR REPLACE VIEW lineitem AS SELECT STRUCT_EXTRACT(ls, 'l_orderkey') l_orderkey, STRUCT_EXTRACT(ls, " |
364 | "'l_partkey') l_partkey, STRUCT_EXTRACT(ls, 'l_suppkey') l_suppkey, STRUCT_EXTRACT(ls, 'l_linenumber') " |
365 | "l_linenumber, STRUCT_EXTRACT(ls, 'l_quantity') l_quantity, STRUCT_EXTRACT(ls, 'l_extendedprice') " |
366 | "l_extendedprice, STRUCT_EXTRACT(ls, 'l_discount') l_discount, STRUCT_EXTRACT(ls, 'l_tax') l_tax, " |
367 | "STRUCT_EXTRACT(ls, 'l_returnflag') l_returnflag, STRUCT_EXTRACT(ls, 'l_linestatus') l_linestatus, " |
368 | "STRUCT_EXTRACT(ls, 'l_shipdate') l_shipdate, STRUCT_EXTRACT(ls, 'l_commitdate') l_commitdate, " |
369 | "STRUCT_EXTRACT(ls, 'l_receiptdate') l_receiptdate, STRUCT_EXTRACT(ls, 'l_shipinstruct') l_shipinstruct, " |
370 | "STRUCT_EXTRACT(ls, 'l_shipmode') l_shipmode, STRUCT_EXTRACT(ls, 'l_comment') l_comment FROM (SELECT " |
371 | "UNNEST(lineitem) ls FROM (SELECT LIST(STRUCT_PACK(l_orderkey, l_partkey ,l_suppkey ,l_linenumber ,l_quantity " |
372 | ",l_extendedprice ,l_discount ,l_tax ,l_returnflag ,l_linestatus ,l_shipdate ,l_commitdate ,l_receiptdate " |
373 | ",l_shipinstruct ,l_shipmode ,l_comment)) lineitem FROM (SELECT * FROM lineitem_small) s1) s2) s3;" )); |
374 | result = con.Query(tpch::get_query(1)); |
375 | for (idx_t col_idx = 0; col_idx < expected_values.size(); col_idx++) { |
376 | REQUIRE(CHECK_COLUMN(result, col_idx, expected_values[col_idx])); |
377 | } |
378 | |
379 | REQUIRE_NO_FAIL(con.Query( |
380 | "CREATE OR REPLACE VIEW lineitem AS SELECT UNNEST(STRUCT_EXTRACT(lineitem, 'll_orderkey')) l_orderkey, " |
381 | "UNNEST(STRUCT_EXTRACT(lineitem, 'll_partkey')) l_partkey, UNNEST(STRUCT_EXTRACT(lineitem, 'll_suppkey')) " |
382 | "l_suppkey, UNNEST(STRUCT_EXTRACT(lineitem, 'll_linenumber')) l_linenumber, UNNEST(STRUCT_EXTRACT(lineitem, " |
383 | "'ll_quantity')) l_quantity, UNNEST(STRUCT_EXTRACT(lineitem, 'll_extendedprice')) l_extendedprice, " |
384 | "UNNEST(STRUCT_EXTRACT(lineitem, 'll_discount')) l_discount, UNNEST(STRUCT_EXTRACT(lineitem, 'll_tax')) l_tax, " |
385 | "UNNEST(STRUCT_EXTRACT(lineitem, 'll_returnflag')) l_returnflag, UNNEST(STRUCT_EXTRACT(lineitem, " |
386 | "'ll_linestatus')) l_linestatus, UNNEST(STRUCT_EXTRACT(lineitem, 'll_shipdate')) l_shipdate, " |
387 | "UNNEST(STRUCT_EXTRACT(lineitem, 'll_commitdate')) l_commitdate, UNNEST(STRUCT_EXTRACT(lineitem, " |
388 | "'ll_receiptdate')) l_receiptdate, UNNEST(STRUCT_EXTRACT(lineitem, 'll_shipinstruct')) l_shipinstruct, " |
389 | "UNNEST(STRUCT_EXTRACT(lineitem, 'll_shipmode')) l_shipmode, UNNEST(STRUCT_EXTRACT(lineitem, 'll_comment')) " |
390 | "l_comment FROM (SELECT STRUCT_PACK(ll_orderkey:= LIST(l_orderkey), ll_partkey := LIST(l_partkey ), ll_suppkey " |
391 | ":= LIST(l_suppkey ), ll_linenumber := LIST(l_linenumber ), ll_quantity := LIST(l_quantity ), ll_extendedprice " |
392 | ":= LIST(l_extendedprice ), ll_discount := LIST(l_discount ), ll_tax := LIST(l_tax ), ll_returnflag := " |
393 | "LIST(l_returnflag ), ll_linestatus := LIST(l_linestatus ), ll_shipdate := LIST(l_shipdate ), ll_commitdate := " |
394 | "LIST(l_commitdate ), ll_receiptdate := LIST(l_receiptdate ), ll_shipinstruct := LIST(l_shipinstruct ), " |
395 | "ll_shipmode := LIST(l_shipmode ), ll_comment:= LIST(l_comment)) lineitem FROM (SELECT * FROM lineitem_small) " |
396 | "s1) s2;" )); |
397 | result = con.Query(tpch::get_query(1)); |
398 | for (idx_t col_idx = 0; col_idx < expected_values.size(); col_idx++) { |
399 | REQUIRE(CHECK_COLUMN(result, col_idx, expected_values[col_idx])); |
400 | } |
401 | } |
402 | |
403 | // TEST_CASE("Aggregate lists", "[nested]") { |
404 | // DuckDB db(nullptr); |
405 | // Connection con(db); |
406 | // con.EnableQueryVerification(); |
407 | // unique_ptr<QueryResult> result; |
408 | // |
409 | // result = con.Query("SELECT SUM(a), b FROM (VALUES (42, LIST_VALUE(1, 2)), (42, LIST_VALUE(3, 4, 5)), (24, |
410 | // LIST_VALUE(1, 2))) lv(a, b) GROUP BY b"); result->Print(); |
411 | //} |
412 | |