diff --git a/jOOQ-test/src/main/resources/org/jooq/test/mysql/create.sql b/jOOQ-test/src/main/resources/org/jooq/test/mysql/create.sql index dff532741e..b0c532ce54 100644 --- a/jOOQ-test/src/main/resources/org/jooq/test/mysql/create.sql +++ b/jOOQ-test/src/main/resources/org/jooq/test/mysql/create.sql @@ -211,6 +211,12 @@ CREATE TABLE t_book ( COMMENT = 'An entity holding books'; / +CREATE INDEX i_book_a ON t_book(author_id) +/ + +CREATE INDEX i_book_b ON t_book(language_id) +/ + CREATE TABLE t_book_store ( name VARCHAR(400) NOT NULL COMMENT 'The books store name', @@ -390,10 +396,10 @@ END / CREATE PROCEDURE p2412( - In p_in_1 integer, + In p_in_1 integer, p_in_2 integer, - Out p_out_1 decimal(12,2), - out p_out_2 decimal(12,2), + Out p_out_1 decimal(12,2), + out p_out_2 decimal(12,2), InOut p_in_out decimal(12,2)) BEGIN SET p_out_1 = 0; diff --git a/jOOQ-test/src/test/java/org/jooq/test/MySQLTest.java b/jOOQ-test/src/test/java/org/jooq/test/MySQLTest.java index db140a9ed4..76f48a54ba 100644 --- a/jOOQ-test/src/test/java/org/jooq/test/MySQLTest.java +++ b/jOOQ-test/src/test/java/org/jooq/test/MySQLTest.java @@ -920,4 +920,26 @@ public class MySQLTest extends jOOQAbstractTest< assertEquals(1, (int) Routines.fp1908_FUNCTION(create().configuration(), 1)); assertEquals(2, (int) Routines.fp1908_PROCEDURE(create().configuration(), 1)); } + + @Test + public void testMySQLIndexHints() throws Exception { + assertEquals(4, create().selectFrom(TBook().useIndex("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().useIndexForJoin("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().useIndexForOrderBy("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().useIndexForGroupBy("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().forceIndex("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().forceIndexForJoin("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().forceIndexForOrderBy("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().forceIndexForGroupBy("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().ignoreIndex("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().ignoreIndexForJoin("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().ignoreIndexForOrderBy("i_book_a", "i_book_b")).fetch().size()); + assertEquals(4, create().selectFrom(TBook().ignoreIndexForGroupBy("i_book_a", "i_book_b")).fetch().size()); + + // Combine random hints + assertEquals(4, create().selectFrom( + TBook().useIndexForGroupBy("i_book_a") + .useIndexForJoin("i_book_b") + .ignoreIndexForOrderBy("i_book_a")).fetch().size()); + } } diff --git a/jOOQ/src/main/java/org/jooq/Table.java b/jOOQ/src/main/java/org/jooq/Table.java index 94e71b3384..7828858a7a 100644 --- a/jOOQ/src/main/java/org/jooq/Table.java +++ b/jOOQ/src/main/java/org/jooq/Table.java @@ -852,9 +852,213 @@ public interface Table extends TableLike { // XXX: Exotic and vendor-specific clauses on tables // ------------------------------------------------------------------------- + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndex("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table useIndex(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForJoin("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table useIndexForJoin(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForOrderBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table useIndexForOrderBy(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForGroupBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table useIndexForGroupBy(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndex("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table ignoreIndex(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForJoin("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table ignoreIndexForJoin(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForOrderBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table ignoreIndexForOrderBy(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForGroupBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table ignoreIndexForGroupBy(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndex("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table forceIndex(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForJoin("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table forceIndexForJoin(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForOrderBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table forceIndexForOrderBy(String... indexes); + + /** + * Specify a MySQL style table hint for query optimisation. + *

+ * Example: + *

+ *

+     * create.select()
+     *       .from(BOOK.as("b").useIndexForGroupBy("MY_INDEX")
+     *       .fetch();
+     * 
+ * + * @see http://dev.mysql.com/doc/refman/5.7/en/index-hints.html + */ + @Support({ MARIADB, MYSQL }) + Table forceIndexForGroupBy(String... indexes); + /* [pro] xx xxx - x xxxxxxx x xxx xxxxxx xxxxx xxxxx xxxx xxx xxxxx xxxxxxxxxxxx + x xxxxxxx x xxx xxxxxx xxxxx xxxxx xxxx xxx xxxxx xxxxxxxxxxxxx x xxx x xxxx xxxxx xxxxx xxxx xx xx xxxxxx xxxxxxxx xxxxx xx xxxxx xxx xx xxxxx x xxxxxxxx xxxxx xxxxxxxx @@ -880,7 +1084,7 @@ public interface Table extends TableLike { xxx x xxxxxx x xxx xxxxxxxxxxxxxxxxxx xxxxxxxxx xxxx xxxx xxxxxx xxxxxxxx xx - x xxxx xxxxxxx xxxx + x xxxx xxxxxxx xxxxx x xxx x xxxx xxx xxxx xxxxxxxx xx xxxx xxxx x xxxx @@ -898,7 +1102,7 @@ public interface Table extends TableLike { xxx x xxxxxx x xxx xxxxxxxxxxxxxxxxxx xxxxxxxxx xxxx xxxx xxxxxx xxxxxxxx xx - x xxxx xxxxxxx xxxx + x xxxx xxxxxxx xxxxx x xxx x xxx xxxx xxxxxxxx xxx xxxxxx xxxxxxxxxxxxxxxxx x diff --git a/jOOQ/src/main/java/org/jooq/impl/AbstractTable.java b/jOOQ/src/main/java/org/jooq/impl/AbstractTable.java index 3c5c307ef6..c8e9157fba 100644 --- a/jOOQ/src/main/java/org/jooq/impl/AbstractTable.java +++ b/jOOQ/src/main/java/org/jooq/impl/AbstractTable.java @@ -352,11 +352,71 @@ abstract class AbstractTable extends AbstractQueryPart impleme return tableField; } - /* [pro] xx - xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx - xx xxxx xxxxx xxx - xx xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + // ------------------------------------------------------------------------ + // XXX: Other API + // ------------------------------------------------------------------------ + @Override + public final Table useIndex(String... indexes) { + return new HintedTable(this, "use index", indexes); + } + + @Override + public final Table useIndexForJoin(String... indexes) { + return new HintedTable(this, "use index for join", indexes); + } + + @Override + public final Table useIndexForOrderBy(String... indexes) { + return new HintedTable(this, "use index for order by", indexes); + } + + @Override + public final Table useIndexForGroupBy(String... indexes) { + return new HintedTable(this, "use index for group by", indexes); + } + + @Override + public final Table ignoreIndex(String... indexes) { + return new HintedTable(this, "ignore index", indexes); + } + + @Override + public final Table ignoreIndexForJoin(String... indexes) { + return new HintedTable(this, "ignore index for join", indexes); + } + + @Override + public final Table ignoreIndexForOrderBy(String... indexes) { + return new HintedTable(this, "ignore index for order by", indexes); + } + + @Override + public final Table ignoreIndexForGroupBy(String... indexes) { + return new HintedTable(this, "ignore index for group by", indexes); + } + + @Override + public final Table forceIndex(String... indexes) { + return new HintedTable(this, "force index", indexes); + } + + @Override + public final Table forceIndexForJoin(String... indexes) { + return new HintedTable(this, "force index for join", indexes); + } + + @Override + public final Table forceIndexForOrderBy(String... indexes) { + return new HintedTable(this, "force index for order by", indexes); + } + + @Override + public final Table forceIndexForGroupBy(String... indexes) { + return new HintedTable(this, "force index for group by", indexes); + } + + /* [pro] xx xxxxxxxxx xxxxxx xxxxx xxxxxxxx xxxxxxxxxxx xxxxx x xxxxxx xxx xxxxxxxxxxxxxxxxxx xxxxxx diff --git a/jOOQ/src/main/java/org/jooq/impl/HintedTable.java b/jOOQ/src/main/java/org/jooq/impl/HintedTable.java new file mode 100644 index 0000000000..591ea05a56 --- /dev/null +++ b/jOOQ/src/main/java/org/jooq/impl/HintedTable.java @@ -0,0 +1,106 @@ +/** + * Copyright (c) 2009-2014, 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 org.jooq.Context; +import org.jooq.Name; +import org.jooq.Record; +import org.jooq.Table; + +/** + * @author Lukas Eder + */ +class HintedTable extends AbstractTable { + + /** + * Generated UID + */ + private static final long serialVersionUID = -3905775637768497535L; + + private final AbstractTable delegate; + private final String keywords; + private final QueryPartList arguments; + + HintedTable(AbstractTable delegate, String keywords, String... arguments) { + this(delegate, keywords, new QueryPartList(Utils.names(arguments))); + } + + HintedTable(AbstractTable delegate, String keywords, QueryPartList arguments) { + super(delegate.getName(), delegate.getSchema()); + + this.delegate = delegate; + this.keywords = keywords; + this.arguments = arguments; + } + + @Override + public final boolean declaresTables() { + return true; + } + + @Override + public final void accept(Context ctx) { + ctx.visit(delegate) + .sql(" ").keyword(keywords) + .sql(" (").visit(arguments) + .sql(")"); + } + + @Override + public final Class getRecordType() { + return delegate.getRecordType(); + } + + @Override + public final Table as(String alias) { + return new HintedTable(new TableAlias(delegate, alias), keywords, arguments); + } + + @Override + public final Table as(String alias, String... fieldAliases) { + return new HintedTable(new TableAlias(delegate, alias, fieldAliases), keywords, arguments); + } + + @Override + final Fields fields0() { + return delegate.fields0(); + } +} diff --git a/jOOQ/src/main/java/org/jooq/impl/Utils.java b/jOOQ/src/main/java/org/jooq/impl/Utils.java index fd7eeab696..78f18e61fa 100644 --- a/jOOQ/src/main/java/org/jooq/impl/Utils.java +++ b/jOOQ/src/main/java/org/jooq/impl/Utils.java @@ -117,6 +117,7 @@ import org.jooq.EnumType; import org.jooq.ExecuteContext; import org.jooq.ExecuteListener; import org.jooq.Field; +import org.jooq.Name; import org.jooq.Param; import org.jooq.QueryPart; import org.jooq.Record; @@ -655,6 +656,15 @@ final class Utils { return result; } + static final Name[] names(String[] names) { + Name[] result = new Name[names.length]; + + for (int i = 0; i < names.length; i++) + result[i] = DSL.name(names[i]); + + return result; + } + /** * Be sure that a given object is a field. *