[#1077] Add support for the SQL standard OVERLAPS predicate

This commit is contained in:
Lukas Eder 2012-08-30 22:51:20 +02:00
parent 86d3792960
commit 27ac37a751
16 changed files with 739 additions and 72 deletions

View File

@ -46,14 +46,19 @@ import static org.jooq.SQLDialect.INGRES;
import static org.jooq.SQLDialect.SQLITE;
import static org.jooq.SQLDialect.SQLSERVER;
import static org.jooq.SQLDialect.SYBASE;
import static org.jooq.impl.Factory.currentDate;
import static org.jooq.impl.Factory.inline;
import static org.jooq.impl.Factory.not;
import static org.jooq.impl.Factory.tuple;
import static org.jooq.impl.Factory.val;
import java.sql.Date;
import org.jooq.TableRecord;
import org.jooq.UpdatableRecord;
import org.jooq.test.BaseTest;
import org.jooq.test.jOOQAbstractTest;
import org.jooq.types.DayToSecond;
import org.junit.Test;
@ -141,4 +146,52 @@ extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, I, IPK, T658,
}
}
}
@Test
public void testTupleOverlapsCondition() throws Exception {
// 1903-06-25
// 1947-08-24
long now = System.currentTimeMillis();
long day = 1000L * 60 * 60 * 24;
// SQL standard (DATE, DATE) OVERLAPS (DATE, DATE) predicate
// ---------------------------------------------------------
assertEquals(2, (int)
create().selectCount()
.from(TAuthor())
.where(tuple(TAuthor_DATE_OF_BIRTH(), currentDate())
.overlaps(new Date(now - day), new Date(now + day)))
.fetchOne(0, Integer.class));
// SQL standard (DATE, INTERVAL) OVERLAPS (DATE, INTERVAL) predicate
// -----------------------------------------------------------------
if (asList(INGRES).contains(getDialect())) {
log.info("SKIPPING", "Ingres INTERVAL OVERLAPS tests");
}
else {
assertEquals(1, (int)
create().selectOne()
.where(tuple(new Date(now), new DayToSecond(3))
.overlaps(new Date(now + day), new DayToSecond(3)))
.fetchOne(0, Integer.class));
// jOOQ should recognise these as a (DATE, INTERVAL) tuple
assertEquals(1, (int)
create().selectOne()
.where(tuple(new Date(now), 3)
.overlaps(new Date(now + day), 3))
.fetchOne(0, Integer.class));
}
// jOOQ's convenience for letting arbitrary data types "overlap"
// -------------------------------------------------------------
assertEquals(1, (int)
create().selectOne()
.where(tuple(1, 3).overlaps(2, 4))
.and(tuple(1, 4).overlaps(2, 3))
.and(tuple(1, 4).overlaps(3, 2))
.and(not(tuple(1, 2).overlaps(3, 4)))
.fetchOne(0, Integer.class));
}
}

View File

@ -972,6 +972,11 @@ public abstract class jOOQAbstractTest<
new TupleTests(this).testTupleConditions();
}
@Test
public void testTupleOverlapsCondition() throws Exception {
new TupleTests(this).testTupleOverlapsCondition();
}
@Test
public void testIgnoreCase() throws Exception {
new PredicateTests(this).testIgnoreCase();

View File

@ -4359,7 +4359,47 @@ notExists(create.selectOne().from(BOOK)
<section id="overlaps-predicate">
<title>OVERLAPS predicate</title>
<content></content>
<content>
<p>
When comparing dates, the SQL standard allows for using a special OVERLAPS predicate, which checks whether two date ranges overlap each other. The following can be said:
</p>
<sql><![CDATA[-- This yields true
(DATE '2010-01-01', DATE '2010-01-03') OVERLAPS (DATE '2010-01-02' DATE '2010-01-04')
-- INTERVAL data types are also supported. This is equivalent to the above
(DATE '2010-01-01', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND)) OVERLAPS (DATE '2010-01-02', CAST('+2 00:00:00' AS INTERVAL DAY TO SECOND))]]></sql>
<h3>The OVERLAPS predicate in jOOQ</h3>
<p>
jOOQ supports the OVERLAPS predicate on <reference id="tuples" title="tuples of degree 2"/>. The following methods are contained in <reference class="org.jooq.Tuple2"/>:
</p>
<java><![CDATA[Condition overlaps(T1 t1, T2 t2);
Condition overlaps(Field<T1> t1, Field<T2> t2);
Condition overlaps(Tuple2<T1, T2> tuple);]]></java>
<p>
This allows for expressing the above predicates as such:
</p>
<java><![CDATA[// The date range tuples version
tuple(Date.valueOf('2010-01-01'), Date.valueOf('2010-01-03')).overlaps(Date.valueOf('2010-01-02'), Date.valueOf('2010-01-04'))
// The INTERVAL tuples version
tuple(Date.valueOf('2010-01-01'), new DayToSecond(2)).overlaps(Date.valueOf('2010-01-02'), new DayToSecond(2))]]></java>
<h3>jOOQ's extensions to the standard</h3>
<p>
Unlike the standard (or any database implementing the standard), jOOQ also supports the OVERLAPS predicate for comparing arbitrary <reference id="tuples" title="tuples of degree 2"/>. For instance, (1, 3) OVERLAPS (2, 4) will yield true in jOOQ. This is simulated as such
</p>
<sql><![CDATA[-- This predicate
(A, B) OVERLAPS (C, D)
-- can be simulated as such
(C <= B) AND (A <= D)]]></sql>
</content>
</section>
</sections>
</section>

View File

@ -45,4 +45,13 @@ package org.jooq;
*/
public interface Tuple extends QueryPart {
/**
* Get the degree of this tuple
*/
int getDegree();
/**
* Get a field at a given index
*/
Field<?> getField(int index);
}

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>1</code>
* A model type for a tuple with degree <code>1</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,19 @@ import java.util.Collection;
*/
public interface Tuple1<T1> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +226,7 @@ public interface Tuple1<T1> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +260,7 @@ public interface Tuple1<T1> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>2</code>
* A model type for a tuple with degree <code>2</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,24 @@ import java.util.Collection;
*/
public interface Tuple2<T1, T2> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +231,7 @@ public interface Tuple2<T1, T2> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,10 +265,76 @@ public interface Tuple2<T1, T2> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@Support({ CUBRID, DB2, HSQLDB, MYSQL, ORACLE, POSTGRES })
Condition notIn(Select<?> select);
/**
* Check if this tuple overlaps another tuple
* <p>
* The SQL standard specifies a temporal <code>OVERLAPS</code> predicate,
* which comes in two flavours:
* <ul>
* <li><code>(DATE, DATE) OVERLAPS (DATE, DATE)</code></li>
* <li><code>(DATE, INTERVAL) OVERLAPS (DATE, INTERVAL)</code></li>
* </ul>
* <p>
* jOOQ also supports arbitrary 2-degree tuple comparisons, by simulating
* them as such <code><pre>
* -- This predicate
* (A, B) OVERLAPS (C, D)
*
* -- can be simulated as such
* (C &lt;= B) AND (A &lt;= D)
* </pre></code>
*/
@Support
Condition overlaps(T1 t1, T2 t2);
/**
* Check if this tuple overlaps another tuple
* <p>
* The SQL standard specifies a temporal <code>OVERLAPS</code> predicate,
* which comes in two flavours:
* <ul>
* <li><code>(DATE, DATE) OVERLAPS (DATE, DATE)</code></li>
* <li><code>(DATE, INTERVAL) OVERLAPS (DATE, INTERVAL)</code></li>
* </ul>
* <p>
* jOOQ also supports arbitrary 2-degree tuple comparisons, by simulating
* them as such <code><pre>
* -- This predicate
* (A, B) OVERLAPS (C, D)
*
* -- can be simulated as such
* (C &lt;= B) AND (A &lt;= D)
* </pre></code>
*/
@Support
Condition overlaps(Field<T1> t1, Field<T2> t2);
/**
* Check if this tuple overlaps another tuple
* <p>
* The SQL standard specifies a temporal <code>OVERLAPS</code> predicate,
* which comes in two flavours:
* <ul>
* <li><code>(DATE, DATE) OVERLAPS (DATE, DATE)</code></li>
* <li><code>(DATE, INTERVAL) OVERLAPS (DATE, INTERVAL)</code></li>
* </ul>
* <p>
* jOOQ also supports arbitrary 2-degree tuple comparisons, by simulating
* them as such <code><pre>
* -- This predicate
* (A, B) OVERLAPS (C, D)
*
* -- can be simulated as such
* (C &lt;= B) AND (A &lt;= D)
* </pre></code>
*/
@Support
Condition overlaps(Tuple2<T1, T2> tuple);
}

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>3</code>
* A model type for a tuple with degree <code>3</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,29 @@ import java.util.Collection;
*/
public interface Tuple3<T1, T2, T3> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +236,7 @@ public interface Tuple3<T1, T2, T3> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +270,7 @@ public interface Tuple3<T1, T2, T3> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>4</code>
* A model type for a tuple with degree <code>4</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,34 @@ import java.util.Collection;
*/
public interface Tuple4<T1, T2, T3, T4> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
/**
* Get the fourth field
*/
Field<T4> field4();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +241,7 @@ public interface Tuple4<T1, T2, T3, T4> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +275,7 @@ public interface Tuple4<T1, T2, T3, T4> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>5</code>
* A model type for a tuple with degree <code>5</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,39 @@ import java.util.Collection;
*/
public interface Tuple5<T1, T2, T3, T4, T5> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
/**
* Get the fourth field
*/
Field<T4> field4();
/**
* Get the fifth field
*/
Field<T5> field5();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +246,7 @@ public interface Tuple5<T1, T2, T3, T4, T5> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +280,7 @@ public interface Tuple5<T1, T2, T3, T4, T5> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>6</code>
* A model type for a tuple with degree <code>6</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,44 @@ import java.util.Collection;
*/
public interface Tuple6<T1, T2, T3, T4, T5, T6> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
/**
* Get the fourth field
*/
Field<T4> field4();
/**
* Get the fifth field
*/
Field<T5> field5();
/**
* Get the sixth field
*/
Field<T6> field6();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +251,7 @@ public interface Tuple6<T1, T2, T3, T4, T5, T6> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +285,7 @@ public interface Tuple6<T1, T2, T3, T4, T5, T6> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>7</code>
* A model type for a tuple with degree <code>7</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,49 @@ import java.util.Collection;
*/
public interface Tuple7<T1, T2, T3, T4, T5, T6, T7> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
/**
* Get the fourth field
*/
Field<T4> field4();
/**
* Get the fifth field
*/
Field<T5> field5();
/**
* Get the sixth field
*/
Field<T6> field6();
/**
* Get the seventh field
*/
Field<T7> field7();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +256,7 @@ public interface Tuple7<T1, T2, T3, T4, T5, T6, T7> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +290,7 @@ public interface Tuple7<T1, T2, T3, T4, T5, T6, T7> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>8</code>
* A model type for a tuple with degree <code>8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -54,6 +54,54 @@ import java.util.Collection;
*/
public interface Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> extends Tuple {
// ------------------------------------------------------------------------
// Field accessors
// ------------------------------------------------------------------------
/**
* Get the first field
*/
Field<T1> field1();
/**
* Get the second field
*/
Field<T2> field2();
/**
* Get the third field
*/
Field<T3> field3();
/**
* Get the fourth field
*/
Field<T4> field4();
/**
* Get the fifth field
*/
Field<T5> field5();
/**
* Get the sixth field
*/
Field<T6> field6();
/**
* Get the seventh field
*/
Field<T7> field7();
/**
* Get the eight field
*/
Field<T8> field8();
// ------------------------------------------------------------------------
// Tuple DSL API
// ------------------------------------------------------------------------
/**
* Compare this tuple with another tuple for equality
* <p>
@ -213,7 +261,7 @@ public interface Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +295,7 @@ public interface Tuple8<T1, T2, T3, T4, T5, T6, T7, T8> extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -45,7 +45,7 @@ import static org.jooq.SQLDialect.POSTGRES;
import java.util.Collection;
/**
* A model type for a tuple with arity <code>N > 8</code>
* A model type for a tuple with degree <code>N > 8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for details.
@ -213,7 +213,7 @@ public interface TupleN extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/
@ -247,7 +247,7 @@ public interface TupleN extends Tuple {
/**
* Compare this tuple with a subselect for equality
* <p>
* Note that the subquery must return a table of the same arity as this
* Note that the subquery must return a table of the same degree as this
* tuple. This is not checked by jOOQ and will result in syntax errors in
* the database, if not used correctly.
*/

View File

@ -5844,7 +5844,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>1</code>
* Create a tuple of degree <code>1</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5856,7 +5856,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>2</code>
* Create a tuple of degree <code>2</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5868,7 +5868,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>3</code>
* Create a tuple of degree <code>3</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5880,7 +5880,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>4</code>
* Create a tuple of degree <code>4</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5892,7 +5892,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>5</code>
* Create a tuple of degree <code>5</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5904,7 +5904,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>6</code>
* Create a tuple of degree <code>6</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5916,7 +5916,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>7</code>
* Create a tuple of degree <code>7</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5928,7 +5928,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>8</code>
* Create a tuple of degree <code>8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5940,7 +5940,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>N > 8</code>
* Create a tuple of degree <code>N > 8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5952,7 +5952,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>1</code>
* Create a tuple of degree <code>1</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5964,7 +5964,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>2</code>
* Create a tuple of degree <code>2</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5976,7 +5976,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>3</code>
* Create a tuple of degree <code>3</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -5988,7 +5988,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>4</code>
* Create a tuple of degree <code>4</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -6000,7 +6000,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>5</code>
* Create a tuple of degree <code>5</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -6012,7 +6012,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>6</code>
* Create a tuple of degree <code>6</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -6024,7 +6024,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>7</code>
* Create a tuple of degree <code>7</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -6036,7 +6036,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>8</code>
* Create a tuple of degree <code>8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for
@ -6048,7 +6048,7 @@ public class Factory implements FactoryOperations {
}
/**
* Create a tuple of arity <code>N > 8</code>
* Create a tuple of degree <code>N > 8</code>
* <p>
* Note: Not all databases support tuples, but many tuple operations can be
* simulated on all databases. See relevant tuple method Javadocs for

View File

@ -39,10 +39,14 @@ import static java.util.Arrays.asList;
import static org.jooq.Comparator.EQUALS;
import static org.jooq.Comparator.NOT_EQUALS;
import static org.jooq.SQLDialect.ASE;
import static org.jooq.SQLDialect.CUBRID;
import static org.jooq.SQLDialect.DB2;
import static org.jooq.SQLDialect.DERBY;
import static org.jooq.SQLDialect.FIREBIRD;
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.SQLITE;
import static org.jooq.SQLDialect.SQLSERVER;
@ -59,6 +63,7 @@ import org.jooq.BindContext;
import org.jooq.Comparator;
import org.jooq.Condition;
import org.jooq.Configuration;
import org.jooq.DataType;
import org.jooq.Field;
import org.jooq.Operator;
import org.jooq.QueryPart;
@ -74,7 +79,6 @@ import org.jooq.Tuple6;
import org.jooq.Tuple7;
import org.jooq.Tuple8;
import org.jooq.TupleN;
import org.jooq.exception.DataAccessException;
/**
* @author Lukas Eder
@ -132,7 +136,69 @@ implements
}
// ------------------------------------------------------------------------
// XXX: Tuple API
// XXX: Tuple accessor API
// ------------------------------------------------------------------------
@Override
public final int getDegree() {
return fields.length;
}
@Override
public final Field<?> getField(int index) {
return fields[index];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T1> field1() {
return (Field<T1>) fields[0];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T2> field2() {
return (Field<T2>) fields[1];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T3> field3() {
return (Field<T3>) fields[2];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T4> field4() {
return (Field<T4>) fields[3];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T5> field5() {
return (Field<T5>) fields[4];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T6> field6() {
return (Field<T6>) fields[5];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T7> field7() {
return (Field<T7>) fields[6];
}
@SuppressWarnings("unchecked")
@Override
public final Field<T8> field8() {
return (Field<T8>) fields[7];
}
// ------------------------------------------------------------------------
// XXX: Tuple DSL API
// ------------------------------------------------------------------------
@Override
@ -789,10 +855,118 @@ implements
return new InSubquery(select, InOperator.NOT_IN);
}
// ------------------------------------------------------------------------
// XXX: Tuple2 API
// ------------------------------------------------------------------------
@Override
public final Condition overlaps(T1 t1, T2 t2) {
return overlaps(tuple(t1, t2));
}
@Override
public final Condition overlaps(Field<T1> t1, Field<T2> t2) {
return overlaps(tuple(t1, t2));
}
@Override
public final Condition overlaps(Tuple2<T1, T2> tuple) {
return new Overlaps(tuple);
}
// ------------------------------------------------------------------------
// XXX: Implementation classes
// ------------------------------------------------------------------------
private class Overlaps extends AbstractCondition {
/**
* Generated UID
*/
private static final long serialVersionUID = 85887551884667824L;
private final TupleImpl<T1, T2, ?, ?, ?, ?, ?, ?> other;
@SuppressWarnings("unchecked")
Overlaps(Tuple2<T1, T2> other) {
this.other = (TupleImpl<T1, T2, ?, ?, ?, ?, ?, ?>) other;
}
@Override
public final void toSQL(RenderContext context) {
delegate(context).toSQL(context);
}
@Override
public final void bind(BindContext context) {
delegate(context).bind(context);
}
@SuppressWarnings({ "unchecked", "rawtypes" })
private final QueryPartInternal delegate(Configuration configuration) {
DataType<?> type0 = fields[0].getDataType();
DataType<?> type1 = fields[1].getDataType();
// The SQL standard only knows temporal OVERLAPS predicates:
// (DATE, DATE) OVERLAPS (DATE, DATE)
// (DATE, INTERVAL) OVERLAPS (DATE, INTERVAL)
boolean standardOverlaps = type0.isDateTime() && type1.isTemporal();
boolean intervalOverlaps = type0.isDateTime() && (type1.isInterval() || type1.isNumeric());
// The non-standard OVERLAPS predicate is always simulated
if (!standardOverlaps || asList(ASE, CUBRID, DB2, DERBY, FIREBIRD, H2, INGRES, MYSQL, SQLSERVER, SQLITE, SYBASE).contains(configuration.getDialect())) {
// Interval OVERLAPS predicates need some additional arithmetic
if (intervalOverlaps) {
return (QueryPartInternal)
other.fields[0].le((Field) fields[0].add(fields[1])).and(
fields[0].le((Field) other.fields[0].add(other.fields[1])));
}
// All other OVERLAPS predicates can be simulated simply
else {
return (QueryPartInternal)
other.fields[0].le((Field) fields[1]).and(
fields[0].le((Field) other.fields[1]));
}
}
// These dialects seem to have trouble with INTERVAL OVERLAPS predicates
else if (intervalOverlaps && asList(HSQLDB).contains(configuration.getDialect())) {
return (QueryPartInternal)
other.fields[0].le((Field) fields[0].add(fields[1])).and(
fields[0].le((Field) other.fields[0].add(other.fields[1])));
}
// Everyone else can handle OVERLAPS (Postgres, Oracle)
else {
return new Native();
}
}
private class Native extends AbstractCondition {
/**
* Generated UID
*/
private static final long serialVersionUID = -1552476981094856727L;
@Override
public final void toSQL(RenderContext context) {
context.sql("(")
.sql(TupleImpl.this)
.keyword(" overlaps ")
.sql(other)
.sql(")");
}
@Override
public final void bind(BindContext context) {
context.bind(TupleImpl.this).bind(other);
}
}
}
private class Compare extends AbstractCondition {
/**
@ -815,7 +989,7 @@ implements
}
@Override
public final void bind(BindContext context) throws DataAccessException {
public final void bind(BindContext context) {
delegate(context).bind(context);
}
@ -874,7 +1048,7 @@ implements
}
@Override
public final void bind(BindContext context) throws DataAccessException {
public final void bind(BindContext context) {
context.bind(TupleImpl.this).bind(other);
}
}
@ -901,7 +1075,7 @@ implements
}
@Override
public final void bind(BindContext context) throws DataAccessException {
public final void bind(BindContext context) {
delegate(context).bind(context);
}
@ -944,7 +1118,7 @@ implements
}
@Override
public final void bind(BindContext context) throws DataAccessException {
public final void bind(BindContext context) {
context.bind(TupleImpl.this).bind((QueryPart) other);
}
@ -986,7 +1160,7 @@ implements
}
@Override
public final void bind(BindContext context) throws DataAccessException {
public final void bind(BindContext context) {
context.bind(TupleImpl.this).bind(other);
}
}

View File

@ -100,6 +100,15 @@ import org.jooq.SelectQuery;
import org.jooq.SimpleSelectQuery;
import org.jooq.Table;
import org.jooq.Truncate;
import org.jooq.Tuple1;
import org.jooq.Tuple2;
import org.jooq.Tuple3;
import org.jooq.Tuple4;
import org.jooq.Tuple5;
import org.jooq.Tuple6;
import org.jooq.Tuple7;
import org.jooq.Tuple8;
import org.jooq.TupleN;
import org.jooq.UpdateQuery;
import org.jooq.conf.RenderKeywordStyle;
import org.jooq.conf.RenderNameStyle;
@ -595,24 +604,91 @@ public class jOOQTest {
@Test
public void testTuples() throws Exception {
assertEquals("(?)", r_ref().render(tuple(1)));
assertEquals("(1)", r_refI().render(tuple(1)));
assertEquals("(?, ?)", r_ref().render(tuple(1, "2")));
assertEquals("(1, '2')", r_refI().render(tuple(1, "2")));
assertEquals("(?, ?, ?)", r_ref().render(tuple(1, "2", 3)));
assertEquals("(1, '2', 3)", r_refI().render(tuple(1, "2", 3)));
assertEquals("(?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4")));
assertEquals("(1, '2', 3, '4')", r_refI().render(tuple(1, "2", 3, "4")));
assertEquals("(?, ?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4", 5)));
assertEquals("(1, '2', 3, '4', 5)", r_refI().render(tuple(1, "2", 3, "4", 5)));
assertEquals("(?, ?, ?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4", 5, "6")));
assertEquals("(1, '2', 3, '4', 5, '6')", r_refI().render(tuple(1, "2", 3, "4", 5, "6")));
assertEquals("(?, ?, ?, ?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4", 5, "6", 7)));
assertEquals("(1, '2', 3, '4', 5, '6', 7)", r_refI().render(tuple(1, "2", 3, "4", 5, "6", 7)));
assertEquals("(?, ?, ?, ?, ?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4", 5, "6", 7, "8")));
assertEquals("(1, '2', 3, '4', 5, '6', 7, '8')", r_refI().render(tuple(1, "2", 3, "4", 5, "6", 7, "8")));
assertEquals("(?, ?, ?, ?, ?, ?, ?, ?, ?)", r_ref().render(tuple(1, "2", 3, "4", 5, "6", 7, "8", 9)));
assertEquals("(1, '2', 3, '4', 5, '6', 7, '8', 9)", r_refI().render(tuple(1, "2", 3, "4", 5, "6", 7, "8", 9)));
Tuple1<Integer> t1 = tuple(1);
Tuple2<Integer, String> t2 = tuple(1, "2");
Tuple3<Integer, String, Integer> t3 = tuple(1, "2", 3);
Tuple4<Integer, String, Integer, String> t4 = tuple(1, "2", 3, "4");
Tuple5<Integer, String, Integer, String, Integer> t5 = tuple(1, "2", 3, "4", 5);
Tuple6<Integer, String, Integer, String, Integer, String> t6 = tuple(1, "2", 3, "4", 5, "6");
Tuple7<Integer, String, Integer, String, Integer, String, Integer> t7 = tuple(1, "2", 3, "4", 5, "6", 7);
Tuple8<Integer, String, Integer, String, Integer, String, Integer, String> t8 = tuple(1, "2", 3, "4", 5, "6", 7, "8");
TupleN t9 = tuple(1, "2", 3, "4", 5, "6", 7, "8", 9);
// General info
assertEquals(1, t1.getDegree());
assertEquals(2, t2.getDegree());
assertEquals(3, t3.getDegree());
assertEquals(4, t4.getDegree());
assertEquals(5, t5.getDegree());
assertEquals(6, t6.getDegree());
assertEquals(7, t7.getDegree());
assertEquals(8, t8.getDegree());
assertEquals(9, t9.getDegree());
// Accessors
assertEquals(val(1), t1.field1());
assertEquals(val(1), t2.field1());
assertEquals(val("2"), t2.field2());
assertEquals(val(1), t3.field1());
assertEquals(val("2"), t3.field2());
assertEquals(val(3), t3.field3());
assertEquals(val(1), t4.field1());
assertEquals(val("2"), t4.field2());
assertEquals(val(3), t4.field3());
assertEquals(val("4"), t4.field4());
assertEquals(val(1), t5.field1());
assertEquals(val("2"), t5.field2());
assertEquals(val(3), t5.field3());
assertEquals(val("4"), t5.field4());
assertEquals(val(5), t5.field5());
assertEquals(val(1), t6.field1());
assertEquals(val("2"), t6.field2());
assertEquals(val(3), t6.field3());
assertEquals(val("4"), t6.field4());
assertEquals(val(5), t6.field5());
assertEquals(val("6"), t6.field6());
assertEquals(val(1), t7.field1());
assertEquals(val("2"), t7.field2());
assertEquals(val(3), t7.field3());
assertEquals(val("4"), t7.field4());
assertEquals(val(5), t7.field5());
assertEquals(val("6"), t7.field6());
assertEquals(val(7), t7.field7());
assertEquals(val(1), t8.field1());
assertEquals(val("2"), t8.field2());
assertEquals(val(3), t8.field3());
assertEquals(val("4"), t8.field4());
assertEquals(val(5), t8.field5());
assertEquals(val("6"), t8.field6());
assertEquals(val(7), t8.field7());
assertEquals(val("8"), t8.field8());
// Rendering
assertEquals("(?)", r_ref().render(t1));
assertEquals("(1)", r_refI().render(t1));
assertEquals("(?, ?)", r_ref().render(t2));
assertEquals("(1, '2')", r_refI().render(t2));
assertEquals("(?, ?, ?)", r_ref().render(t3));
assertEquals("(1, '2', 3)", r_refI().render(t3));
assertEquals("(?, ?, ?, ?)", r_ref().render(t4));
assertEquals("(1, '2', 3, '4')", r_refI().render(t4));
assertEquals("(?, ?, ?, ?, ?)", r_ref().render(t5));
assertEquals("(1, '2', 3, '4', 5)", r_refI().render(t5));
assertEquals("(?, ?, ?, ?, ?, ?)", r_ref().render(t6));
assertEquals("(1, '2', 3, '4', 5, '6')", r_refI().render(t6));
assertEquals("(?, ?, ?, ?, ?, ?, ?)", r_ref().render(t7));
assertEquals("(1, '2', 3, '4', 5, '6', 7)", r_refI().render(t7));
assertEquals("(?, ?, ?, ?, ?, ?, ?, ?)", r_ref().render(t8));
assertEquals("(1, '2', 3, '4', 5, '6', 7, '8')", r_refI().render(t8));
assertEquals("(?, ?, ?, ?, ?, ?, ?, ?, ?)", r_ref().render(t9));
assertEquals("(1, '2', 3, '4', 5, '6', 7, '8', 9)", r_refI().render(t9));
context.checking(new Expectations() {{
int i = 0;
@ -628,7 +704,7 @@ public class jOOQTest {
oneOf(statement).setInt(++i, i);
}});
assertEquals(10, b_ref().bind(tuple(1, "2", 3, "4", 5, "6", 7, "8", 9)).peekIndex());
assertEquals(10, b_ref().bind(t9).peekIndex());
context.assertIsSatisfied();
}