[#1952] Add support for SQL Server OPTION (...) query hints
This commit is contained in:
parent
c1387f5779
commit
b8371015f7
@ -36,6 +36,7 @@
|
||||
|
||||
package org.jooq.test;
|
||||
|
||||
import static junit.framework.Assert.assertEquals;
|
||||
import static org.jooq.test.sqlserver.generatedclasses.Tables.T_639_NUMBERS_TABLE;
|
||||
import static org.jooq.test.sqlserver.generatedclasses.Tables.T_725_LOB_TEST;
|
||||
import static org.jooq.test.sqlserver.generatedclasses.Tables.T_785;
|
||||
@ -104,6 +105,8 @@ import org.jooq.types.ULong;
|
||||
import org.jooq.types.UShort;
|
||||
import org.jooq.util.sqlserver.SQLServerDataType;
|
||||
|
||||
import org.junit.Test;
|
||||
|
||||
/**
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@ -754,4 +757,13 @@ public class SQLServerTest extends jOOQAbstractTest<
|
||||
SQLServerDataType.VARCHAR,
|
||||
};
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSQLServerOptionHint() throws Exception {
|
||||
assertEquals(4, create()
|
||||
.selectFrom(T_BOOK)
|
||||
.option("OPTION(OPTIMIZE FOR UNKNOWN)")
|
||||
.fetch()
|
||||
.size());
|
||||
}
|
||||
}
|
||||
|
||||
@ -95,7 +95,7 @@ import org.jooq.api.annotation.Transition;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@State
|
||||
public interface SelectForUpdateStep<R extends Record> extends SelectFinalStep<R> {
|
||||
public interface SelectForUpdateStep<R extends Record> extends SelectOptionStep<R> {
|
||||
|
||||
/**
|
||||
* Add a <code>FOR UPDATE</code> clause to the end of the query.
|
||||
@ -125,6 +125,6 @@ public interface SelectForUpdateStep<R extends Record> extends SelectFinalStep<R
|
||||
@Transition(
|
||||
name = "FOR SHARE"
|
||||
)
|
||||
SelectFinalStep<R> forShare();
|
||||
SelectOptionStep<R> forShare();
|
||||
|
||||
}
|
||||
|
||||
@ -84,7 +84,7 @@ import org.jooq.api.annotation.Transition;
|
||||
* @author Lukas Eder
|
||||
*/
|
||||
@State
|
||||
public interface SelectForUpdateWaitStep<R extends Record> extends SelectFinalStep<R> {
|
||||
public interface SelectForUpdateWaitStep<R extends Record> extends SelectOptionStep<R> {
|
||||
|
||||
/**
|
||||
* Add a <code>WAIT</code> clause to the <code>FOR UPDATE</code> clause at
|
||||
@ -99,7 +99,7 @@ public interface SelectForUpdateWaitStep<R extends Record> extends SelectFinalSt
|
||||
name = "WAIT",
|
||||
args = "Integer"
|
||||
)
|
||||
SelectFinalStep<R> wait(int seconds);
|
||||
SelectOptionStep<R> wait(int seconds);
|
||||
|
||||
/**
|
||||
* Add a <code>NOWAIT</code> clause to the <code>FOR UPDATE</code> clause at
|
||||
@ -111,7 +111,7 @@ public interface SelectForUpdateWaitStep<R extends Record> extends SelectFinalSt
|
||||
@Transition(
|
||||
name = "NOWAIT"
|
||||
)
|
||||
SelectFinalStep<R> noWait();
|
||||
SelectOptionStep<R> noWait();
|
||||
|
||||
/**
|
||||
* Add a <code>WAIT</code> clause to the <code>FOR UPDATE</code> clause at
|
||||
@ -124,5 +124,5 @@ public interface SelectForUpdateWaitStep<R extends Record> extends SelectFinalSt
|
||||
@Transition(
|
||||
name = "SKIP LOCKED"
|
||||
)
|
||||
SelectFinalStep<R> skipLocked();
|
||||
SelectOptionStep<R> skipLocked();
|
||||
}
|
||||
|
||||
116
jOOQ/src/main/java/org/jooq/SelectOptionStep.java
Normal file
116
jOOQ/src/main/java/org/jooq/SelectOptionStep.java
Normal file
@ -0,0 +1,116 @@
|
||||
/**
|
||||
* Copyright (c) 2009-2013, 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 org.jooq.api.annotation.State;
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
@State
|
||||
public interface SelectOptionStep<R extends Record> extends SelectFinalStep<R> {
|
||||
|
||||
/**
|
||||
* Add a SQL Server-style query hint to the select clause.
|
||||
* <p>
|
||||
* Example: <code><pre>
|
||||
* DSLContext create = DSL.using(configuration);
|
||||
*
|
||||
* create.select(field1, field2)
|
||||
* .from(table1)
|
||||
* .option("OPTION (OPTIMIZE FOR UNKNOWN)")
|
||||
* .execute();
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* You can also use this clause for any other database, that accepts hints
|
||||
* or options at the same syntactic location, e.g. for DB2's isolation clause: <code><pre>
|
||||
* create.select(field1, field2)
|
||||
* .from(table1)
|
||||
* .option("WITH RR USE AND KEEP EXCLUSIVE LOCKS")
|
||||
* .execute();
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* The outcome of such a query is this: <code><pre>
|
||||
* SELECT field1, field2 FROM table1 [option]
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* For SQL Server style table hints, see {@link Table#with(String)}
|
||||
*
|
||||
* @see Table#with(String)
|
||||
* @see SelectQuery#addOption(String)
|
||||
*/
|
||||
@Support
|
||||
SelectFinalStep<R> option(String string);
|
||||
}
|
||||
@ -264,7 +264,7 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
void addHaving(Operator operator, Collection<Condition> conditions);
|
||||
|
||||
/**
|
||||
* Add an Oracle-style hint to the select clause
|
||||
* Add an Oracle-style hint to the select clause.
|
||||
* <p>
|
||||
* Example: <code><pre>
|
||||
* DSLContext create = DSL.using(configuration);
|
||||
@ -295,6 +295,37 @@ public interface SelectQuery<R extends Record> extends Select<R>, ConditionProvi
|
||||
@Support
|
||||
void addHint(String hint);
|
||||
|
||||
/**
|
||||
* Add a SQL Server-style query hint to the select clause.
|
||||
* <p>
|
||||
* Example: <code><pre>
|
||||
* DSLContext create = DSL.using(configuration);
|
||||
*
|
||||
* create.select(field1, field2)
|
||||
* .from(table1)
|
||||
* .option("OPTION (OPTIMIZE FOR UNKNOWN)")
|
||||
* .execute();
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* You can also use this clause for any other database, that accepts hints
|
||||
* or options at the same syntactic location, e.g. for DB2's isolation clause: <code><pre>
|
||||
* create.select(field1, field2)
|
||||
* .from(table1)
|
||||
* .option("WITH RR USE AND KEEP EXCLUSIVE LOCKS")
|
||||
* .execute();
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* The outcome of such a query is this: <code><pre>
|
||||
* SELECT field1, field2 FROM table1 [option]
|
||||
* </pre></code>
|
||||
* <p>
|
||||
* For SQL Server style table hints, see {@link Table#with(String)}
|
||||
*
|
||||
* @see Table#with(String)
|
||||
*/
|
||||
@Support
|
||||
void addOption(String option);
|
||||
|
||||
/**
|
||||
* Add an Oracle-specific <code>CONNECT BY</code> clause to the query
|
||||
*/
|
||||
|
||||
@ -186,6 +186,12 @@ class SelectImpl<R extends Record> extends AbstractDelegatingQuery<Select<R>> im
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl<R> option(String hint) {
|
||||
getQuery().addOption(hint);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final SelectImpl<R> from(TableLike<?>... tables) {
|
||||
getQuery().addFrom(tables);
|
||||
|
||||
@ -98,6 +98,7 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> implements Sel
|
||||
|
||||
private final SelectFieldList select;
|
||||
private String hint;
|
||||
private String option;
|
||||
private boolean distinct;
|
||||
private boolean forUpdate;
|
||||
private final QueryPartList<Field<?>> forUpdateOf;
|
||||
@ -310,6 +311,14 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> implements Sel
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// [#1952] SQL Server OPTION() clauses as well as many other optional
|
||||
// end-of-query clauses are appended to the end of a query
|
||||
if (!StringUtils.isBlank(option)) {
|
||||
context.formatSeparator()
|
||||
.sql(option);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@ -905,6 +914,10 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> implements Sel
|
||||
this.hint = hint;
|
||||
}
|
||||
|
||||
final void setOption(String option) {
|
||||
this.option = option;
|
||||
}
|
||||
|
||||
@Override
|
||||
final boolean isForUpdate() {
|
||||
return forUpdate;
|
||||
@ -1184,6 +1197,11 @@ class SelectQueryImpl<R extends Record> extends AbstractSelect<R> implements Sel
|
||||
setHint(h);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void addOption(String o) {
|
||||
setOption(o);
|
||||
}
|
||||
|
||||
// -------------------------------------------------------------------------
|
||||
// Utility classes
|
||||
// -------------------------------------------------------------------------
|
||||
|
||||
Loading…
Reference in New Issue
Block a user