| 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 |  | 
|---|