[#1645] Add support for Oracle's PARTITION BY clause in OUTER JOINs
This commit is contained in:
parent
e3d0935070
commit
e146168d29
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
104
jOOQ/src/main/java/org/jooq/SelectJoinPartitionByStep.java
Normal file
104
jOOQ/src/main/java/org/jooq/SelectJoinPartitionByStep.java
Normal 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);
|
||||
|
||||
}
|
||||
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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.
|
||||
|
||||
70
jOOQ/src/main/java/org/jooq/TablePartitionByStep.java
Normal file
70
jOOQ/src/main/java/org/jooq/TablePartitionByStep.java
Normal 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);
|
||||
}
|
||||
@ -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));
|
||||
}
|
||||
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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>
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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.
|
||||
|
||||
Loading…
Reference in New Issue
Block a user