Repository: ignite Updated Branches: refs/heads/master 8fd4f747d -> 7b28da729
IGNITE-4642: Added "enforceJoinOrder" and "lazy" flags to thick JDBC driver. This closes #2446. Project: http://git-wip-us.apache.org/repos/asf/ignite/repo Commit: http://git-wip-us.apache.org/repos/asf/ignite/commit/7b28da72 Tree: http://git-wip-us.apache.org/repos/asf/ignite/tree/7b28da72 Diff: http://git-wip-us.apache.org/repos/asf/ignite/diff/7b28da72 Branch: refs/heads/master Commit: 7b28da72953bd561cc559dd4fff52269abc4e11e Parents: 8fd4f74 Author: tledkov-gridgain <[email protected]> Authored: Tue Aug 29 17:18:15 2017 +0300 Committer: devozerov <[email protected]> Committed: Tue Aug 29 17:18:15 2017 +0300 ---------------------------------------------------------------------- .../internal/jdbc2/JdbcConnectionSelfTest.java | 36 +++++++ .../org/apache/ignite/IgniteJdbcDriver.java | 31 ++++++ .../ignite/internal/jdbc2/JdbcConnection.java | 24 +++++ .../ignite/internal/jdbc2/JdbcQueryTask.java | 16 +++ .../ignite/internal/jdbc2/JdbcQueryTaskV2.java | 107 +++++++++++++++++++ .../ignite/internal/jdbc2/JdbcResultSet.java | 11 +- .../ignite/internal/jdbc2/JdbcStatement.java | 16 +-- 7 files changed, 230 insertions(+), 11 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcConnectionSelfTest.java ---------------------------------------------------------------------- diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcConnectionSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcConnectionSelfTest.java index bd5c8e9..aeb7c76 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcConnectionSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcConnectionSelfTest.java @@ -304,4 +304,40 @@ public class JdbcConnectionSelfTest extends GridCommonAbstractTest { conn.rollback(); } } + + /** + * @throws Exception If failed. + */ + public void testSqlHints() throws Exception { + try (final Connection conn = DriverManager.getConnection(CFG_URL_PREFIX + "enforceJoinOrder=true@" + + configURL())) { + assertTrue(((JdbcConnection)conn).isEnforceJoinOrder()); + assertFalse(((JdbcConnection)conn).isDistributedJoins()); + assertFalse(((JdbcConnection)conn).isCollocatedQuery()); + assertFalse(((JdbcConnection)conn).isLazy()); + } + + try (final Connection conn = DriverManager.getConnection(CFG_URL_PREFIX + "distributedJoins=true@" + + configURL())) { + assertFalse(((JdbcConnection)conn).isEnforceJoinOrder()); + assertTrue(((JdbcConnection)conn).isDistributedJoins()); + assertFalse(((JdbcConnection)conn).isCollocatedQuery()); + assertFalse(((JdbcConnection)conn).isLazy()); + } + + try (final Connection conn = DriverManager.getConnection(CFG_URL_PREFIX + "collocated=true@" + + configURL())) { + assertFalse(((JdbcConnection)conn).isEnforceJoinOrder()); + assertFalse(((JdbcConnection)conn).isDistributedJoins()); + assertTrue(((JdbcConnection)conn).isCollocatedQuery()); + assertFalse(((JdbcConnection)conn).isLazy()); + } + + try (final Connection conn = DriverManager.getConnection(CFG_URL_PREFIX + "lazy=true@" + configURL())) { + assertFalse(((JdbcConnection)conn).isEnforceJoinOrder()); + assertFalse(((JdbcConnection)conn).isDistributedJoins()); + assertFalse(((JdbcConnection)conn).isCollocatedQuery()); + assertTrue(((JdbcConnection)conn).isLazy()); + } + } } http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java index 47fe982..f519589 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java @@ -30,6 +30,7 @@ import java.util.logging.Logger; import org.apache.ignite.cache.affinity.AffinityKey; import org.apache.ignite.internal.jdbc.JdbcConnection; import org.apache.ignite.internal.jdbc.JdbcDriverPropertyInfo; +import org.apache.ignite.internal.jdbc.thin.JdbcThinUtils; import org.apache.ignite.logger.java.JavaLogger; /** @@ -110,6 +111,22 @@ import org.apache.ignite.logger.java.JavaLogger; * combination with {@code local} and/or {@code collocated} flags with {@code true} value or in case of querying * of local cache. Default value is {@code false}. * </li> + * <li> + * {@code enforceJoinOrder} - Sets flag to enforce join order of tables in the query. If set to {@code true} + * query optimizer will not reorder tables in join. By default is {@code false}. + * </li> + * <li> + * {@code lazy} - Sets flag to enable lazy query execution. + * By default Ignite attempts to fetch the whole query result set to memory and send it to the client. + * For small and medium result sets this provides optimal performance and minimize duration of internal + * database locks, thus increasing concurrency. + * + * <p> If result set is too big to fit in available memory this could lead to excessive GC pauses and even + * OutOfMemoryError. Use this flag as a hint for Ignite to fetch result set lazily, thus minimizing memory + * consumption at the cost of moderate performance hit. + * + * <p> Defaults to {@code false}, meaning that the whole result set is fetched to memory eagerly. + * </li> * </ul> * * <h2 class="header">Configuration of Ignite Java client based connection</h2> @@ -287,6 +304,12 @@ public class IgniteJdbcDriver implements Driver { /** Collocated parameter name. */ private static final String PARAM_COLLOCATED = "collocated"; + /** Parameter: enforce join order flag. */ + public static final String PARAM_ENFORCE_JOIN_ORDER = "enforceJoinOrder"; + + /** Parameter: lazy query execution flag. */ + public static final String PARAM_LAZY = "lazy"; + /** Distributed joins parameter name. */ private static final String PARAM_DISTRIBUTED_JOINS = "distributedJoins"; @@ -329,6 +352,12 @@ public class IgniteJdbcDriver implements Driver { /** Distributed joins property name. */ public static final String PROP_DISTRIBUTED_JOINS = PROP_PREFIX + PARAM_DISTRIBUTED_JOINS; + /** Enforce join order property name. */ + public static final String PROP_ENFORCE_JOIN_ORDER = PROP_PREFIX + PARAM_ENFORCE_JOIN_ORDER; + + /** Lazy query execution property name. */ + public static final String PROP_LAZY = PROP_PREFIX + PARAM_LAZY; + /** Transactions allowed property name. */ public static final String PROP_TX_ALLOWED = PROP_PREFIX + PARAM_TX_ALLOWED; @@ -416,6 +445,8 @@ public class IgniteJdbcDriver implements Driver { new JdbcDriverPropertyInfo("Local", info.getProperty(PROP_LOCAL), ""), new JdbcDriverPropertyInfo("Collocated", info.getProperty(PROP_COLLOCATED), ""), new JdbcDriverPropertyInfo("Distributed Joins", info.getProperty(PROP_DISTRIBUTED_JOINS), ""), + new JdbcDriverPropertyInfo("Enforce Join Order", info.getProperty(JdbcThinUtils.PROP_ENFORCE_JOIN_ORDER), ""), + new JdbcDriverPropertyInfo("Lazy query execution", info.getProperty(JdbcThinUtils.PROP_LAZY), ""), new JdbcDriverPropertyInfo("Transactions Allowed", info.getProperty(PROP_TX_ALLOWED), "") ); http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java index dd0ec08..1c37fe2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcConnection.java @@ -77,6 +77,8 @@ import static org.apache.ignite.IgniteJdbcDriver.PROP_CACHE; import static org.apache.ignite.IgniteJdbcDriver.PROP_CFG; import static org.apache.ignite.IgniteJdbcDriver.PROP_COLLOCATED; import static org.apache.ignite.IgniteJdbcDriver.PROP_DISTRIBUTED_JOINS; +import static org.apache.ignite.IgniteJdbcDriver.PROP_ENFORCE_JOIN_ORDER; +import static org.apache.ignite.IgniteJdbcDriver.PROP_LAZY; import static org.apache.ignite.IgniteJdbcDriver.PROP_LOCAL; import static org.apache.ignite.IgniteJdbcDriver.PROP_NODE_ID; import static org.apache.ignite.IgniteJdbcDriver.PROP_TX_ALLOWED; @@ -133,6 +135,12 @@ public class JdbcConnection implements Connection { /** Distributed joins flag. */ private boolean distributedJoins; + /** Enforced join order flag. */ + private boolean enforceJoinOrder; + + /** Lazy query execution flag. */ + private boolean lazy; + /** Transactions allowed flag. */ private boolean txAllowed; @@ -175,6 +183,8 @@ public class JdbcConnection implements Connection { locQry = Boolean.parseBoolean(props.getProperty(PROP_LOCAL)); collocatedQry = Boolean.parseBoolean(props.getProperty(PROP_COLLOCATED)); distributedJoins = Boolean.parseBoolean(props.getProperty(PROP_DISTRIBUTED_JOINS)); + enforceJoinOrder = Boolean.parseBoolean(props.getProperty(PROP_ENFORCE_JOIN_ORDER)); + lazy = Boolean.parseBoolean(props.getProperty(PROP_LAZY)); txAllowed = Boolean.parseBoolean(props.getProperty(PROP_TX_ALLOWED)); stream = Boolean.parseBoolean(props.getProperty(PROP_STREAMING)); @@ -843,6 +853,20 @@ public class JdbcConnection implements Connection { } /** + * @return Enforce join order flag. + */ + boolean isEnforceJoinOrder() { + return enforceJoinOrder; + } + + /** + * @return Lazy query execution flag. + */ + boolean isLazy() { + return lazy; + } + + /** * Ensures that connection is not closed. * * @throws SQLException If connection is closed. http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java index 7ae6ea2..4854129 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTask.java @@ -164,6 +164,8 @@ class JdbcQueryTask implements IgniteCallable<JdbcQueryTask.QueryResult> { qry.setLocal(locQry); qry.setCollocated(collocatedQry); qry.setDistributedJoins(distributedJoins); + qry.setEnforceJoinOrder(enforceJoinOrder()); + qry.setLazy(lazy()); qry.setSchema(schemaName); QueryCursorImpl<List<?>> qryCursor = (QueryCursorImpl<List<?>>)cache.withKeepBinary().query(qry); @@ -217,6 +219,20 @@ class JdbcQueryTask implements IgniteCallable<JdbcQueryTask.QueryResult> { } /** + * @return Enforce join order flag (SQL hit). + */ + protected boolean enforceJoinOrder() { + return false; + } + + /** + * @return Lazy query execution flag (SQL hit). + */ + protected boolean lazy() { + return false; + } + + /** * Schedules removal of stored cursor in case of remote query execution. * * @param uuid Cursor UUID. http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV2.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV2.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV2.java new file mode 100644 index 0000000..abb9954 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV2.java @@ -0,0 +1,107 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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. + */ + +package org.apache.ignite.internal.jdbc2; + +import java.util.UUID; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteJdbcDriver; +import org.apache.ignite.IgniteSystemProperties; + +/** + * Task for SQL queries execution through {@link IgniteJdbcDriver}. + * <p> + * Not closed cursors will be removed after {@link #RMV_DELAY} milliseconds. + * This parameter can be configured via {@link IgniteSystemProperties#IGNITE_JDBC_DRIVER_CURSOR_REMOVE_DELAY} + * system property. + */ +class JdbcQueryTaskV2 extends JdbcQueryTask { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Enforce join order flag. */ + private final boolean enforceJoinOrder; + + /** Lazy query execution flag. */ + private final boolean lazy; + + /** + * @param ignite Ignite. + * @param cacheName Cache name. + * @param schemaName Schema name. + * @param sql Sql query. + * @param isQry Operation type flag - query or not - to enforce query type check. + * @param loc Local execution flag. + * @param args Args. + * @param fetchSize Fetch size. + * @param uuid UUID. + * @param locQry Local query flag. + * @param collocatedQry Collocated query flag. + * @param distributedJoins Distributed joins flag. + * @param enforceJoinOrder Enforce joins order falg. + * @param lazy Lazy query execution flag. + */ + public JdbcQueryTaskV2(Ignite ignite, String cacheName, String schemaName, String sql, Boolean isQry, boolean loc, + Object[] args, int fetchSize, UUID uuid, boolean locQry, boolean collocatedQry, boolean distributedJoins, + boolean enforceJoinOrder, boolean lazy) { + super(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, uuid, locQry, + collocatedQry, distributedJoins); + + this.enforceJoinOrder = enforceJoinOrder; + this.lazy = lazy; + } + + /** {@inheritDoc} */ + @Override protected boolean enforceJoinOrder() { + return enforceJoinOrder; + } + + /** {@inheritDoc} */ + @Override protected boolean lazy() { + return lazy; + } + + /** + * @param ignite Ignite. + * @param cacheName Cache name. + * @param schemaName Schema name. + * @param sql Sql query. + * @param isQry Operation type flag - query or not - to enforce query type check. + * @param loc Local execution flag. + * @param args Args. + * @param fetchSize Fetch size. + * @param uuid UUID. + * @param locQry Local query flag. + * @param collocatedQry Collocated query flag. + * @param distributedJoins Distributed joins flag. + * @param enforceJoinOrder Enforce joins order falg. + * @param lazy Lazy query execution flag. + * @return Appropriate task JdbcQueryTask or JdbcQueryTaskV2. + */ + public static JdbcQueryTask createTask(Ignite ignite, String cacheName, String schemaName, String sql, + Boolean isQry, boolean loc, Object[] args, int fetchSize, UUID uuid, boolean locQry, + boolean collocatedQry, boolean distributedJoins, + boolean enforceJoinOrder, boolean lazy) { + + if (enforceJoinOrder || lazy) + return new JdbcQueryTaskV2(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, + uuid, locQry, collocatedQry, distributedJoins, enforceJoinOrder, lazy); + else + return new JdbcQueryTask(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, + uuid, locQry, collocatedQry, distributedJoins); + } +} \ No newline at end of file http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java index 01c6386..baddb88 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcResultSet.java @@ -97,6 +97,7 @@ public class JdbcResultSet implements ResultSet { * @param cols Column names. * @param types Types. * @param fields Fields. + * @param finished Result set finished flag (the last result set). */ JdbcResultSet(@Nullable UUID uuid, JdbcStatement stmt, List<String> tbls, List<String> cols, List<String> types, Collection<List<?>> fields, boolean finished) { @@ -146,9 +147,9 @@ public class JdbcResultSet implements ResultSet { boolean loc = nodeId == null; // Connections from new clients send queries with new tasks, so we have to continue in the same manner - JdbcQueryTask qryTask = new JdbcQueryTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), null, - true, loc, null, fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), - conn.isDistributedJoins()); + JdbcQueryTask qryTask = JdbcQueryTaskV2.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), + null,true, loc, null, fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { JdbcQueryTask.QueryResult res = @@ -184,11 +185,11 @@ public class JdbcResultSet implements ResultSet { /** * Marks result set as closed. * If this result set is associated with locally executed query then query cursor will also closed. + * @throws SQLException On error. */ void closeInternal() throws SQLException { - if (((JdbcConnection)stmt.getConnection()).nodeId() == null && uuid != null) { + if (((JdbcConnection)stmt.getConnection()).nodeId() == null && uuid != null) JdbcQueryTask.remove(uuid); - } closed = true; } http://git-wip-us.apache.org/repos/asf/ignite/blob/7b28da72/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java ---------------------------------------------------------------------- diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java index 19c20a3..4e05db4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatement.java @@ -108,8 +108,9 @@ public class JdbcStatement implements Statement { boolean loc = nodeId == null; - JdbcQueryTask qryTask = new JdbcQueryTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), sql, true, - loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), conn.isDistributedJoins()); + JdbcQueryTask qryTask = JdbcQueryTaskV2.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), + sql, true, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { JdbcQueryTask.QueryResult res = @@ -165,8 +166,9 @@ public class JdbcStatement implements Statement { if (!conn.isDmlSupported()) throw new SQLException("Failed to query Ignite: DML operations are supported in versions 1.8.0 and newer"); - JdbcQueryTask qryTask = new JdbcQueryTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), sql, false, - loc, args, fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), conn.isDistributedJoins()); + JdbcQueryTask qryTask = JdbcQueryTaskV2.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), + sql, false, loc, args, fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { JdbcQueryTask.QueryResult qryRes = @@ -219,6 +221,7 @@ public class JdbcStatement implements Statement { /** * Marks statement as closed and closes all result sets. + * @throws SQLException On error. */ void closeInternal() throws SQLException { for (Iterator<JdbcResultSet> it = resSets.iterator(); it.hasNext(); ) { @@ -332,8 +335,9 @@ public class JdbcStatement implements Statement { boolean loc = nodeId == null; - JdbcQueryTask qryTask = new JdbcQueryTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), sql, null, - loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), conn.isDistributedJoins()); + JdbcQueryTask qryTask = JdbcQueryTaskV2.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), + sql, null, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { JdbcQueryTask.QueryResult res =
