| 1 | #include "catch.hpp" |
| 2 | #include "test_helpers.hpp" |
| 3 | |
| 4 | using namespace duckdb; |
| 5 | using namespace std; |
| 6 | |
| 7 | TEST_CASE("Test basic joins of tables" , "[joins]" ) { |
| 8 | DuckDB db(nullptr); |
| 9 | Connection con(db); |
| 10 | unique_ptr<QueryResult> result; |
| 11 | con.EnableQueryVerification(); |
| 12 | |
| 13 | // create tables |
| 14 | con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" ); |
| 15 | con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" ); |
| 16 | |
| 17 | con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" ); |
| 18 | con.Query("INSERT INTO test2 VALUES (1, 10), (1, 20), (2, 30)" ); |
| 19 | |
| 20 | SECTION("simple cross product + join condition" ) { |
| 21 | result = con.Query("SELECT a, test.b, c FROM test, test2 WHERE test.b " |
| 22 | "= test2.b ORDER BY c;" ); |
| 23 | REQUIRE(CHECK_COLUMN(result, 0, {11, 11, 12})); |
| 24 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 2})); |
| 25 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 26 | } |
| 27 | SECTION("ambiguous reference to column" ) { |
| 28 | REQUIRE_FAIL(con.Query("SELECT b FROM test, test2 WHERE test.b > test2.b;" )); |
| 29 | } |
| 30 | SECTION("simple cross product + multiple join conditions" ) { |
| 31 | result = con.Query("SELECT a, test.b, c FROM test, test2 WHERE test.b=test2.b AND test.a-1=test2.c" ); |
| 32 | REQUIRE(CHECK_COLUMN(result, 0, {11})); |
| 33 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 34 | REQUIRE(CHECK_COLUMN(result, 2, {10})); |
| 35 | } |
| 36 | SECTION("use join columns in subquery" ) { |
| 37 | result = con.Query("SELECT a, (SELECT test.a), c FROM test, test2 WHERE " |
| 38 | "test.b = test2.b ORDER BY c;" ); |
| 39 | REQUIRE(CHECK_COLUMN(result, 0, {11, 11, 12})); |
| 40 | REQUIRE(CHECK_COLUMN(result, 1, {11, 11, 12})); |
| 41 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 42 | } |
| 43 | SECTION("explicit join" ) { |
| 44 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON " |
| 45 | "test.b = test2.b ORDER BY c;" ); |
| 46 | REQUIRE(CHECK_COLUMN(result, 0, {11, 11, 12})); |
| 47 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 2})); |
| 48 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 49 | } |
| 50 | SECTION("explicit join with condition the wrong way around" ) { |
| 51 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON " |
| 52 | "test2.b = test.b ORDER BY c;" ); |
| 53 | REQUIRE(CHECK_COLUMN(result, 0, {11, 11, 12})); |
| 54 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 2})); |
| 55 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 56 | } |
| 57 | SECTION("explicit join with additional condition that is no left-right " |
| 58 | "comparision" ) { |
| 59 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON " |
| 60 | "test2.b = test.b and test.b = 2;" ); |
| 61 | REQUIRE(CHECK_COLUMN(result, 0, {12})); |
| 62 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 63 | REQUIRE(CHECK_COLUMN(result, 2, {30})); |
| 64 | } |
| 65 | |
| 66 | SECTION("explicit join with additional condition that is constant" ) { |
| 67 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON " |
| 68 | "test2.b = test.b and 2 = 2 ORDER BY c;" ); |
| 69 | REQUIRE(CHECK_COLUMN(result, 0, {11, 11, 12})); |
| 70 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 2})); |
| 71 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 72 | } |
| 73 | |
| 74 | SECTION("explicit join with only condition that is no left-right comparision" ) { |
| 75 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON " |
| 76 | "test.b = 2 ORDER BY c;" ); |
| 77 | REQUIRE(CHECK_COLUMN(result, 0, {12, 12, 12})); |
| 78 | REQUIRE(CHECK_COLUMN(result, 1, {2, 2, 2})); |
| 79 | REQUIRE(CHECK_COLUMN(result, 2, {10, 20, 30})); |
| 80 | } |
| 81 | SECTION("explicit join with only condition that is constant" ) { |
| 82 | result = con.Query("SELECT a, test.b, c FROM test INNER JOIN test2 ON NULL = 2;" ); |
| 83 | REQUIRE(CHECK_COLUMN(result, 0, {})); |
| 84 | REQUIRE(CHECK_COLUMN(result, 1, {})); |
| 85 | REQUIRE(CHECK_COLUMN(result, 2, {})); |
| 86 | } |
| 87 | |
| 88 | SECTION("equality join where both lhs and rhs keys are projected" ) { |
| 89 | result = con.Query("SELECT * FROM (VALUES (1)) tbl(i) JOIN (VALUES (1)) tbl2(j) ON (i=j);" ); |
| 90 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 91 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 92 | } |
| 93 | SECTION("equality join where both lhs and rhs keys are projected with filter" ) { |
| 94 | result = |
| 95 | con.Query("SELECT * FROM (VALUES (1), (2)) tbl(i) JOIN (VALUES (1), (2)) tbl2(j) ON (i=j) WHERE i+j=2;" ); |
| 96 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 97 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | TEST_CASE("Test join with > STANDARD_VECTOR_SIZE duplicates" , "[joins][.]" ) { |
| 102 | DuckDB db(nullptr); |
| 103 | Connection con(db); |
| 104 | unique_ptr<QueryResult> result; |
| 105 | con.EnableQueryVerification(); |
| 106 | |
| 107 | size_t element_count = STANDARD_VECTOR_SIZE * 10; |
| 108 | REQUIRE_NO_FAIL(con.Query("BEGIN TRANSACTION" )); |
| 109 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 110 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" )); |
| 111 | |
| 112 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" )); |
| 113 | for (size_t i = 0; i < element_count; i++) { |
| 114 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, 10)" )); |
| 115 | } |
| 116 | REQUIRE_NO_FAIL(con.Query("COMMIT" )); |
| 117 | |
| 118 | result = con.Query("SELECT COUNT(*) FROM test2;" ); |
| 119 | REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(element_count)})); |
| 120 | |
| 121 | result = con.Query("SELECT COUNT(*) FROM test INNER JOIN test2 ON test.b=test2.b" ); |
| 122 | REQUIRE(CHECK_COLUMN(result, 0, {Value::BIGINT(element_count)})); |
| 123 | } |
| 124 | |
| 125 | TEST_CASE("Equality + inequality joins" , "[joins]" ) { |
| 126 | DuckDB db(nullptr); |
| 127 | Connection con(db); |
| 128 | unique_ptr<QueryResult> result; |
| 129 | con.EnableQueryVerification(); |
| 130 | |
| 131 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 132 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" )); |
| 133 | |
| 134 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (a INTEGER, c INTEGER);" )); |
| 135 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (11, 1), (12, 1), (13, 4)" )); |
| 136 | |
| 137 | result = con.Query("SELECT test.a, b, c FROM test, test2 WHERE test.a = " |
| 138 | "test2.a AND test.b <> test2.c ORDER BY test.a;" ); |
| 139 | REQUIRE(CHECK_COLUMN(result, 0, {12, 13})); |
| 140 | REQUIRE(CHECK_COLUMN(result, 1, {2, 3})); |
| 141 | REQUIRE(CHECK_COLUMN(result, 2, {1, 4})); |
| 142 | |
| 143 | result = con.Query("SELECT test.a, b, c FROM test, test2 WHERE test.a = " |
| 144 | "test2.a AND test.b < test2.c ORDER BY test.a;" ); |
| 145 | REQUIRE(CHECK_COLUMN(result, 0, {13})); |
| 146 | REQUIRE(CHECK_COLUMN(result, 1, {3})); |
| 147 | REQUIRE(CHECK_COLUMN(result, 2, {4})); |
| 148 | |
| 149 | result = con.Query("SELECT test.a, b, c FROM test, test2 WHERE test.a = " |
| 150 | "test2.a AND test.b <= test2.c ORDER BY test.a;" ); |
| 151 | REQUIRE(CHECK_COLUMN(result, 0, {11, 13})); |
| 152 | REQUIRE(CHECK_COLUMN(result, 1, {1, 3})); |
| 153 | REQUIRE(CHECK_COLUMN(result, 2, {1, 4})); |
| 154 | |
| 155 | result = con.Query("SELECT test.a, b, c FROM test, test2 WHERE test.a = " |
| 156 | "test2.a AND test.b > test2.c ORDER BY test.a;" ); |
| 157 | REQUIRE(CHECK_COLUMN(result, 0, {12})); |
| 158 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 159 | REQUIRE(CHECK_COLUMN(result, 2, {1})); |
| 160 | |
| 161 | result = con.Query("SELECT test.a, b, c FROM test, test2 WHERE test.a = " |
| 162 | "test2.a AND test.b >= test2.c ORDER BY test.a;" ); |
| 163 | REQUIRE(CHECK_COLUMN(result, 0, {11, 12})); |
| 164 | REQUIRE(CHECK_COLUMN(result, 1, {1, 2})); |
| 165 | REQUIRE(CHECK_COLUMN(result, 2, {1, 1})); |
| 166 | } |
| 167 | |
| 168 | TEST_CASE("Equality + inequality anti and semi joins" , "[joins]" ) { |
| 169 | DuckDB db(nullptr); |
| 170 | Connection con(db); |
| 171 | unique_ptr<QueryResult> result; |
| 172 | con.EnableQueryVerification(); |
| 173 | |
| 174 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER, str VARCHAR);" )); |
| 175 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1, 'a'), (12, 2, 'b'), (13, 3, 'c')" )); |
| 176 | |
| 177 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (a INTEGER, c INTEGER, str2 VARCHAR);" )); |
| 178 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (11, 1, 'd'), (12, 1, 'e'), (13, 4, 'f')" )); |
| 179 | |
| 180 | result = con.Query("SELECT * FROM test WHERE EXISTS(SELECT * FROM test2 " |
| 181 | "WHERE test.a=test2.a AND test.b<>test2.c);" ); |
| 182 | REQUIRE(CHECK_COLUMN(result, 0, {12, 13})); |
| 183 | REQUIRE(CHECK_COLUMN(result, 1, {2, 3})); |
| 184 | REQUIRE(CHECK_COLUMN(result, 2, {"b" , "c" })); |
| 185 | |
| 186 | result = con.Query("SELECT * FROM test WHERE EXISTS(SELECT * FROM test2 WHERE " |
| 187 | "test.a=test2.a AND test.b<>test2.c) AND NOT EXISTS(SELECT * " |
| 188 | "FROM test2 WHERE test.a=test2.a AND test.b<test2.c);" ); |
| 189 | REQUIRE(CHECK_COLUMN(result, 0, {12})); |
| 190 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 191 | REQUIRE(CHECK_COLUMN(result, 2, {"b" })); |
| 192 | |
| 193 | result = con.Query("SELECT * FROM test WHERE NOT EXISTS(SELECT * FROM " |
| 194 | "test2 WHERE test.a=test2.a AND test.b<test2.c);" ); |
| 195 | REQUIRE(CHECK_COLUMN(result, 0, {11, 12})); |
| 196 | REQUIRE(CHECK_COLUMN(result, 1, {1, 2})); |
| 197 | REQUIRE(CHECK_COLUMN(result, 2, {"a" , "b" })); |
| 198 | |
| 199 | result = con.Query("SELECT * FROM test WHERE NOT EXISTS(SELECT * FROM test2 WHERE " |
| 200 | "test.a=test2.a AND test.b<test2.c) AND NOT EXISTS(SELECT * FROM test2 " |
| 201 | "WHERE test.a=test2.a AND test.b>test2.c);" ); |
| 202 | REQUIRE(CHECK_COLUMN(result, 0, {11})); |
| 203 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 204 | REQUIRE(CHECK_COLUMN(result, 2, {"a" })); |
| 205 | |
| 206 | result = con.Query("SELECT * FROM test WHERE EXISTS(SELECT * FROM test2 WHERE " |
| 207 | "test.a=test2.a AND test.b<>test2.c) AND test.a > 11;" ); |
| 208 | REQUIRE(CHECK_COLUMN(result, 0, {12, 13})); |
| 209 | REQUIRE(CHECK_COLUMN(result, 1, {2, 3})); |
| 210 | REQUIRE(CHECK_COLUMN(result, 2, {"b" , "c" })); |
| 211 | } |
| 212 | |
| 213 | TEST_CASE("Equality + inequality anti and semi joins with selection vector" , "[joins]" ) { |
| 214 | DuckDB db(nullptr); |
| 215 | Connection con(db); |
| 216 | unique_ptr<QueryResult> result; |
| 217 | con.EnableQueryVerification(); |
| 218 | |
| 219 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER, str VARCHAR);" )); |
| 220 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1, 'a'), (12, 2, 'b'), (13, 3, 'c')" )); |
| 221 | |
| 222 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (a INTEGER, c INTEGER, str2 VARCHAR);" )); |
| 223 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (11, 1, 'd'), (12, 1, 'e'), (13, 4, 'f')" )); |
| 224 | |
| 225 | result = con.Query("SELECT * FROM test WHERE NOT EXISTS(SELECT * FROM " |
| 226 | "test2 WHERE test.a=test2.a AND test.b<test2.c AND " |
| 227 | "test2.a>14) AND NOT EXISTS(SELECT * FROM test2 WHERE " |
| 228 | "test.a=test2.a AND test.b>test2.c AND test2.a<10);" ); |
| 229 | REQUIRE(CHECK_COLUMN(result, 0, {11, 12, 13})); |
| 230 | REQUIRE(CHECK_COLUMN(result, 1, {1, 2, 3})); |
| 231 | REQUIRE(CHECK_COLUMN(result, 2, {"a" , "b" , "c" })); |
| 232 | |
| 233 | result = con.Query("SELECT * FROM test WHERE NOT EXISTS(SELECT * FROM " |
| 234 | "test2 WHERE test.a=test2.a AND test.b<test2.c AND " |
| 235 | "test2.a=12) AND NOT EXISTS(SELECT * FROM test2 WHERE " |
| 236 | "test.a=test2.a AND test.b>test2.c AND test2.a=12);" ); |
| 237 | REQUIRE(CHECK_COLUMN(result, 0, {11, 13})); |
| 238 | REQUIRE(CHECK_COLUMN(result, 1, {1, 3})); |
| 239 | REQUIRE(CHECK_COLUMN(result, 2, {"a" , "c" })); |
| 240 | |
| 241 | result = con.Query("SELECT * FROM test WHERE EXISTS(SELECT * FROM test2 WHERE " |
| 242 | "test.a=test2.a AND test.b<>test2.c) AND test.a < 13;" ); |
| 243 | REQUIRE(CHECK_COLUMN(result, 0, {12})); |
| 244 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 245 | REQUIRE(CHECK_COLUMN(result, 2, {"b" })); |
| 246 | } |
| 247 | |
| 248 | TEST_CASE("Test range joins" , "[joins]" ) { |
| 249 | DuckDB db(nullptr); |
| 250 | Connection con(db); |
| 251 | unique_ptr<QueryResult> result; |
| 252 | con.EnableQueryVerification(); |
| 253 | |
| 254 | // create tables |
| 255 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 256 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" )); |
| 257 | |
| 258 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" )); |
| 259 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, 10), (1, 20), (2, 30)" )); |
| 260 | |
| 261 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b<test2.b" ); |
| 262 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 263 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 264 | |
| 265 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b " |
| 266 | "<= test2.b ORDER BY 1,2" ); |
| 267 | REQUIRE(CHECK_COLUMN(result, 0, {1, 1, 1, 2})); |
| 268 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 2, 2})); |
| 269 | |
| 270 | // range join on multiple predicates |
| 271 | result = con.Query( |
| 272 | "SELECT test.a, test.b, test2.b, test2.c FROM test, test2 WHERE test.a>test2.c AND test.b <= test2.b" ); |
| 273 | REQUIRE(CHECK_COLUMN(result, 0, {11})); |
| 274 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 275 | REQUIRE(CHECK_COLUMN(result, 2, {1})); |
| 276 | REQUIRE(CHECK_COLUMN(result, 3, {10})); |
| 277 | |
| 278 | // introduce some NULL values |
| 279 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, NULL), (NULL, 1)" )); |
| 280 | // join result should be unchanged |
| 281 | result = con.Query( |
| 282 | "SELECT test.a, test.b, test2.b, test2.c FROM test, test2 WHERE test.a>test2.c AND test.b <= test2.b" ); |
| 283 | REQUIRE(CHECK_COLUMN(result, 0, {11})); |
| 284 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 285 | REQUIRE(CHECK_COLUMN(result, 2, {1})); |
| 286 | REQUIRE(CHECK_COLUMN(result, 3, {10})); |
| 287 | |
| 288 | // on the RHS as well |
| 289 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, NULL), (NULL, 10)" )); |
| 290 | // join result should be unchanged |
| 291 | result = con.Query( |
| 292 | "SELECT test.a, test.b, test2.b, test2.c FROM test, test2 WHERE test.a>test2.c AND test.b <= test2.b" ); |
| 293 | REQUIRE(CHECK_COLUMN(result, 0, {11})); |
| 294 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 295 | REQUIRE(CHECK_COLUMN(result, 2, {1})); |
| 296 | REQUIRE(CHECK_COLUMN(result, 3, {10})); |
| 297 | } |
| 298 | |
| 299 | TEST_CASE("Test inequality joins" , "[joins]" ) { |
| 300 | DuckDB db(nullptr); |
| 301 | Connection con(db); |
| 302 | unique_ptr<QueryResult> result; |
| 303 | con.EnableQueryVerification(); |
| 304 | |
| 305 | // create tables |
| 306 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 307 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" )); |
| 308 | |
| 309 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" )); |
| 310 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, 10), (1, 20), (2, 30)" )); |
| 311 | |
| 312 | // inequality join |
| 313 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b <> test2.b ORDER BY test.b, test2.b" ); |
| 314 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 2, 3, 3, 3})); |
| 315 | REQUIRE(CHECK_COLUMN(result, 1, {2, 1, 1, 1, 1, 2})); |
| 316 | // inequality join with filter |
| 317 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b <> test2.b AND test.b <> 1 AND test2.b <> " |
| 318 | "2 ORDER BY test.b, test2.b" ); |
| 319 | REQUIRE(CHECK_COLUMN(result, 0, {2, 2, 3, 3})); |
| 320 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 1, 1})); |
| 321 | |
| 322 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (NULL, NULL)" )); |
| 323 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (NULL, NULL)" )); |
| 324 | // inequality join with NULL values |
| 325 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b <> test2.b ORDER BY test.b, test2.b" ); |
| 326 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2, 2, 3, 3, 3})); |
| 327 | REQUIRE(CHECK_COLUMN(result, 1, {2, 1, 1, 1, 1, 2})); |
| 328 | |
| 329 | // inequality join with filter and NULL values |
| 330 | result = con.Query("SELECT test.b, test2.b FROM test, test2 WHERE test.b <> test2.b AND test.b <> 1 AND test2.b <> " |
| 331 | "2 ORDER BY test.b, test2.b" ); |
| 332 | REQUIRE(CHECK_COLUMN(result, 0, {2, 2, 3, 3})); |
| 333 | REQUIRE(CHECK_COLUMN(result, 1, {1, 1, 1, 1})); |
| 334 | } |
| 335 | |
| 336 | TEST_CASE("Test USING joins" , "[joins]" ) { |
| 337 | DuckDB db(nullptr); |
| 338 | Connection con(db); |
| 339 | unique_ptr<QueryResult> result; |
| 340 | con.EnableQueryVerification(); |
| 341 | |
| 342 | // create tables |
| 343 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t1 (a INTEGER, b INTEGER, c INTEGER)" )); |
| 344 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t1 VALUES (1,2,3)" )); |
| 345 | |
| 346 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t2 (a INTEGER, b INTEGER, c INTEGER)" )); |
| 347 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t2 VALUES (1,2,3), (2,2,4), (1,3,4)" )); |
| 348 | |
| 349 | // USING join |
| 350 | result = con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(a) ORDER BY t2.b" ); |
| 351 | REQUIRE(CHECK_COLUMN(result, 0, {1, 1})); |
| 352 | REQUIRE(CHECK_COLUMN(result, 1, {2, 3})); |
| 353 | REQUIRE(CHECK_COLUMN(result, 2, {3, 4})); |
| 354 | |
| 355 | result = con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(b) ORDER BY t2.c" ); |
| 356 | REQUIRE(CHECK_COLUMN(result, 0, {1, 2})); |
| 357 | REQUIRE(CHECK_COLUMN(result, 1, {2, 2})); |
| 358 | REQUIRE(CHECK_COLUMN(result, 2, {3, 4})); |
| 359 | |
| 360 | result = con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(a,b)" ); |
| 361 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 362 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 363 | REQUIRE(CHECK_COLUMN(result, 2, {3})); |
| 364 | |
| 365 | result = con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(a,b,c)" ); |
| 366 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 367 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 368 | REQUIRE(CHECK_COLUMN(result, 2, {3})); |
| 369 | |
| 370 | // USING columns can be used without requiring a table specifier |
| 371 | result = con.Query("SELECT a+1 FROM t1 JOIN t2 USING(a) ORDER BY a" ); |
| 372 | REQUIRE(CHECK_COLUMN(result, 0, {2, 2})); |
| 373 | |
| 374 | REQUIRE_FAIL(con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(a+b)" )); |
| 375 | REQUIRE_FAIL(con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(\"\")" )); |
| 376 | REQUIRE_FAIL(con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(d)" )); |
| 377 | REQUIRE_FAIL(con.Query("SELECT t2.a, t2.b, t2.c FROM t1 JOIN t2 USING(t1.a)" )); |
| 378 | |
| 379 | result = con.Query("SELECT * FROM t1 JOIN t2 USING(a,b)" ); |
| 380 | REQUIRE(result->names.size() == 4); |
| 381 | REQUIRE(result->names[0] == "a" ); |
| 382 | REQUIRE(result->names[1] == "b" ); |
| 383 | REQUIRE(result->names[2] == "c" ); |
| 384 | REQUIRE(result->names[3] == "c" ); |
| 385 | |
| 386 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 387 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 388 | REQUIRE(CHECK_COLUMN(result, 2, {3})); |
| 389 | REQUIRE(CHECK_COLUMN(result, 3, {3})); |
| 390 | |
| 391 | // CONTROVERSIAL: |
| 392 | // we do not allow this because it is ambiguous: "b" can be bind to both "t1.b" or "t2.b" and this would give |
| 393 | // different results SQLite allows this, PostgreSQL does not |
| 394 | REQUIRE_FAIL(con.Query("SELECT * FROM t1 JOIN t2 USING(a) JOIN t2 t2b USING (b);" )); |
| 395 | // a chain with the same column name is allowed though! |
| 396 | result = con.Query("SELECT * FROM t1 JOIN t2 USING(a) JOIN t2 t2b USING (a) ORDER BY 1, 2, 3, 4, 5, 6, 7" ); |
| 397 | REQUIRE(CHECK_COLUMN(result, 0, {1, 1, 1, 1})); |
| 398 | REQUIRE(CHECK_COLUMN(result, 1, {2, 2, 2, 2})); |
| 399 | REQUIRE(CHECK_COLUMN(result, 2, {3, 3, 3, 3})); |
| 400 | REQUIRE(CHECK_COLUMN(result, 3, {2, 2, 3, 3})); |
| 401 | REQUIRE(CHECK_COLUMN(result, 4, {3, 3, 4, 4})); |
| 402 | REQUIRE(CHECK_COLUMN(result, 5, {2, 3, 2, 3})); |
| 403 | REQUIRE(CHECK_COLUMN(result, 6, {3, 4, 3, 4})); |
| 404 | |
| 405 | REQUIRE(result->names.size() == 7); |
| 406 | REQUIRE(result->names[0] == "a" ); |
| 407 | REQUIRE(result->names[1] == "b" ); |
| 408 | REQUIRE(result->names[2] == "c" ); |
| 409 | REQUIRE(result->names[3] == "b" ); |
| 410 | REQUIRE(result->names[4] == "c" ); |
| 411 | REQUIRE(result->names[5] == "b" ); |
| 412 | REQUIRE(result->names[6] == "c" ); |
| 413 | } |
| 414 | |
| 415 | TEST_CASE("Test chaining USING joins" , "[joins]" ) { |
| 416 | DuckDB db(nullptr); |
| 417 | Connection con(db); |
| 418 | unique_ptr<QueryResult> result; |
| 419 | con.EnableQueryVerification(); |
| 420 | |
| 421 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t1 (a INTEGER, b INTEGER)" )); |
| 422 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t1 VALUES (1, 2)" )); |
| 423 | |
| 424 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t2 (b INTEGER, c INTEGER)" )); |
| 425 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t2 VALUES (2, 3)" )); |
| 426 | |
| 427 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t3 (c INTEGER, d INTEGER)" )); |
| 428 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t3 VALUES (3, 4)" )); |
| 429 | |
| 430 | // multiple joins with using |
| 431 | // single column |
| 432 | result = con.Query("SELECT * FROM t1 JOIN t2 USING (b) JOIN t3 USING (c) ORDER BY 1, 2, 3, 4;" ); |
| 433 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 434 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 435 | REQUIRE(CHECK_COLUMN(result, 2, {3})); |
| 436 | REQUIRE(CHECK_COLUMN(result, 3, {4})); |
| 437 | |
| 438 | REQUIRE(result->names.size() == 4); |
| 439 | REQUIRE(result->names[0] == "a" ); |
| 440 | REQUIRE(result->names[1] == "b" ); |
| 441 | REQUIRE(result->names[2] == "c" ); |
| 442 | REQUIRE(result->names[3] == "d" ); |
| 443 | |
| 444 | // column does not exist on left side of join |
| 445 | REQUIRE_FAIL(con.Query("SELECT * FROM t1 JOIN t2 USING (c)" )); |
| 446 | // column does not exist on right side of join |
| 447 | REQUIRE_FAIL(con.Query("SELECT * FROM t1 JOIN t2 USING (a)" )); |
| 448 | |
| 449 | REQUIRE_NO_FAIL(con.Query("DROP TABLE t1" )); |
| 450 | REQUIRE_NO_FAIL(con.Query("DROP TABLE t2" )); |
| 451 | REQUIRE_NO_FAIL(con.Query("DROP TABLE t3" )); |
| 452 | |
| 453 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t1 (a INTEGER, b INTEGER, c INTEGER)" )); |
| 454 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t1 VALUES (1, 2, 2)" )); |
| 455 | |
| 456 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t2 (b INTEGER, c INTEGER, d INTEGER, e INTEGER)" )); |
| 457 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t2 VALUES (2, 2, 3, 4)" )); |
| 458 | |
| 459 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE t3 (d INTEGER, e INTEGER)" )); |
| 460 | REQUIRE_NO_FAIL(con.Query("INSERT INTO t3 VALUES (3, 4)" )); |
| 461 | |
| 462 | // multi column |
| 463 | result = con.Query("SELECT * FROM t1 JOIN t2 USING (b, c) JOIN t3 USING (d, e);" ); |
| 464 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 465 | REQUIRE(CHECK_COLUMN(result, 1, {2})); |
| 466 | REQUIRE(CHECK_COLUMN(result, 2, {2})); |
| 467 | REQUIRE(CHECK_COLUMN(result, 3, {3})); |
| 468 | REQUIRE(CHECK_COLUMN(result, 4, {4})); |
| 469 | |
| 470 | REQUIRE(result->names.size() == 5); |
| 471 | REQUIRE(result->names[0] == "a" ); |
| 472 | REQUIRE(result->names[1] == "b" ); |
| 473 | REQUIRE(result->names[2] == "c" ); |
| 474 | REQUIRE(result->names[3] == "d" ); |
| 475 | REQUIRE(result->names[4] == "e" ); |
| 476 | } |
| 477 | |
| 478 | TEST_CASE("Test joins with various columns that are only used in the join" , "[joins]" ) { |
| 479 | DuckDB db(nullptr); |
| 480 | Connection con(db); |
| 481 | unique_ptr<QueryResult> result; |
| 482 | con.EnableQueryVerification(); |
| 483 | |
| 484 | // create tables |
| 485 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 486 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (11, 1), (12, 2), (13, 3)" )); |
| 487 | |
| 488 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" )); |
| 489 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, 10), (1, 20), (2, 30)" )); |
| 490 | |
| 491 | // count of single join |
| 492 | result = con.Query("SELECT COUNT(*) FROM test, test2 WHERE test.b = test2.b" ); |
| 493 | REQUIRE(CHECK_COLUMN(result, 0, {3})); |
| 494 | // now a sum |
| 495 | result = con.Query("SELECT SUM(test.a), MIN(test.a), MAX(test.a) FROM test, test2 WHERE test.b = test2.b" ); |
| 496 | REQUIRE(CHECK_COLUMN(result, 0, {34})); |
| 497 | REQUIRE(CHECK_COLUMN(result, 1, {11})); |
| 498 | REQUIRE(CHECK_COLUMN(result, 2, {12})); |
| 499 | |
| 500 | // count of multi-way join |
| 501 | result = con.Query("SELECT COUNT(*) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b" ); |
| 502 | REQUIRE(CHECK_COLUMN(result, 0, {3})); |
| 503 | // now a sum |
| 504 | result = con.Query("SELECT SUM(a1.a) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b" ); |
| 505 | REQUIRE(CHECK_COLUMN(result, 0, {36})); |
| 506 | |
| 507 | // count of multi-way join with filters |
| 508 | result = con.Query("SELECT COUNT(*) FROM test a1, test a2, test a3 WHERE a1.b=a2.b AND a2.b=a3.b AND a1.a=11 AND " |
| 509 | "a2.a=11 AND a3.a=11" ); |
| 510 | REQUIRE(CHECK_COLUMN(result, 0, {1})); |
| 511 | |
| 512 | // unused columns that become unused because of optimizer |
| 513 | result = con.Query("SELECT (TRUE OR a1.a=a2.b) FROM test a1, test a2 WHERE a1.a=11 AND a2.a>=10" ); |
| 514 | REQUIRE(CHECK_COLUMN(result, 0, {true, true, true})); |
| 515 | } |
| 516 | |
| 517 | TEST_CASE("Test joins with comparisons involving both sides of the join" , "[joins]" ) { |
| 518 | DuckDB db(nullptr); |
| 519 | Connection con(db); |
| 520 | unique_ptr<QueryResult> result; |
| 521 | con.EnableQueryVerification(); |
| 522 | |
| 523 | // create tables |
| 524 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test (a INTEGER, b INTEGER);" )); |
| 525 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test VALUES (4, 1), (2, 2)" )); |
| 526 | |
| 527 | REQUIRE_NO_FAIL(con.Query("CREATE TABLE test2 (b INTEGER, c INTEGER);" )); |
| 528 | REQUIRE_NO_FAIL(con.Query("INSERT INTO test2 VALUES (1, 2), (3, 0)" )); |
| 529 | |
| 530 | result = con.Query("SELECT * FROM test JOIN test2 ON test.a+test2.c=test.b+test2.b" ); |
| 531 | REQUIRE(CHECK_COLUMN(result, 0, {4})); |
| 532 | REQUIRE(CHECK_COLUMN(result, 1, {1})); |
| 533 | REQUIRE(CHECK_COLUMN(result, 2, {3})); |
| 534 | REQUIRE(CHECK_COLUMN(result, 3, {0})); |
| 535 | |
| 536 | result = con.Query("SELECT * FROM test LEFT JOIN test2 ON test.a+test2.c=test.b+test2.b ORDER BY 1" ); |
| 537 | REQUIRE(CHECK_COLUMN(result, 0, {2, 4})); |
| 538 | REQUIRE(CHECK_COLUMN(result, 1, {2, 1})); |
| 539 | REQUIRE(CHECK_COLUMN(result, 2, {Value(), 3})); |
| 540 | REQUIRE(CHECK_COLUMN(result, 3, {Value(), 0})); |
| 541 | |
| 542 | result = con.Query("SELECT * FROM test RIGHT JOIN test2 ON test.a+test2.c=test.b+test2.b ORDER BY 1" ); |
| 543 | REQUIRE(CHECK_COLUMN(result, 0, {Value(), 4})); |
| 544 | REQUIRE(CHECK_COLUMN(result, 1, {Value(), 1})); |
| 545 | REQUIRE(CHECK_COLUMN(result, 2, {1, 3})); |
| 546 | REQUIRE(CHECK_COLUMN(result, 3, {2, 0})); |
| 547 | } |
| 548 | |