[#2765] Add support for a database-agnostic GENERATE_SERIES(FROM, TO) table function
This commit is contained in:
parent
a5f36eb2b7
commit
1d5ae25f2b
128
jOOQ-test/src/org/jooq/test/_/testcases/TableFunctionTests.java
Normal file
128
jOOQ-test/src/org/jooq/test/_/testcases/TableFunctionTests.java
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2013, Data Geekery GmbH (http://www.datageekery.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This work is dual-licensed
|
||||
* - under the Apache Software License 2.0 (the "ASL")
|
||||
* - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
|
||||
* =============================================================================
|
||||
* You may choose which license applies to you:
|
||||
*
|
||||
* - If you're using this work with Open Source databases, you may choose
|
||||
* either ASL or jOOQ License.
|
||||
* - If you're using this work with at least one commercial database, you must
|
||||
* choose jOOQ License
|
||||
*
|
||||
* For more information, please visit http://www.jooq.org/licenses
|
||||
*
|
||||
* Apache Software License 2.0:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* jOOQ License and Maintenance Agreement:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Data Geekery grants the Customer the non-exclusive, timely limited and
|
||||
* non-transferable license to install and use the Software under the terms of
|
||||
* the jOOQ License and Maintenance Agreement.
|
||||
*
|
||||
* This library is distributed with a LIMITED WARRANTY. See the jOOQ License
|
||||
* and Maintenance Agreement for more details: http://www.jooq.org/licensing
|
||||
*/
|
||||
package org.jooq.test._.testcases;
|
||||
|
||||
import static java.util.Arrays.asList;
|
||||
import static org.jooq.SQLDialect.CUBRID;
|
||||
import static org.jooq.SQLDialect.ORACLE;
|
||||
import static org.jooq.SQLDialect.POSTGRES;
|
||||
import static org.jooq.impl.DSL.generateSeries;
|
||||
import static org.jooq.impl.DSL.selectOne;
|
||||
import static org.junit.Assert.assertEquals;
|
||||
|
||||
import java.sql.Date;
|
||||
import java.util.List;
|
||||
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.Record2;
|
||||
import org.jooq.Record3;
|
||||
import org.jooq.Record6;
|
||||
import org.jooq.Table;
|
||||
import org.jooq.TableRecord;
|
||||
import org.jooq.UpdatableRecord;
|
||||
import org.jooq.test.BaseTest;
|
||||
import org.jooq.test.jOOQAbstractTest;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
public class TableFunctionTests<
|
||||
A extends UpdatableRecord<A> & Record6<Integer, String, String, Date, Integer, ?>,
|
||||
AP,
|
||||
B extends UpdatableRecord<B>,
|
||||
S extends UpdatableRecord<S> & Record1<String>,
|
||||
B2S extends UpdatableRecord<B2S> & Record3<String, Integer, Integer>,
|
||||
BS extends UpdatableRecord<BS>,
|
||||
L extends TableRecord<L> & Record2<String, String>,
|
||||
X extends TableRecord<X>,
|
||||
DATE extends UpdatableRecord<DATE>,
|
||||
BOOL extends UpdatableRecord<BOOL>,
|
||||
D extends UpdatableRecord<D>,
|
||||
T extends UpdatableRecord<T>,
|
||||
U extends TableRecord<U>,
|
||||
UU extends UpdatableRecord<UU>,
|
||||
I extends TableRecord<I>,
|
||||
IPK extends UpdatableRecord<IPK>,
|
||||
T725 extends UpdatableRecord<T725>,
|
||||
T639 extends UpdatableRecord<T639>,
|
||||
T785 extends TableRecord<T785>>
|
||||
extends BaseTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T725, T639, T785> {
|
||||
|
||||
public TableFunctionTests(jOOQAbstractTest<A, AP, B, S, B2S, BS, L, X, DATE, BOOL, D, T, U, UU, I, IPK, T725, T639, T785> delegate) {
|
||||
super(delegate);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateSeries() throws Exception {
|
||||
if (!asList(CUBRID, POSTGRES, ORACLE).contains(dialect().family()))
|
||||
return;
|
||||
|
||||
List<Integer> expected = asList(0, 1, 2, 3);
|
||||
Table<Record1<Integer>> series = generateSeries(0, 3);
|
||||
Table<Record1<Integer>> t = series.as("t", "a");
|
||||
|
||||
assertEquals(
|
||||
expected,
|
||||
create().select()
|
||||
.from(series)
|
||||
.orderBy(1)
|
||||
.fetch(0, Integer.class));
|
||||
assertEquals(
|
||||
0, (int)
|
||||
create().selectFrom(series)
|
||||
.orderBy(1)
|
||||
.fetch()
|
||||
.get(0)
|
||||
.value1());
|
||||
assertEquals(
|
||||
expected,
|
||||
create().select()
|
||||
.from(t)
|
||||
.orderBy(t.field("a"))
|
||||
.fetch(t.field("a")));
|
||||
|
||||
assertEquals(3, create().fetchCount(
|
||||
selectOne()
|
||||
.from(t)
|
||||
.join(TBook())
|
||||
.on(TBook_ID().eq(t.field("a").coerce(Integer.class)))
|
||||
));
|
||||
}
|
||||
}
|
||||
@ -144,6 +144,7 @@ import org.jooq.test._.testcases.RowValueExpressionTests;
|
||||
import org.jooq.test._.testcases.SchemaAndMappingTests;
|
||||
import org.jooq.test._.testcases.SelectTests;
|
||||
import org.jooq.test._.testcases.StatementTests;
|
||||
import org.jooq.test._.testcases.TableFunctionTests;
|
||||
import org.jooq.test._.testcases.ThreadSafetyTests;
|
||||
import org.jooq.test._.testcases.TruncateTests;
|
||||
import org.jooq.test._.testcases.ValuesConstructorTests;
|
||||
@ -2141,6 +2142,11 @@ public abstract class jOOQAbstractTest<
|
||||
@Test
|
||||
public void testStoredProceduresWithCursorParameters() throws Exception {
|
||||
new RoutineAndUDTTests(this).testStoredProceduresWithCursorParameters();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGenerateSeries() throws Exception {
|
||||
new TableFunctionTests(this).testGenerateSeries();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
@ -4658,6 +4658,48 @@ public class DSL {
|
||||
throw new SQLDialectNotSupportedException("Converting arbitrary types into array tables is currently not supported");
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX Table functions
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
/**
|
||||
* A table function generating a series of values from <code>from</code> to
|
||||
* <code>to</code> (inclusive).
|
||||
* <p>
|
||||
* This function is inspired by PostgreSQL's
|
||||
* <code>GENERATE_SERIES(from, to)</code> function. Other SQL dialects may
|
||||
* be capable of emulating this behaviour, e.g. Oracle: <code><pre>
|
||||
* -- PostgreSQL
|
||||
* SELECT * FROM GENERATE_SERIES(a, b)
|
||||
*
|
||||
* -- Oracle
|
||||
* SELECT * FROM (SELECT a + LEVEL - 1 FROM DUAL CONNECT BY a + LEVEL - 1 <= b)
|
||||
* </pre></code>
|
||||
*/
|
||||
@Support({ CUBRID, ORACLE, POSTGRES })
|
||||
public static Table<Record1<Integer>> generateSeries(int from, int to) {
|
||||
return generateSeries(val(from), val(to));
|
||||
}
|
||||
|
||||
/**
|
||||
* A table function generating a series of values from <code>from</code> to
|
||||
* <code>to</code> (inclusive).
|
||||
* <p>
|
||||
* This function is inspired by PostgreSQL's
|
||||
* <code>GENERATE_SERIES(from, to)</code> function. Other SQL dialects may
|
||||
* be capable of emulating this behaviour, e.g. Oracle: <code><pre>
|
||||
* -- PostgreSQL
|
||||
* SELECT * FROM GENERATE_SERIES(a, b)
|
||||
*
|
||||
* -- Oracle
|
||||
* SELECT * FROM (SELECT a + LEVEL - 1 FROM DUAL CONNECT BY a + LEVEL - 1 <= b)
|
||||
* </pre></code>
|
||||
*/
|
||||
@Support({ CUBRID, ORACLE, POSTGRES })
|
||||
public static Table<Record1<Integer>> generateSeries(Field<Integer> from, Field<Integer> to) {
|
||||
return new GenerateSeries(nullSafe(from), nullSafe(to));
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// XXX SQL keywords
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
128
jOOQ/src/main/java/org/jooq/impl/GenerateSeries.java
Normal file
128
jOOQ/src/main/java/org/jooq/impl/GenerateSeries.java
Normal file
@ -0,0 +1,128 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2013, Data Geekery GmbH (http://www.datageekery.com)
|
||||
* All rights reserved.
|
||||
*
|
||||
* This work is dual-licensed
|
||||
* - under the Apache Software License 2.0 (the "ASL")
|
||||
* - under the jOOQ License and Maintenance Agreement (the "jOOQ License")
|
||||
* =============================================================================
|
||||
* You may choose which license applies to you:
|
||||
*
|
||||
* - If you're using this work with Open Source databases, you may choose
|
||||
* either ASL or jOOQ License.
|
||||
* - If you're using this work with at least one commercial database, you must
|
||||
* choose jOOQ License
|
||||
*
|
||||
* For more information, please visit http://www.jooq.org/licenses
|
||||
*
|
||||
* Apache Software License 2.0:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*
|
||||
* jOOQ License and Maintenance Agreement:
|
||||
* -----------------------------------------------------------------------------
|
||||
* Data Geekery grants the Customer the non-exclusive, timely limited and
|
||||
* non-transferable license to install and use the Software under the terms of
|
||||
* the jOOQ License and Maintenance Agreement.
|
||||
*
|
||||
* This library is distributed with a LIMITED WARRANTY. See the jOOQ License
|
||||
* and Maintenance Agreement for more details: http://www.jooq.org/licensing
|
||||
*/
|
||||
package org.jooq.impl;
|
||||
|
||||
import static org.jooq.impl.DSL.level;
|
||||
import static org.jooq.impl.DSL.name;
|
||||
import static org.jooq.impl.DSL.one;
|
||||
import static org.jooq.impl.DSL.table;
|
||||
|
||||
import org.jooq.BindContext;
|
||||
import org.jooq.Configuration;
|
||||
import org.jooq.Field;
|
||||
import org.jooq.QueryPart;
|
||||
import org.jooq.Record1;
|
||||
import org.jooq.RenderContext;
|
||||
import org.jooq.Table;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
class GenerateSeries extends AbstractTable<Record1<Integer>> {
|
||||
|
||||
/**
|
||||
* Generated UID
|
||||
*/
|
||||
private static final long serialVersionUID = 2385574114457239818L;
|
||||
|
||||
private final Field<Integer> from;
|
||||
private final Field<Integer> to;
|
||||
|
||||
GenerateSeries(Field<Integer> from, Field<Integer> to) {
|
||||
super("generate_series");
|
||||
|
||||
this.from = from;
|
||||
this.to = to;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void toSQL(RenderContext ctx) {
|
||||
ctx.visit(delegate(ctx.configuration()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void bind(BindContext ctx) {
|
||||
ctx.visit(delegate(ctx.configuration()));
|
||||
}
|
||||
|
||||
private final QueryPart delegate(Configuration configuration) {
|
||||
switch (configuration.dialect().family()) {
|
||||
case CUBRID:
|
||||
/* [pro] */
|
||||
case ORACLE:
|
||||
/* [/pro] */
|
||||
|
||||
// There is a bug in CUBRID preventing reuse of "level" in the
|
||||
// predicate http://jira.cubrid.org/browse/ENGINE-119
|
||||
Field<Integer> level = from.add(level()).sub(one());
|
||||
return table("({select} {0} {as} {1} {from} {2} {connect by} {level} <= {3})",
|
||||
level,
|
||||
name("generate_series"),
|
||||
new Dual(),
|
||||
to.add(one()).sub(from));
|
||||
|
||||
case POSTGRES:
|
||||
default:
|
||||
return table("{generate_series}({0}, {1})", from, to);
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@Override
|
||||
public final Class<? extends Record1<Integer>> getRecordType() {
|
||||
return (Class<? extends Record1<Integer>>) RecordImpl.class;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record1<Integer>> as(String alias) {
|
||||
return new TableAlias<Record1<Integer>>(this, alias);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final Table<Record1<Integer>> as(String alias, String... fieldAliases) {
|
||||
return new TableAlias<Record1<Integer>>(this, alias, fieldAliases);
|
||||
}
|
||||
|
||||
@Override
|
||||
final Fields<Record1<Integer>> fields0() {
|
||||
return new Fields<Record1<Integer>>(DSL.fieldByName(Integer.class, "generate_series"));
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user