[#1645] Add support for Oracle's PARTITION BY clause in OUTER JOINs

This commit is contained in:
Lukas Eder 2012-08-01 13:33:09 +02:00
parent e3d0935070
commit e146168d29
11 changed files with 316 additions and 25 deletions

View File

@ -83,6 +83,7 @@ import java.math.BigInteger;
import java.sql.Date;
import java.sql.Timestamp;
import java.util.Arrays;
import java.util.Collections;
import org.jooq.ArrayRecord;
import org.jooq.DataType;
@ -1244,7 +1245,7 @@ public class jOOQOracleTest extends jOOQAbstractTest<
}
@Test
public void testKeepDenseRank() {
public void testOracleKeepDenseRank() {
assertEquals(
Arrays.asList(3, 7),
Arrays.asList(
@ -1255,4 +1256,42 @@ public class jOOQOracleTest extends jOOQAbstractTest<
.fetchOne()
.into(Integer[].class)));
}
@Test
public void testOraclePartitionedOuterJoin() {
// Maybe, find a more sensible query for the test case...?
Result<Record> result1 =
create().select(
TAuthor_FIRST_NAME(),
TBook_TITLE())
.from(TAuthor()
.leftOuterJoin(TBook())
.partitionBy(TBook_TITLE())
.on(TAuthor_ID().equal(TBook_AUTHOR_ID())))
.orderBy(
TAuthor_FIRST_NAME(),
TBook_ID())
.fetch();
assertEquals(8, result1.size());
assertEquals(BOOK_TITLES, result1.getValues(TBook_TITLE()).subList(0, 4));
assertEquals(Collections.nCopies(4, "George"), result1.getValues(TAuthor_FIRST_NAME()).subList(0, 4));
assertEquals(Collections.nCopies(4, "Paulo"), result1.getValues(TAuthor_FIRST_NAME()).subList(4, 8));
Result<Record> result2 =
create().select(
TAuthor_FIRST_NAME(),
TBook_TITLE())
.from(TAuthor())
.leftOuterJoin(TBook())
.partitionBy(TBook_TITLE())
.on(TAuthor_ID().equal(TBook_AUTHOR_ID()))
.orderBy(
TAuthor_FIRST_NAME(),
TBook_ID())
.fetch();
assertEquals(result1, result2);
}
}

View File

@ -0,0 +1,104 @@
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq;
import static org.jooq.SQLDialect.ORACLE;
import java.util.Collection;
/**
* This type is used for the {@link Select}'s DSL API when selecting generic
* {@link Record} types.
* <p>
* Example: <code><pre>
* -- get all authors' first and last names, and the number
* -- of books they've written in German, if they have written
* -- more than five books in German in the last three years
* -- (from 2011), and sort those authors by last names
* -- limiting results to the second and third row
*
* SELECT T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME, COUNT(*)
* FROM T_AUTHOR
* JOIN T_BOOK ON T_AUTHOR.ID = T_BOOK.AUTHOR_ID
* WHERE T_BOOK.LANGUAGE = 'DE'
* AND T_BOOK.PUBLISHED > '2008-01-01'
* GROUP BY T_AUTHOR.FIRST_NAME, T_AUTHOR.LAST_NAME
* HAVING COUNT(*) > 5
* ORDER BY T_AUTHOR.LAST_NAME ASC NULLS FIRST
* LIMIT 2
* OFFSET 1
* FOR UPDATE
* OF FIRST_NAME, LAST_NAME
* NO WAIT
* </pre></code> Its equivalent in jOOQ <code><pre>
* create.select(TAuthor.FIRST_NAME, TAuthor.LAST_NAME, create.count())
* .from(T_AUTHOR)
* .join(T_BOOK).on(TBook.AUTHOR_ID.equal(TAuthor.ID))
* .where(TBook.LANGUAGE.equal("DE"))
* .and(TBook.PUBLISHED.greaterThan(parseDate('2008-01-01')))
* .groupBy(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
* .having(create.count().greaterThan(5))
* .orderBy(TAuthor.LAST_NAME.asc().nullsFirst())
* .limit(2)
* .offset(1)
* .forUpdate()
* .of(TAuthor.FIRST_NAME, TAuthor.LAST_NAME)
* .noWait();
* </pre></code> Refer to the manual for more details
*
* @author Lukas Eder
*/
public interface SelectJoinPartitionByStep extends SelectOnStep {
/**
* Add a <code>PARTITION BY</code> clause to the right hand side of the
* <code>OUTER JOIN</code> keywords
*
* @see TablePartitionByStep#partitionBy(Field...)
*/
@Support(ORACLE)
SelectOnStep partitionBy(Field<?>... fields);
/**
* Add a <code>PARTITION BY</code> clause to the right hand side of the
* <code>OUTER JOIN</code> keywords
*
* @see TablePartitionByStep#partitionBy(Collection)
*/
@Support(ORACLE)
SelectOnStep partitionBy(Collection<? extends Field<?>> fields);
}

View File

@ -205,7 +205,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#leftOuterJoin(TableLike)
*/
@Support
SelectOnStep leftOuterJoin(TableLike<?> table);
SelectJoinPartitionByStep leftOuterJoin(TableLike<?> table);
/**
* Convenience method to <code>LEFT OUTER JOIN</code> a table to the last
@ -221,7 +221,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#leftOuterJoin(String)
*/
@Support
SelectOnStep leftOuterJoin(String sql);
SelectJoinPartitionByStep leftOuterJoin(String sql);
/**
* Convenience method to <code>LEFT OUTER JOIN</code> a table to the last
@ -237,7 +237,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#leftOuterJoin(String, Object...)
*/
@Support
SelectOnStep leftOuterJoin(String sql, Object... bindings);
SelectJoinPartitionByStep leftOuterJoin(String sql, Object... bindings);
/**
* Convenience method to <code>RIGHT OUTER JOIN</code> a table to the last
@ -249,7 +249,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#rightOuterJoin(TableLike)
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
SelectOnStep rightOuterJoin(TableLike<?> table);
SelectJoinPartitionByStep rightOuterJoin(TableLike<?> table);
/**
* Convenience method to <code>RIGHT OUTER JOIN</code> a table to the last
@ -267,7 +267,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#rightOuterJoin(String)
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
SelectOnStep rightOuterJoin(String sql);
SelectJoinPartitionByStep rightOuterJoin(String sql);
/**
* Convenience method to <code>RIGHT OUTER JOIN</code> a table to the last
@ -285,7 +285,7 @@ public interface SelectJoinStep extends SelectWhereStep {
* @see Table#rightOuterJoin(String, Object...)
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
SelectOnStep rightOuterJoin(String sql, Object... bindings);
SelectJoinPartitionByStep rightOuterJoin(String sql, Object... bindings);
/**
* Convenience method to <code>FULL OUTER JOIN</code> a table to the last

View File

@ -107,6 +107,21 @@ public interface SelectQuery extends Select<Record>, ConditionProvider, OrderPro
@Support
void addJoin(TableLike<?> table, JoinType type, Condition... conditions);
/**
* Joins the existing table product to a new table using a condition
* <p>
* This adds a <code>PARTITION BY</code> clause to the right hand side of a
* <code>OUTER JOIN</code> expression.
*
* @param table The joined table
* @param type The type of join
* @param conditions The joining conditions
* @param partitionBy The <code>PARTITION BY</code> expression
* @see TablePartitionByStep
*/
@Support(ORACLE)
void addJoin(TableLike<?> table, JoinType type, Condition[] conditions, Field<?>[] partitionBy);
/**
* Joins the existing table product to a new table with a <code>USING</code>
* clause

View File

@ -235,7 +235,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* <code>LEFT OUTER JOIN</code> a table to this table.
*/
@Support
TableOnStep leftOuterJoin(TableLike<?> table);
TablePartitionByStep leftOuterJoin(TableLike<?> table);
/**
* <code>LEFT OUTER JOIN</code> a table to this table.
@ -248,7 +248,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* @see Factory#table(String)
*/
@Support
TableOnStep leftOuterJoin(String sql);
TablePartitionByStep leftOuterJoin(String sql);
/**
* <code>LEFT OUTER JOIN</code> a table to this table.
@ -261,7 +261,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* @see Factory#table(String, Object...)
*/
@Support
TableOnStep leftOuterJoin(String sql, Object... bindings);
TablePartitionByStep leftOuterJoin(String sql, Object... bindings);
/**
* <code>RIGHT OUTER JOIN</code> a table to this table.
@ -269,7 +269,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* This is only possible where the underlying RDBMS supports it
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
TableOnStep rightOuterJoin(TableLike<?> table);
TablePartitionByStep rightOuterJoin(TableLike<?> table);
/**
* <code>RIGHT OUTER JOIN</code> a table to this table.
@ -284,7 +284,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* @see Factory#table(String)
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
TableOnStep rightOuterJoin(String sql);
TablePartitionByStep rightOuterJoin(String sql);
/**
* <code>RIGHT OUTER JOIN</code> a table to this table.
@ -299,7 +299,7 @@ public interface Table<R extends Record> extends org.jooq.Type<R>, AliasProvider
* @see Factory#table(String, Object...)
*/
@Support({ ASE, CUBRID, DB2, DERBY, H2, HSQLDB, INGRES, MYSQL, ORACLE, POSTGRES, SQLSERVER, SYBASE })
TableOnStep rightOuterJoin(String sql, Object... bindings);
TablePartitionByStep rightOuterJoin(String sql, Object... bindings);
/**
* <code>FULL OUTER JOIN</code> a table to this table.

View File

@ -0,0 +1,70 @@
/**
* Copyright (c) 2009-2012, Lukas Eder, lukas.eder@gmail.com
* All rights reserved.
*
* This software is licensed to you under the Apache License, Version 2.0
* (the "License"); You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* . Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
*
* . Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* . Neither the name "jOOQ" nor the names of its contributors may be
* used to endorse or promote products derived from this software without
* specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
package org.jooq;
import static org.jooq.SQLDialect.ORACLE;
import java.util.Collection;
/**
* An intermediate type for the construction of a partitioned
* {@link SQLDialect#ORACLE} <code>OUTER JOIN</code> clause.
* <p>
* This step allows for adding Oracle-specific <code>PARTITION BY</code> clauses
* to the right of an <code>OUTER JOIN</code> keyword. See the Oracle
* documentation for more details here: <a href=
* "http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm#i2054062"
* >http://docs.oracle.com/cd/B28359_01/server.111/b28286/queries006.htm#
* i2054062</a>
*
* @author Lukas Eder
*/
public interface TablePartitionByStep extends TableOnStep {
/**
* Add a <code>PARTITION BY</code> clause to the right hand side of the
* <code>OUTER JOIN</code> keywords
*/
@Support(ORACLE)
TableOnStep partitionBy(Field<?>... fields);
/**
* Add a <code>PARTITION BY</code> clause to the right hand side of the
* <code>OUTER JOIN</code> keywords
*/
@Support(ORACLE)
TableOnStep partitionBy(Collection<? extends Field<?>> fields);
}

View File

@ -55,6 +55,7 @@ import org.jooq.Table;
import org.jooq.TableField;
import org.jooq.TableLike;
import org.jooq.TableOnStep;
import org.jooq.TablePartitionByStep;
abstract class AbstractTable<R extends Record> extends AbstractFieldProviderQueryPart<R> implements Table<R> {
@ -199,32 +200,32 @@ abstract class AbstractTable<R extends Record> extends AbstractFieldProviderQuer
}
@Override
public final TableOnStep leftOuterJoin(TableLike<?> table) {
public final TablePartitionByStep leftOuterJoin(TableLike<?> table) {
return new JoinTable(this, table, JoinType.LEFT_OUTER_JOIN);
}
@Override
public final TableOnStep leftOuterJoin(String sql) {
public final TablePartitionByStep leftOuterJoin(String sql) {
return leftOuterJoin(table(sql));
}
@Override
public final TableOnStep leftOuterJoin(String sql, Object... bindings) {
public final TablePartitionByStep leftOuterJoin(String sql, Object... bindings) {
return leftOuterJoin(table(sql, bindings));
}
@Override
public final TableOnStep rightOuterJoin(TableLike<?> table) {
public final TablePartitionByStep rightOuterJoin(TableLike<?> table) {
return new JoinTable(this, table, JoinType.RIGHT_OUTER_JOIN);
}
@Override
public final TableOnStep rightOuterJoin(String sql) {
public final TablePartitionByStep rightOuterJoin(String sql) {
return rightOuterJoin(table(sql));
}
@Override
public final TableOnStep rightOuterJoin(String sql, Object... bindings) {
public final TablePartitionByStep rightOuterJoin(String sql, Object... bindings) {
return rightOuterJoin(table(sql, bindings));
}

View File

@ -73,6 +73,7 @@ import org.jooq.TableField;
import org.jooq.TableLike;
import org.jooq.TableOnConditionStep;
import org.jooq.TableOnStep;
import org.jooq.TablePartitionByStep;
import org.jooq.exception.DataAccessException;
/**
@ -80,7 +81,7 @@ import org.jooq.exception.DataAccessException;
*
* @author Lukas Eder
*/
class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnConditionStep {
class JoinTable extends AbstractTable<Record> implements TableOnConditionStep, TablePartitionByStep {
/**
* Generated UID
@ -89,6 +90,7 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
private final Table<?> lhs;
private final Table<?> rhs;
private final FieldList rhsPartitionBy;
private final JoinType type;
private final ConditionProviderImpl condition;
@ -99,6 +101,7 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
this.lhs = lhs.asTable();
this.rhs = rhs.asTable();
this.rhsPartitionBy = new FieldList();
this.type = type;
this.condition = new ConditionProviderImpl();
@ -133,6 +136,15 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
.sql(rhs)
.sql(rhs instanceof JoinTable ? ")" : "");
// [#1645] The Oracle PARTITION BY clause can be put to the right of an
// OUTER JOINed table
if (!rhsPartitionBy.isEmpty()) {
context.formatSeparator()
.keyword(" partition by (")
.sql(rhsPartitionBy)
.sql(")");
}
// CROSS JOIN and NATURAL JOIN do not have any condition clauses
if (!asList(CROSS_JOIN,
NATURAL_JOIN,
@ -233,7 +245,7 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
@Override
public final void bind(BindContext context) throws DataAccessException {
context.bind(lhs).bind(rhs);
context.bind(lhs).bind(rhs).bind((QueryPart) rhsPartitionBy);
if (!using.isEmpty()) {
context.bind((QueryPart) using);
@ -272,6 +284,17 @@ class JoinTable extends AbstractTable<Record> implements TableOnStep, TableOnCon
// Join API
// ------------------------------------------------------------------------
@Override
public final TableOnStep partitionBy(Field<?>... fields) {
return partitionBy(Util.list(fields));
}
@Override
public final TableOnStep partitionBy(Collection<? extends Field<?>> fields) {
rhsPartitionBy.addAll(fields);
return this;
}
@Override
public final JoinTable on(Condition... conditions) {
condition.addConditions(conditions);

View File

@ -56,6 +56,7 @@ import org.jooq.SelectConditionStep;
import org.jooq.SelectConnectByConditionStep;
import org.jooq.SelectForUpdateOfStep;
import org.jooq.SelectHavingConditionStep;
import org.jooq.SelectJoinPartitionByStep;
import org.jooq.SelectJoinStep;
import org.jooq.SelectOffsetStep;
import org.jooq.SelectOnConditionStep;
@ -77,7 +78,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
// Cascading interface implementations for Select behaviour
SelectSelectStep,
SelectOnStep,
SelectJoinPartitionByStep,
SelectOnConditionStep,
SelectConditionStep,
SelectConnectByConditionStep,
@ -95,6 +96,11 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
*/
private transient TableLike<?> joinTable;
/**
* A temporary member holding a join partition by expression
*/
private transient Field<?>[] joinPartitionBy;
/**
* A temporary member holding a join type
*/
@ -573,8 +579,9 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
conditionStep = ConditionStep.ON;
joinConditions = new ConditionProviderImpl();
joinConditions.addConditions(conditions);
getQuery().addJoin(joinTable, joinType, joinConditions);
getQuery().addJoin(joinTable, joinType, new Condition[] { joinConditions }, joinPartitionBy);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
}
@ -594,6 +601,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
conditionStep = ConditionStep.ON;
getQuery().addJoinOnKey(joinTable, joinType);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
}
@ -603,6 +611,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
conditionStep = ConditionStep.ON;
getQuery().addJoinOnKey(joinTable, joinType, keyFields);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
}
@ -612,6 +621,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
conditionStep = ConditionStep.ON;
getQuery().addJoinOnKey(joinTable, joinType, key);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
@ -626,6 +636,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
public final SelectImpl using(Collection<? extends Field<?>> fields) {
getQuery().addJoinUsing(joinTable, joinType, fields);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
}
@ -654,6 +665,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
conditionStep = ConditionStep.ON;
joinTable = table;
joinType = type;
joinPartitionBy = null;
joinConditions = null;
return this;
}
@ -681,6 +693,7 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
private final SelectImpl simpleJoin0(TableLike<?> table, JoinType type) {
getQuery().addJoin(table, type);
joinTable = null;
joinPartitionBy = null;
joinType = null;
return this;
}
@ -765,6 +778,17 @@ class SelectImpl extends AbstractDelegatingSelect<Record> implements
return naturalRightOuterJoin(table(sql, bindings));
}
@Override
public final SelectImpl partitionBy(Field<?>... fields) {
joinPartitionBy = fields;
return this;
}
@Override
public final SelectImpl partitionBy(Collection<? extends Field<?>> fields) {
return partitionBy(fields.toArray(new Field[fields.size()]));
}
/**
* The {@link SelectImpl} current condition step
* <p>

View File

@ -140,6 +140,11 @@ class SelectQueryImpl extends AbstractSubSelect<Record> implements SelectQuery {
@Override
public final void addJoin(TableLike<?> table, JoinType type, Condition... conditions) {
addJoin(table, type, conditions, null);
}
@Override
public final void addJoin(TableLike<?> table, JoinType type, Condition[] conditions, Field<?>[] partitionBy) {
// TODO: This and similar methods should be refactored, patterns extracted...
int index = getFrom().size() - 1;
@ -150,10 +155,10 @@ class SelectQueryImpl extends AbstractSubSelect<Record> implements SelectQuery {
joined = getFrom().get(index).join(table).on(conditions);
break;
case LEFT_OUTER_JOIN:
joined = getFrom().get(index).leftOuterJoin(table).on(conditions);
joined = getFrom().get(index).leftOuterJoin(table).partitionBy(partitionBy).on(conditions);
break;
case RIGHT_OUTER_JOIN:
joined = getFrom().get(index).rightOuterJoin(table).on(conditions);
joined = getFrom().get(index).rightOuterJoin(table).partitionBy(partitionBy).on(conditions);
break;
case FULL_OUTER_JOIN:
joined = getFrom().get(index).fullOuterJoin(table).on(conditions);

View File

@ -53,7 +53,9 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.regex.Pattern;
@ -193,6 +195,14 @@ final class Util {
}
}
/**
* Use this rather than {@link Arrays#asList(Object...)} for
* <code>null</code>-safety
*/
static final <T> List<T> list(T[] array) {
return array == null ? Collections.<T>emptyList() : Arrays.asList(array);
}
/**
* [#1005] Convert values from the <code>VALUES</code> clause to appropriate
* values as specified by the <code>INTO</code> clause's column list.