From 8002ebe98ce680b36b45afa4d15afd3784a2a2fc Mon Sep 17 00:00:00 2001 From: Lukas Eder Date: Sat, 7 Jan 2012 16:23:10 +0000 Subject: [PATCH] [#1021] Add explicit integration tests for LEFT|RIGHT|FULL OUTER JOIN --- .../src/org/jooq/test/jOOQAbstractTest.java | 102 ++++++++++++++++++ .../main/java/org/jooq/SelectJoinStep.java | 55 +++++++--- 2 files changed, 142 insertions(+), 15 deletions(-) diff --git a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java index 8a89255fce..47c3c46196 100644 --- a/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java +++ b/jOOQ-test/src/org/jooq/test/jOOQAbstractTest.java @@ -5880,6 +5880,108 @@ public abstract class jOOQAbstractTest< assertNull(result.getValue(3, TAuthor_LAST_NAME())); } + @Test + public void testOuterJoin() throws Exception { + // Test LEFT OUTER JOIN + // -------------------- + Result result1 = + create().select( + TAuthor_ID(), + TBook_ID(), + TBookToBookStore_BOOK_STORE_NAME()) + .from(TAuthor()) + .leftOuterJoin(TBook()).on(TAuthor_ID().equal(TBook_AUTHOR_ID())) + .leftOuterJoin(TBookToBookStore()).on(TBook_ID().equal(TBookToBookStore_BOOK_ID())) + .orderBy( + TAuthor_ID().asc(), + TBook_ID().asc(), + TBookToBookStore_BOOK_STORE_NAME().asc().nullsLast()) + .fetch(); + + assertEquals( + asList(1, 1, 1, 2, 2, 2, 2), + result1.getValues(0, Integer.class)); + assertEquals( + asList(1, 1, 2, 3, 3, 3, 4), + result1.getValues(1, Integer.class)); + assertEquals( + asList("Ex Libris", "Orell Füssli", "Orell Füssli", "Buchhandlung im Volkshaus", "Ex Libris", "Orell Füssli", null), + result1.getValues(2)); + + // Test RIGHT OUTER JOIN + // --------------------- + + switch (getDialect()) { + case SQLITE: + log.info("SKIPPING", "RIGHT OUTER JOIN tests"); + break; + + default: { + Result result2 = + create().select( + TAuthor_ID(), + TBook_ID(), + TBookToBookStore_BOOK_STORE_NAME()) + .from(TBookToBookStore()) + .rightOuterJoin(TBook()).on(TBook_ID().equal(TBookToBookStore_BOOK_ID())) + .rightOuterJoin(TAuthor()).on(TAuthor_ID().equal(TBook_AUTHOR_ID())) + .orderBy( + TAuthor_ID().asc(), + TBook_ID().asc(), + TBookToBookStore_BOOK_STORE_NAME().asc().nullsLast()) + .fetch(); + + assertEquals(result1, result2); + assertEquals( + asList(1, 1, 1, 2, 2, 2, 2), + result2.getValues(0, Integer.class)); + assertEquals( + asList(1, 1, 2, 3, 3, 3, 4), + result2.getValues(1, Integer.class)); + assertEquals( + asList("Ex Libris", "Orell Füssli", "Orell Füssli", "Buchhandlung im Volkshaus", "Ex Libris", "Orell Füssli", null), + result2.getValues(2)); + + break; + } + } + + // Test FULL OUTER JOIN + // -------------------- + + switch (getDialect()) { + case ASE: + case DERBY: + case H2: + case MYSQL: + case SQLITE: + log.info("SKIPPING", "FULL OUTER JOIN tests"); + break; + + default: { + Select z = create().select(zero().as("z")); + Select o = create().select(one().as("o")); + + Result result3 = + create().select() + .from(z) + .fullOuterJoin(o).on(z.getField("z").cast(Integer.class).equal(o.getField("o").cast(Integer.class))) + .fetch(); + + assertEquals("z", result3.getField(0).getName()); + assertEquals("o", result3.getField(1).getName()); + + // Interestingly, ordering doesn't work with Oracle, in this + // example... Seems to be an Oracle bug?? + @SuppressWarnings("unchecked") + List> list = asList(asList(0, null), asList(null, 1)); + assertTrue(list.contains(asList(result3.get(0).into(Integer[].class)))); + assertTrue(list.contains(asList(result3.get(1).into(Integer[].class)))); + break; + } + } + } + @Test public void testAliasing() throws Exception { Table b = TBook().as("b"); diff --git a/jOOQ/src/main/java/org/jooq/SelectJoinStep.java b/jOOQ/src/main/java/org/jooq/SelectJoinStep.java index 15a7a4de70..dda710db9a 100644 --- a/jOOQ/src/main/java/org/jooq/SelectJoinStep.java +++ b/jOOQ/src/main/java/org/jooq/SelectJoinStep.java @@ -35,13 +35,17 @@ */ package org.jooq; +import static org.jooq.SQLDialect.ASE; +import static org.jooq.SQLDialect.DB2; import static org.jooq.SQLDialect.DERBY; import static org.jooq.SQLDialect.H2; import static org.jooq.SQLDialect.HSQLDB; +import static org.jooq.SQLDialect.INGRES; import static org.jooq.SQLDialect.MYSQL; import static org.jooq.SQLDialect.ORACLE; import static org.jooq.SQLDialect.POSTGRES; import static org.jooq.SQLDialect.SQLITE; +import static org.jooq.SQLDialect.SQLSERVER; import static org.jooq.SQLDialect.SYBASE; import org.jooq.impl.Factory; @@ -124,6 +128,13 @@ public interface SelectJoinStep extends SelectWhereStep { /** * CROSS JOIN a table + *

+ * If this syntax is unavailable, it is simulated with a regular + * INNER JOIN. The following two constructs are equivalent: + *

+     * A cross join B
+     * A join B on 1 = 1
+     * 
*/ @Support SelectJoinStep crossJoin(TableLike table); @@ -131,6 +142,13 @@ public interface SelectJoinStep extends SelectWhereStep { /** * CROSS JOIN a table *

+ * If this syntax is unavailable, it is simulated with a regular + * INNER JOIN. The following two constructs are equivalent: + *

+     * A cross join B
+     * A join B on 1 = 1
+     * 
+ *

* NOTE: When inserting plain SQL into jOOQ objects, you must * guarantee syntax integrity. You may also create the possibility of * malicious SQL injection. Be sure to properly use bind variables and/or @@ -144,6 +162,13 @@ public interface SelectJoinStep extends SelectWhereStep { /** * CROSS JOIN a table *

+ * If this syntax is unavailable, it is simulated with a regular + * INNER JOIN. The following two constructs are equivalent: + *

+     * A cross join B
+     * A join B on 1 = 1
+     * 
+ *

* NOTE: When inserting plain SQL into jOOQ objects, you must * guarantee syntax integrity. You may also create the possibility of * malicious SQL injection. Be sure to properly use bind variables and/or @@ -191,7 +216,7 @@ public interface SelectJoinStep extends SelectWhereStep { *

* This is only possible where the underlying RDBMS supports it */ - @Support + @Support({ ASE, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep rightOuterJoin(TableLike table); /** @@ -206,7 +231,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String) */ - @Support + @Support({ ASE, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep rightOuterJoin(String sql); /** @@ -221,7 +246,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String, Object...) */ - @Support + @Support({ ASE, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep rightOuterJoin(String sql, Object... bindings); /** @@ -229,7 +254,7 @@ public interface SelectJoinStep extends SelectWhereStep { *

* This is only possible where the underlying RDBMS supports it */ - @Support + @Support({ DB2, HSQLDB, INGRES, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep fullOuterJoin(TableLike table); /** @@ -244,7 +269,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String) */ - @Support + @Support({ DB2, HSQLDB, INGRES, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep fullOuterJoin(String sql); /** @@ -259,7 +284,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String, Object...) */ - @Support + @Support({ DB2, HSQLDB, INGRES, ORACLE, POSTGRES, SQLSERVER, SYBASE }) SelectOnStep fullOuterJoin(String sql, Object... bindings); /** @@ -268,7 +293,7 @@ public interface SelectJoinStep extends SelectWhereStep { * Natural joins are supported by most RDBMS. If they aren't supported, they * are simulated if jOOQ has enough information. */ - @Support({DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalJoin(TableLike table); /** @@ -284,7 +309,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String) */ - @Support({DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalJoin(String sql); /** @@ -300,7 +325,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String, Object...) */ - @Support({DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, H2, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalJoin(String sql, Object... bindings); /** @@ -309,7 +334,7 @@ public interface SelectJoinStep extends SelectWhereStep { * Natural joins are supported by most RDBMS. If they aren't supported, they * are simulated if jOOQ has enough information. */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalLeftOuterJoin(TableLike table); /** @@ -325,7 +350,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String) */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalLeftOuterJoin(String sql); /** @@ -341,7 +366,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String, Object...) */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalLeftOuterJoin(String sql, Object... bindings); /** @@ -351,7 +376,7 @@ public interface SelectJoinStep extends SelectWhereStep { * Natural joins are supported by most RDBMS. If they aren't supported, they * are simulated if jOOQ has enough information. */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalRightOuterJoin(TableLike table); /** @@ -368,7 +393,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String) */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalRightOuterJoin(String sql); /** @@ -385,7 +410,7 @@ public interface SelectJoinStep extends SelectWhereStep { * * @see Factory#condition(String, Object...) */ - @Support({DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE}) + @Support({ DERBY, HSQLDB, MYSQL, ORACLE, POSTGRES, SQLITE, SYBASE }) SelectJoinStep naturalRightOuterJoin(String sql, Object... bindings); }