From f4c6603799c8752c6ee1ef13c697348fa36f9761 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 4 Sep 2017 11:31:28 +0300 Subject: [PATCH 01/36] IGNITE-6046: prototype of execution SQL query with multiple SQL statements --- .../ignite/cache/query/SqlFieldsQuery.java | 18 ++++ .../processors/query/GridQueryIndexing.java | 9 ++ .../processors/query/GridQueryProcessor.java | 65 +++++++++++++ .../query/MultipleStatementsQuery.java | 54 +++++++++++ ...niteClientCacheInitializationFailTest.java | 6 ++ .../processors/query/h2/IgniteH2Indexing.java | 58 ++++++++++++ .../query/h2/sql/GridSqlQueryParser.java | 81 +++++++++++++++++ .../MultipleStatementsSqlQuerySelfTest.java | 91 +++++++++++++++++++ 8 files changed, 382 insertions(+) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java create mode 100644 modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java diff --git a/modules/core/src/main/java/org/apache/ignite/cache/query/SqlFieldsQuery.java b/modules/core/src/main/java/org/apache/ignite/cache/query/SqlFieldsQuery.java index 54f839691b448..2d128d158b9fb 100644 --- a/modules/core/src/main/java/org/apache/ignite/cache/query/SqlFieldsQuery.java +++ b/modules/core/src/main/java/org/apache/ignite/cache/query/SqlFieldsQuery.java @@ -80,6 +80,24 @@ public class SqlFieldsQuery extends Query> { /** Schema. */ private String schema; + /** + * Copy constructs SQL fields query. + * + * @param qry SQL query. + */ + public SqlFieldsQuery(SqlFieldsQuery qry) { + sql = qry.sql; + args = qry.args; + collocated = qry.collocated; + timeout = qry.timeout; + enforceJoinOrder = qry.enforceJoinOrder; + distributedJoins = qry.distributedJoins; + replicatedOnly = qry.replicatedOnly; + lazy = qry.lazy; + parts = qry.parts; + schema = qry.schema; + } + /** * Constructs SQL fields query. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 8eecfc21a4bdd..d6c2f005a9779 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -295,4 +295,13 @@ public void remove(String cacheName, GridQueryTypeDescriptor type, KeyCacheObjec * @return {@code True} if insert. */ public boolean isInsertStatement(PreparedStatement nativeStmt); + + /** + * Split multi-statements SQL query to the first statement and remaining SQL query string. + * + * @param schema Schema. + * @param qry Query with multiple statements. + * @return List of queries. + */ + MultipleStatementsQuery splitSqlQuery(String schema, SqlFieldsQuery qry); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index d5ac8fcb39762..9926e07d9ee2d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1857,6 +1857,37 @@ public FieldsQueryCursor> querySqlFieldsNoCache(final SqlFieldsQuery qry } } + /** + * @param qry Query. + * @param keepBinary Keep binary flag. + * @return List of queries. + */ + public QueryResult querySqlFieldsMultipleNoCache(final SqlFieldsQuery qry, final boolean keepBinary) { + checkxEnabled(); + + validateSqlFieldsQuery(qry); + + if (qry.isLocal()) + throw new IgniteException("Local query is not supported without specific cache."); + + if (qry.getSchema() == null) + qry.setSchema(QueryUtils.DFLT_SCHEMA); + + if (!busyLock.enterBusy()) + throw new IllegalStateException("Failed to execute query (grid is stopping)."); + + try { + MultipleStatementsQuery multQry = idx.splitSqlQuery(qry.getSchema(), qry); + + FieldsQueryCursor> cur = querySqlFieldsNoCache(multQry.first(), keepBinary); + + return new QueryResult(cur, multQry.remaining()); + } + finally { + busyLock.leaveBusy(); + } + } + /** * Validate SQL fields query. * @@ -2638,4 +2669,38 @@ public void manager(SchemaOperationManager mgr) { this.mgr = mgr; } } + + /** + * + */ + public static class QueryResult { + /** Cursor. */ + private FieldsQueryCursor> cur; + + /** Remaining query. */ + private SqlFieldsQuery remaining; + + /** + * @param cur Cursor. + * @param remaining Remaining query. + */ + public QueryResult(FieldsQueryCursor> cur, SqlFieldsQuery remaining) { + this.cur = cur; + this.remaining = remaining; + } + + /** + * @return Query cursor. + */ + public FieldsQueryCursor> cursor() { + return cur; + } + + /** + * @return Remaining query. + */ + public SqlFieldsQuery remaining() { + return remaining; + } + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java new file mode 100644 index 0000000000000..81f6021418057 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java @@ -0,0 +1,54 @@ +/* + * 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.processors.query; + +import org.apache.ignite.cache.query.SqlFieldsQuery; + +/** + * Multiple statement SQL query. + */ +public class MultipleStatementsQuery { + /** First statement. */ + private SqlFieldsQuery first; + + /** Remaining query. */ + private SqlFieldsQuery remaining; + + /** + * @param first Fisrt statement. + * @param remaining Remaining statement. + */ + public MultipleStatementsQuery(SqlFieldsQuery first, SqlFieldsQuery remaining) { + this.first = first; + this.remaining = remaining; + } + + /** + * @return The first query. + */ + public SqlFieldsQuery first() { + return first; + } + + /** + * @return Remaining query. + */ + public SqlFieldsQuery remaining() { + return remaining; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java index fa6dd707c5f35..031152a6a95bd 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java @@ -49,6 +49,7 @@ import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; +import org.apache.ignite.internal.processors.query.MultipleStatementsQuery; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor; import org.apache.ignite.internal.util.GridSpinBusyLock; @@ -362,5 +363,10 @@ private static class FailedIndexing implements GridQueryIndexing { @Override public boolean isInsertStatement(PreparedStatement nativeStmt) { return false; } + + /** {@inheritDoc} */ + @Override public MultipleStatementsQuery splitSqlQuery(String schema, SqlFieldsQuery qry) { + return null; + } } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 0f97a4ba1e975..26ec1b5cf550f 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -90,6 +90,7 @@ import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.query.MultipleStatementsQuery; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory; @@ -1256,6 +1257,63 @@ private Iterable> runQueryTwoStep( }; } + /** {@inheritDoc} */ + @Override public MultipleStatementsQuery splitSqlQuery(String schemaName, SqlFieldsQuery qry) { + String sqlQry = qry.getSql(); + + Connection c = connectionForSchema(schemaName); + + boolean cachesCreated = false; + + PreparedStatement stmt = null; + + // Loop for cache create + while (true) { + try { + // Do not cache this statement because the whole query object will be cached later on. + stmt = prepareStatement(c, sqlQry, false); + + break; + } + catch (SQLException e) { + if (!cachesCreated && ( + e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) + ) { + try { + ctx.cache().createMissingQueryCaches(); + } + catch (IgniteCheckedException ignored) { + throw new CacheException("Failed to create missing caches.", e); + } + + cachesCreated = true; + } + else + throw new IgniteSQLException("Failed to parse query: " + sqlQry, + IgniteQueryErrorCode.PARSING, e); + } + } + + GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt); + + SqlFieldsQuery first = new SqlFieldsQuery(qry); + first.setSql(prep.prepared().getSQL()); + // TODO: split parameters! + + SqlFieldsQuery remaining = null; + + if (prep.remainingSql() != null) { + remaining = new SqlFieldsQuery(qry); + + remaining.setSql(prep.remainingSql()); + // TODO: split parameters! + } + + return new MultipleStatementsQuery(first, remaining); + } + /** {@inheritDoc} */ @Override public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java index 0d6a0b2831281..376846303299e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQueryParser.java @@ -392,6 +392,29 @@ public class GridSqlQueryParser { /** */ private static final Getter COLUMN_CHECK_CONSTRAINT = getter(Column.class, "checkConstraint"); + /** Class for private class: 'org.h2.command.CommandList'. */ + private static final Class CLS_COMMAND_LIST; + + /** */ + private static final Getter LIST_COMMAND; + + /** */ + private static final Getter REMAINING; + + static { + try { + CLS_COMMAND_LIST = (Class)CommandContainer.class.getClassLoader() + .loadClass("org.h2.command.CommandList"); + + LIST_COMMAND = getter(CLS_COMMAND_LIST, "command"); + + REMAINING = getter(CLS_COMMAND_LIST, "remaining"); + } + catch (ClassNotFoundException e) { + throw new RuntimeException(e); + } + } + /** */ private static final String PARAM_NAME_VALUE_SEPARATOR = "="; @@ -443,6 +466,26 @@ public static Prepared prepared(PreparedStatement stmt) { return PREPARED.get(cmd); } + /** + * @param stmt Prepared statement. + * @return Parsed select. + */ + public static PreparedWithRemaining preparedWithRemaining(PreparedStatement stmt) { + Command cmd = COMMAND.get((JdbcPreparedStatement)stmt); + + if (cmd instanceof CommandContainer) + return new PreparedWithRemaining(PREPARED.get(cmd), null); + else { + Class cmdCls = cmd.getClass(); + + if (cmdCls.getName().equals("org.h2.command.CommandList")) { + return new PreparedWithRemaining(PREPARED.get(LIST_COMMAND.get(cmd)), REMAINING.get(cmd)); + } + else + throw new IgniteSQLException("Unexpected statement command"); + } + } + /** * @param qry Query expression to parse. * @return Subquery AST. @@ -1604,4 +1647,42 @@ public R get(T obj) { } } } + + /** + * + */ + public static class PreparedWithRemaining { + /** Prepared. */ + private Prepared prepared; + + /** Remaining sql. */ + private String remainingSql; + + /** + * @param prepared Prepared. + * @param sql Remaining SQL. + */ + public PreparedWithRemaining(Prepared prepared, String sql) { + this.prepared = prepared; + + if (sql != null) + sql = sql.trim(); + + remainingSql = !F.isEmpty(sql) ? sql : null; + } + + /** + * @return Prepared. + */ + public Prepared prepared() { + return prepared; + } + + /** + * @return Remaining SQL. + */ + public String remainingSql() { + return remainingSql; + } + } } \ No newline at end of file diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java new file mode 100644 index 0000000000000..9ca2a4721b3de --- /dev/null +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -0,0 +1,91 @@ +/* + * 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.processors.query; + +import java.util.List; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; + +/** + * Tests for schemas. + */ +public class MultipleStatementsSqlQuerySelfTest extends GridCommonAbstractTest { + /** Node. */ + private IgniteEx node; + + /** {@inheritDoc} */ + @Override protected void beforeTest() throws Exception { + node = (IgniteEx)startGrid(); + + startGrid(2); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + } + + /** + * Test query without caches. + * + * @throws Exception If failed. + */ + public void testQuery() throws Exception { + GridQueryProcessor qryProc = node.context().query(); + + SqlFieldsQuery qry = new SqlFieldsQuery( + "create table test(ID int primary key, NAME varchar(20)); " + + "insert into test (ID, NAME) values (1, 'name_1');" + + "insert into test (ID, NAME) values (2, 'name_2'), (3, 'name_3');" + + "select * from test;") + .setSchema("PUBLIC"); + + GridQueryProcessor.QueryResult res = qryProc.querySqlFieldsMultipleNoCache(qry, true); + + assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DDL statement is expected "; + + res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + + List> rows = res.cursor().getAll(); + + assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DML statement is expected"; + assert Long.valueOf(1).equals(rows.get(0).get(0)) : "1 row must be updated. [actual=" + rows.get(0).get(0) + ']'; + + res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + + assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DML statement is expected"; + assert Long.valueOf(2).equals(res.cursor().getAll().get(0).get(0)) : "2 row must be updated"; + + res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + + rows = res.cursor().getAll(); + + assert rows.size() == 3 : "Invalid rows count: " + rows.size(); + + for (int i = 0; i < rows.size(); ++i) { + assert Integer.valueOf(1).equals(rows.get(i).get(0)) + || Integer.valueOf(2).equals(rows.get(i).get(0)) + || Integer.valueOf(3).equals(rows.get(i).get(0)) + : "Invalid ID: " + rows.get(i).get(0); + } + + assert res.remaining() == null : "No more results expected"; + } +} From f43bb01dee136f4e59b6b17ccd6877555aaedab9 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 4 Sep 2017 16:03:53 +0300 Subject: [PATCH 02/36] IGNITE-6046: prototype of execution SQL query with multiple SQL statements --- .../processors/query/GridQueryIndexing.java | 23 +- .../processors/query/GridQueryProcessor.java | 53 +--- .../query/MultipleStatementsQuery.java | 54 ---- ...niteClientCacheInitializationFailTest.java | 10 +- .../query/h2/DmlStatementsProcessor.java | 28 +- .../processors/query/h2/IgniteH2Indexing.java | 241 +++++++++++++++--- .../query/h2/ddl/DdlStatementsProcessor.java | 7 +- .../query/h2/sql/GridSqlQuerySplitter.java | 16 +- .../MultipleStatementsSqlQuerySelfTest.java | 67 ++++- 9 files changed, 316 insertions(+), 183 deletions(-) delete mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index d6c2f005a9779..0261cc4e6321b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -89,6 +89,20 @@ public QueryCursor> queryDistributedSql(String schemaNa public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException; + /** + * Parses SQL query into two step query and executes it. + * + * @param schemaName Schema name. + * @param qry Query. + * @param keepBinary Keep binary flag. + * @param cancel Query cancel. + * @param mainCacheId Main cache ID. + * @return Cursor. + * @throws IgniteCheckedException If failed. + */ + public List>> queryDistributedSqlFieldsMultiple(String schemaName, SqlFieldsQuery qry, + boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException; + /** * Perform a MERGE statement using data streamer as receiver. * @@ -295,13 +309,4 @@ public void remove(String cacheName, GridQueryTypeDescriptor type, KeyCacheObjec * @return {@code True} if insert. */ public boolean isInsertStatement(PreparedStatement nativeStmt); - - /** - * Split multi-statements SQL query to the first statement and remaining SQL query string. - * - * @param schema Schema. - * @param qry Query with multiple statements. - * @return List of queries. - */ - MultipleStatementsQuery splitSqlQuery(String schema, SqlFieldsQuery qry); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index 9926e07d9ee2d..3104651bc6302 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1858,11 +1858,13 @@ public FieldsQueryCursor> querySqlFieldsNoCache(final SqlFieldsQuery qry } /** + * Query SQL fields without strict dependency on concrete cache. + * * @param qry Query. * @param keepBinary Keep binary flag. - * @return List of queries. + * @return Cursor. */ - public QueryResult querySqlFieldsMultipleNoCache(final SqlFieldsQuery qry, final boolean keepBinary) { + public List>> querySqlFieldsNoCache0(final SqlFieldsQuery qry, final boolean keepBinary) { checkxEnabled(); validateSqlFieldsQuery(qry); @@ -1877,11 +1879,18 @@ public QueryResult querySqlFieldsMultipleNoCache(final SqlFieldsQuery qry, final throw new IllegalStateException("Failed to execute query (grid is stopping)."); try { - MultipleStatementsQuery multQry = idx.splitSqlQuery(qry.getSchema(), qry); + IgniteOutClosureX>>> clo = new IgniteOutClosureX>>>() { + @Override public List>> applyx() throws IgniteCheckedException { + GridQueryCancel cancel = new GridQueryCancel(); - FieldsQueryCursor> cur = querySqlFieldsNoCache(multQry.first(), keepBinary); + return idx.queryDistributedSqlFieldsMultiple(qry.getSchema(), qry, keepBinary, cancel, null); + } + }; - return new QueryResult(cur, multQry.remaining()); + return executeQuery(GridCacheQueryType.SQL_FIELDS, qry.getSql(), null, clo, true); + } + catch (IgniteCheckedException e) { + throw new CacheException(e); } finally { busyLock.leaveBusy(); @@ -2669,38 +2678,4 @@ public void manager(SchemaOperationManager mgr) { this.mgr = mgr; } } - - /** - * - */ - public static class QueryResult { - /** Cursor. */ - private FieldsQueryCursor> cur; - - /** Remaining query. */ - private SqlFieldsQuery remaining; - - /** - * @param cur Cursor. - * @param remaining Remaining query. - */ - public QueryResult(FieldsQueryCursor> cur, SqlFieldsQuery remaining) { - this.cur = cur; - this.remaining = remaining; - } - - /** - * @return Query cursor. - */ - public FieldsQueryCursor> cursor() { - return cur; - } - - /** - * @return Remaining query. - */ - public SqlFieldsQuery remaining() { - return remaining; - } - } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java deleted file mode 100644 index 81f6021418057..0000000000000 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/MultipleStatementsQuery.java +++ /dev/null @@ -1,54 +0,0 @@ -/* - * 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.processors.query; - -import org.apache.ignite.cache.query.SqlFieldsQuery; - -/** - * Multiple statement SQL query. - */ -public class MultipleStatementsQuery { - /** First statement. */ - private SqlFieldsQuery first; - - /** Remaining query. */ - private SqlFieldsQuery remaining; - - /** - * @param first Fisrt statement. - * @param remaining Remaining statement. - */ - public MultipleStatementsQuery(SqlFieldsQuery first, SqlFieldsQuery remaining) { - this.first = first; - this.remaining = remaining; - } - - /** - * @return The first query. - */ - public SqlFieldsQuery first() { - return first; - } - - /** - * @return Remaining query. - */ - public SqlFieldsQuery remaining() { - return remaining; - } -} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java index 031152a6a95bd..8fefd81933baf 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java @@ -247,6 +247,11 @@ private static class FailedIndexing implements GridQueryIndexing { return null; } + /** {@inheritDoc} */ + @Override public List>> queryDistributedSqlFieldsMultiple(String schemaName, SqlFieldsQuery qry, + boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException { + return null; + } /** {@inheritDoc} */ @Override public long streamUpdateQuery(String spaceName, String qry, @Nullable Object[] params, @@ -363,10 +368,5 @@ private static class FailedIndexing implements GridQueryIndexing { @Override public boolean isInsertStatement(PreparedStatement nativeStmt) { return false; } - - /** {@inheritDoc} */ - @Override public MultipleStatementsQuery splitSqlQuery(String schema, SqlFieldsQuery qry) { - return null; - } } } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index 0ff9cfef6b60a..ed894afa1fcc2 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -149,7 +149,7 @@ public void onCacheStop(String cacheName) { * Execute DML statement, possibly with few re-attempts in case of concurrent data modifications. * * @param schemaName Schema. - * @param stmt JDBC statement. + * @param prepared Prepared JDBC statement. * @param fieldsQry Original query. * @param loc Query locality flag. * @param filters Cache name and key filter. @@ -157,13 +157,13 @@ public void onCacheStop(String cacheName) { * @return Update result (modified items count and failed keys). * @throws IgniteCheckedException if failed. */ - private UpdateResult updateSqlFields(String schemaName, PreparedStatement stmt, SqlFieldsQuery fieldsQry, + private UpdateResult updateSqlFields(String schemaName, Prepared prepared, SqlFieldsQuery fieldsQry, boolean loc, IndexingQueryFilter filters, GridQueryCancel cancel) throws IgniteCheckedException { Object[] errKeys = null; long items = 0; - UpdatePlan plan = getPlanForStatement(schemaName, stmt, null); + UpdatePlan plan = getPlanForStatement(schemaName, prepared, null); GridCacheContext cctx = plan.tbl.rowDescriptor().context(); @@ -187,7 +187,7 @@ else if (!opCtx.isKeepBinary()) UpdateResult r; try { - r = executeUpdateStatement(schemaName, cctx, stmt, fieldsQry, loc, filters, cancel, errKeys); + r = executeUpdateStatement(schemaName, cctx, prepared, fieldsQry, loc, filters, cancel, errKeys); } finally { cctx.operationContextPerCall(opCtx); @@ -212,16 +212,16 @@ else if (items == 0L) /** * @param schemaName Schema. - * @param stmt Prepared statement. + * @param p Prepared. * @param fieldsQry Initial query * @param cancel Query cancel. * @return Update result wrapped into {@link GridQueryFieldsResult} * @throws IgniteCheckedException if failed. */ @SuppressWarnings("unchecked") - QueryCursorImpl> updateSqlFieldsDistributed(String schemaName, PreparedStatement stmt, + QueryCursorImpl> updateSqlFieldsDistributed(String schemaName, Prepared p, SqlFieldsQuery fieldsQry, GridQueryCancel cancel) throws IgniteCheckedException { - UpdateResult res = updateSqlFields(schemaName, stmt, fieldsQry, false, null, cancel); + UpdateResult res = updateSqlFields(schemaName, p, fieldsQry, false, null, cancel); QueryCursorImpl> resCur = (QueryCursorImpl>)new QueryCursorImpl(Collections.singletonList (Collections.singletonList(res.cnt)), cancel, false); @@ -246,7 +246,7 @@ QueryCursorImpl> updateSqlFieldsDistributed(String schemaName, PreparedS GridQueryFieldsResult updateSqlFieldsLocal(String schemaName, PreparedStatement stmt, SqlFieldsQuery fieldsQry, IndexingQueryFilter filters, GridQueryCancel cancel) throws IgniteCheckedException { - UpdateResult res = updateSqlFields(schemaName, stmt, fieldsQry, true, filters, cancel); + UpdateResult res = updateSqlFields(schemaName, GridSqlQueryParser.prepared(stmt), fieldsQry, true, filters, cancel); return new GridQueryFieldsResultAdapter(UPDATE_RESULT_META, new IgniteSingletonIterator(Collections.singletonList(res.cnt))); @@ -339,7 +339,7 @@ long streamUpdateQuery(IgniteDataStreamer streamer, PreparedStatement stmt, Obje * * @param schemaName Schema name. * @param cctx Cache context. - * @param prepStmt Prepared statement for DML query. + * @param prepared Prepared statement for DML query. * @param fieldsQry Fields query. * @param filters Cache name and key filter. * @param failedKeys Keys to restrict UPDATE and DELETE operations with. Null or empty array means no restriction. @@ -348,13 +348,13 @@ long streamUpdateQuery(IgniteDataStreamer streamer, PreparedStatement stmt, Obje */ @SuppressWarnings({"ConstantConditions", "unchecked"}) private UpdateResult executeUpdateStatement(String schemaName, final GridCacheContext cctx, - PreparedStatement prepStmt, SqlFieldsQuery fieldsQry, boolean loc, IndexingQueryFilter filters, + Prepared prepared, SqlFieldsQuery fieldsQry, boolean loc, IndexingQueryFilter filters, GridQueryCancel cancel, Object[] failedKeys) throws IgniteCheckedException { int mainCacheId = CU.cacheId(cctx.name()); Integer errKeysPos = null; - UpdatePlan plan = getPlanForStatement(schemaName, prepStmt, errKeysPos); + UpdatePlan plan = getPlanForStatement(schemaName, prepared, errKeysPos); if (plan.fastUpdateArgs != null) { assert F.isEmpty(failedKeys) && errKeysPos == null; @@ -422,14 +422,12 @@ private UpdateResult executeUpdateStatement(String schemaName, final GridCacheCo * if available. * * @param schema Schema. - * @param prepStmt JDBC statement. + * @param p Prepared JDBC statement. * @return Update plan. */ @SuppressWarnings({"unchecked", "ConstantConditions"}) - private UpdatePlan getPlanForStatement(String schema, PreparedStatement prepStmt, @Nullable Integer errKeysPos) + private UpdatePlan getPlanForStatement(String schema, Prepared p, @Nullable Integer errKeysPos) throws IgniteCheckedException { - Prepared p = GridSqlQueryParser.prepared(prepStmt); - H2DmlPlanKey planKey = new H2DmlPlanKey(schema, p.getSQL()); UpdatePlan res = (errKeysPos == null ? planCache.get(planKey) : null); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 26ec1b5cf550f..f02c9e3ab1e46 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -90,7 +90,6 @@ import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; import org.apache.ignite.internal.processors.query.IgniteSQLException; -import org.apache.ignite.internal.processors.query.MultipleStatementsQuery; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; import org.apache.ignite.internal.processors.query.QueryUtils; import org.apache.ignite.internal.processors.query.h2.database.H2RowFactory; @@ -1258,60 +1257,226 @@ private Iterable> runQueryTwoStep( } /** {@inheritDoc} */ - @Override public MultipleStatementsQuery splitSqlQuery(String schemaName, SqlFieldsQuery qry) { - String sqlQry = qry.getSql(); + @Override public List>> queryDistributedSqlFieldsMultiple(String schemaName, + SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { Connection c = connectionForSchema(schemaName); - boolean cachesCreated = false; + final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); + final boolean distributedJoins = qry.isDistributedJoins(); + final boolean grpByCollocated = qry.isCollocated(); - PreparedStatement stmt = null; + final DistributedJoinMode distributedJoinMode = distributedJoinMode(qry.isLocal(), distributedJoins); - // Loop for cache create - while (true) { - try { - // Do not cache this statement because the whole query object will be cached later on. - stmt = prepareStatement(c, sqlQry, false); + GridCacheTwoStepQuery twoStepQry = null; + List meta; + + List>> results = new ArrayList<>(); + + String sqlQry = qry.getSql(); + Object[] argsOrig = qry.getArgs(); + int firstArg = 0; + Object[] args = null; + String remainingSql = sqlQry; + + while (remainingSql != null) { + + final H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, + distributedJoins, enforceJoinOrder, qry.isLocal()); + H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); - break; + if (cachedQry != null) { + twoStepQry = cachedQry.query().copy(); + meta = cachedQry.meta(); } - catch (SQLException e) { - if (!cachesCreated && ( - e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) - ) { + else { + final UUID locNodeId = ctx.localNodeId(); + + // Here we will just parse the statement, no need to optimize it at all. + H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); + + GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) + .distributedJoinMode(distributedJoinMode)); + + PreparedStatement stmt = null; + Prepared prepared; + + boolean cachesCreated = false; + + try { try { - ctx.cache().createMissingQueryCaches(); + while (true) { + try { + // Do not cache this statement because the whole query object will be cached later on. + stmt = prepareStatement(c, remainingSql, false); + + break; + } + catch (SQLException e) { + if (!cachesCreated && ( + e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) + ) { + try { + ctx.cache().createMissingQueryCaches(); + } + catch (IgniteCheckedException ignored) { + throw new CacheException("Failed to create missing caches.", e); + } + + cachesCreated = true; + } + else + throw new IgniteSQLException("Failed to parse query: " + sqlQry, + IgniteQueryErrorCode.PARSING, e); + } + } + + GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt); + + // remaining == null if the query string contains single SQL statement. + remainingSql = prep.remainingSql(); + + sqlQry = prep.prepared().getSQL(); + + prepared = prep.prepared(); + + int paramsCnt = prepared.getParameters().size(); + + if (argsOrig != null && paramsCnt > 0) { + args = Arrays.copyOfRange(argsOrig, firstArg, firstArg + paramsCnt); + + firstArg += paramsCnt; + } + else + args = null; + + if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery)qry).isQuery() != prepared.isQuery()) + throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", + IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + + if (prepared.isQuery()) { + bindParameters(stmt, F.asList(args)); + + twoStepQry = GridSqlQuerySplitter.split(c, prepared, args, + grpByCollocated, distributedJoins, enforceJoinOrder, this); + + assert twoStepQry != null; + } + } + finally { + GridH2QueryContext.clearThreadLocal(); } - catch (IgniteCheckedException ignored) { - throw new CacheException("Failed to create missing caches.", e); + + // It is a DML statement if we did not create a twoStepQuery. + if (twoStepQry == null) { + if (DmlStatementsProcessor.isDmlStatement(prepared)) { + try { + results.add(dmlProc.updateSqlFieldsDistributed(schemaName, prepared, + new SqlFieldsQuery(qry).setSql(sqlQry).setArgs(args), cancel)); + + continue; + } + catch (IgniteCheckedException e) { + throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + + ", params=" + Arrays.deepToString(args) + "]", e); + } + } + + if (DdlStatementsProcessor.isDdlStatement(prepared)) { + try { + results.add(ddlProc.runDdlStatement(sqlQry, prepared)); + + continue; + } + catch (IgniteCheckedException e) { + throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); + } + } + } + + LinkedHashSet caches0 = new LinkedHashSet<>(); + + assert twoStepQry != null; + + int tblCnt = twoStepQry.tablesCount(); + + if (mainCacheId != null) + caches0.add(mainCacheId); + + if (tblCnt > 0) { + for (QueryTable tblKey : twoStepQry.tables()) { + GridH2Table tbl = dataTable(tblKey); + + int cacheId = CU.cacheId(tbl.cacheName()); + + caches0.add(cacheId); + } + } + + if (caches0.isEmpty()) + twoStepQry.local(true); + else { + //Prohibit usage indices with different numbers of segments in same query. + List cacheIds = new ArrayList<>(caches0); + + checkCacheIndexSegmentation(cacheIds); + + twoStepQry.cacheIds(cacheIds); + twoStepQry.local(qry.isLocal()); } - cachesCreated = true; + meta = H2Utils.meta(stmt.getMetaData()); + } + catch (IgniteCheckedException e) { + throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + + Arrays.deepToString(qry.getArgs()) + "]", e); + } + catch (SQLException e) { + throw new IgniteSQLException(e); + } + finally { + U.close(stmt, log); } - else - throw new IgniteSQLException("Failed to parse query: " + sqlQry, - IgniteQueryErrorCode.PARSING, e); } - } - GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt); + if (log.isDebugEnabled()) + log.debug("Parsed query: `" + sqlQry + "` into two step query: " + twoStepQry); + + twoStepQry.pageSize(qry.getPageSize()); - SqlFieldsQuery first = new SqlFieldsQuery(qry); - first.setSql(prep.prepared().getSQL()); - // TODO: split parameters! + if (cancel == null) + cancel = new GridQueryCancel(); - SqlFieldsQuery remaining = null; + int partitions[] = qry.getPartitions(); - if (prep.remainingSql() != null) { - remaining = new SqlFieldsQuery(qry); + if (partitions == null && twoStepQry.derivedPartitions() != null) { + try { + partitions = calculateQueryPartitions(twoStepQry.derivedPartitions(), args); + } + catch (IgniteCheckedException e) { + throw new CacheException("Failed to calculate derived partitions: [qry=" + sqlQry + ", params=" + + Arrays.deepToString(args) + "]", e); + } + } + + QueryCursorImpl> cursor = new QueryCursorImpl<>( + runQueryTwoStep(schemaName, twoStepQry, keepBinary, enforceJoinOrder, qry.getTimeout(), cancel, + args, partitions, qry.isLazy()), cancel); + + cursor.fieldsMeta(meta); + + if (cachedQry == null && !twoStepQry.explain()) { + cachedQry = new H2TwoStepCachedQuery(meta, twoStepQry.copy()); + + twoStepCache.putIfAbsent(cachedQryKey, cachedQry); + } - remaining.setSql(prep.remainingSql()); - // TODO: split parameters! + results.add(cursor); } - return new MultipleStatementsQuery(first, remaining); + return results; } /** {@inheritDoc} */ @@ -1391,7 +1556,7 @@ private Iterable> runQueryTwoStep( if (prepared.isQuery()) { bindParameters(stmt, F.asList(qry.getArgs())); - twoStepQry = GridSqlQuerySplitter.split((JdbcPreparedStatement)stmt, qry.getArgs(), + twoStepQry = GridSqlQuerySplitter.split(c, prepared, qry.getArgs(), grpByCollocated, distributedJoins, enforceJoinOrder, this); assert twoStepQry != null; @@ -1405,7 +1570,7 @@ private Iterable> runQueryTwoStep( if (twoStepQry == null) { if (DmlStatementsProcessor.isDmlStatement(prepared)) { try { - return dmlProc.updateSqlFieldsDistributed(schemaName, stmt, qry, cancel); + return dmlProc.updateSqlFieldsDistributed(schemaName, prepared, qry, cancel); } catch (IgniteCheckedException e) { throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + @@ -1415,7 +1580,7 @@ private Iterable> runQueryTwoStep( if (DdlStatementsProcessor.isDdlStatement(prepared)) { try { - return ddlProc.runDdlStatement(sqlQry, stmt); + return ddlProc.runDdlStatement(sqlQry, prepared); } catch (IgniteCheckedException e) { throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index 65e402d2d3653..2f46bebafc7fc 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -84,17 +84,16 @@ public void start(final GridKernalContext ctx, IgniteH2Indexing idx) { * Execute DDL statement. * * @param sql SQL. - * @param stmt H2 statement to parse and execute. + * @param prepared Prepared. */ @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"}) - public FieldsQueryCursor> runDdlStatement(String sql, PreparedStatement stmt) + public FieldsQueryCursor> runDdlStatement(String sql, Prepared prepared) throws IgniteCheckedException { - assert stmt instanceof JdbcPreparedStatement; IgniteInternalFuture fut = null; try { - GridSqlStatement stmt0 = new GridSqlQueryParser(false).parse(GridSqlQueryParser.prepared(stmt)); + GridSqlStatement stmt0 = new GridSqlQueryParser(false).parse(prepared); if (stmt0 instanceof GridSqlCreateIndex) { GridSqlCreateIndex cmd = (GridSqlCreateIndex)stmt0; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java index 1578f9fb78dc0..6df70d0df7446 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java @@ -171,7 +171,8 @@ private String columnName(int idx) { } /** - * @param stmt Prepared statement. + * @param conn Connection. + * @param prepared Prepared. * @param params Parameters. * @param collocatedGrpBy Whether the query has collocated GROUP BY keys. * @param distributedJoins If distributed joins enabled. @@ -182,7 +183,8 @@ private String columnName(int idx) { * @throws IgniteCheckedException If failed. */ public static GridCacheTwoStepQuery split( - JdbcPreparedStatement stmt, + Connection conn, + Prepared prepared, Object[] params, boolean collocatedGrpBy, boolean distributedJoins, @@ -194,7 +196,7 @@ public static GridCacheTwoStepQuery split( // Here we will just do initial query parsing. Do not use optimized // subqueries because we do not have unique FROM aliases yet. - GridSqlQuery qry = parse(prepared(stmt), false); + GridSqlQuery qry = parse(prepared, false); String originalSql = qry.getSQL(); @@ -212,8 +214,6 @@ public static GridCacheTwoStepQuery split( // debug("NORMALIZED", qry.getSQL()); - Connection conn = stmt.getConnection(); - // Here we will have correct normalized AST with optimized join order. // The distributedJoins parameter is ignored because it is not relevant for // the REDUCE query optimization. @@ -233,12 +233,12 @@ public static GridCacheTwoStepQuery split( boolean allCollocated = true; for (GridCacheSqlQuery mapSqlQry : splitter.mapSqlQrys) { - Prepared prepared = optimize(h2, conn, mapSqlQry.query(), mapSqlQry.parameters(params), + Prepared prepared0 = optimize(h2, conn, mapSqlQry.query(), mapSqlQry.parameters(params), true, enforceJoinOrder); - allCollocated &= isCollocated((Query)prepared); + allCollocated &= isCollocated((Query)prepared0); - mapSqlQry.query(parse(prepared, true).getSQL()); + mapSqlQry.query(parse(prepared0, true).getSQL()); } // We do not need distributed joins if all MAP queries are collocated. diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index 9ca2a4721b3de..905b9a3455280 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.processors.query; import java.util.List; +import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; @@ -57,25 +58,25 @@ public void testQuery() throws Exception { "select * from test;") .setSchema("PUBLIC"); - GridQueryProcessor.QueryResult res = qryProc.querySqlFieldsMultipleNoCache(qry, true); + List>> res = qryProc.querySqlFieldsNoCache0(qry, true); - assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DDL statement is expected "; + assert res.size() == 4 : "Unexpected cursors count: " + res.size(); - res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + assert !((QueryCursorImpl)res.get(0)).isQuery() : "Results of DDL statement is expected "; - List> rows = res.cursor().getAll(); + List> rows = res.get(1).getAll(); - assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DML statement is expected"; + assert !((QueryCursorImpl)res.get(1)).isQuery() : "Results of DDL statement is expected "; assert Long.valueOf(1).equals(rows.get(0).get(0)) : "1 row must be updated. [actual=" + rows.get(0).get(0) + ']'; - res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + rows = res.get(2).getAll(); - assert !((QueryCursorImpl)res.cursor()).isQuery() : "Results of DML statement is expected"; - assert Long.valueOf(2).equals(res.cursor().getAll().get(0).get(0)) : "2 row must be updated"; + assert !((QueryCursorImpl)res.get(2)).isQuery() : "Results of DML statement is expected "; + assert Long.valueOf(2).equals(rows.get(0).get(0)) : "2 row must be updated"; - res = qryProc.querySqlFieldsMultipleNoCache(res.remaining(), true); + rows = res.get(3).getAll(); - rows = res.cursor().getAll(); + assert ((QueryCursorImpl)res.get(3)).isQuery() : "Results of SELECT statement is expected "; assert rows.size() == 3 : "Invalid rows count: " + rows.size(); @@ -85,7 +86,51 @@ public void testQuery() throws Exception { || Integer.valueOf(3).equals(rows.get(i).get(0)) : "Invalid ID: " + rows.get(i).get(0); } + } + + /** + * Test query without caches. + * + * @throws Exception If failed. + */ + public void testQueryWithParameters() throws Exception { + GridQueryProcessor qryProc = node.context().query(); + + SqlFieldsQuery qry = new SqlFieldsQuery( + "create table test(ID int primary key, NAME varchar(20)); " + + "insert into test (ID, NAME) values (?, ?);" + + "insert into test (ID, NAME) values (?, ?), (?, ?);" + + "select * from test;") + .setSchema("PUBLIC") + .setArgs(1, "name_1", 2, "name2", 3, "name_3"); + + List>> res = qryProc.querySqlFieldsNoCache0(qry, true); + + assert res.size() == 4 : "Unexpected cursors count: " + res.size(); + + assert !((QueryCursorImpl)res.get(0)).isQuery() : "Results of DDL statement is expected "; - assert res.remaining() == null : "No more results expected"; + List> rows = res.get(1).getAll(); + + assert !((QueryCursorImpl)res.get(1)).isQuery() : "Results of DDL statement is expected "; + assert Long.valueOf(1).equals(rows.get(0).get(0)) : "1 row must be updated. [actual=" + rows.get(0).get(0) + ']'; + + rows = res.get(2).getAll(); + + assert !((QueryCursorImpl)res.get(2)).isQuery() : "Results of DML statement is expected "; + assert Long.valueOf(2).equals(rows.get(0).get(0)) : "2 row must be updated"; + + rows = res.get(3).getAll(); + + assert ((QueryCursorImpl)res.get(3)).isQuery() : "Results of SELECT statement is expected "; + + assert rows.size() == 3 : "Invalid rows count: " + rows.size(); + + for (int i = 0; i < rows.size(); ++i) { + assert Integer.valueOf(1).equals(rows.get(i).get(0)) + || Integer.valueOf(2).equals(rows.get(i).get(0)) + || Integer.valueOf(3).equals(rows.get(i).get(0)) + : "Invalid ID: " + rows.get(i).get(0); + } } } From c9670c3ce27ad98574467e0e418be1b1271916fc Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 4 Sep 2017 18:26:46 +0300 Subject: [PATCH 03/36] IGNITE-6046: save the progress --- .../internal/jdbc/thin/JdbcThinStatement.java | 21 +++- ...cQueryExecuteMultipleStatementsResult.java | 97 +++++++++++++++++++ .../odbc/jdbc/JdbcRequestHandler.java | 63 +++++++++--- .../processors/odbc/jdbc/JdbcResult.java | 3 + .../odbc/jdbc/JdbcStatementResults.java | 88 +++++++++++++++++ 5 files changed, 252 insertions(+), 20 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 59a9db091b539..4818eec4a4edf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -32,7 +32,9 @@ import org.apache.ignite.internal.processors.odbc.SqlListenerResponse; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcBatchExecuteResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteMultipleStatementsResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.FETCH_FORWARD; @@ -114,13 +116,24 @@ protected void execute0(String sql, List args) throws SQLException { throw new SQLException("SQL query is empty."); try { - JdbcQueryExecuteResult res = conn.io().queryExecute(conn.getSchema(), pageSize, maxRows, + JdbcResult res0 = conn.io().queryExecute(conn.getSchema(), pageSize, maxRows, sql, args); - assert res != null; + assert res0 != null; - rs = new JdbcThinResultSet(this, res.getQueryId(), pageSize, res.last(), res.items(), - res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount()); + if (res0 instanceof JdbcQueryExecuteResult) { + JdbcQueryExecuteResult res = (JdbcQueryExecuteResult)res0; + + rs = new JdbcThinResultSet(this, res.getQueryId(), pageSize, res.last(), res.items(), + res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount()); + } + else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { + JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; + + } + else { + throw new SQLException("Unexpected result [res=" + res0 + ']'); + } } catch (IOException e) { conn.close(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java new file mode 100644 index 0000000000000..4f0c5d4edfd44 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java @@ -0,0 +1,97 @@ +/* + * 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.processors.odbc.jdbc; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import org.apache.ignite.binary.BinaryObjectException; +import org.apache.ignite.internal.binary.BinaryReaderExImpl; +import org.apache.ignite.internal.binary.BinaryWriterExImpl; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * JDBC query execute result for query with multiple SQL statements. + */ +public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { + /** Statements results. */ + private List results; + + /** + * Default constructor. + */ + JdbcQueryExecuteMultipleStatementsResult() { + super(QRY_EXEC_MULT); + } + + /** + * @param results Statements results. + */ + public JdbcQueryExecuteMultipleStatementsResult(List results) { + super(QRY_EXEC_MULT); + this.results = results; + } + + /** + * @return Update counts of query IDs. + */ + public List results() { + return results; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriterExImpl writer) throws BinaryObjectException { + super.writeBinary(writer); + + if (results != null && results.size() > 0) { + writer.writeInt(results.size()); + + for (JdbcStatementResults r : results) + r.writeBinary(writer); + + } else + writer.writeInt(0); + } + + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReaderExImpl reader) throws BinaryObjectException { + super.readBinary(reader); + + int cnt = reader.readInt(); + if (cnt == 0) + results = Collections.emptyList(); + else + { + results = new ArrayList<>(cnt); + + for (int i = 0; i < cnt; ++i) { + JdbcStatementResults r = new JdbcStatementResults(); + + r.readBinary(reader); + + results.add(r); + } + } + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcQueryExecuteMultipleStatementsResult.class, this); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index d2508a660607f..a8cc0fab93ca0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -246,31 +246,62 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qry.setSchema(schemaName); - FieldsQueryCursor> qryCur = ctx.query().querySqlFieldsNoCache(qry, true); + List>> results = ctx.query().querySqlFieldsNoCache0(qry, true); - JdbcQueryCursor cur = new JdbcQueryCursor(qryId, req.pageSize(), req.maxRows(), (QueryCursorImpl)qryCur); + if (results.size() == 1) { + FieldsQueryCursor> qryCur = results.get(0); - JdbcQueryExecuteResult res; + JdbcQueryCursor cur = new JdbcQueryCursor(qryId, req.pageSize(), req.maxRows(), (QueryCursorImpl)qryCur); - if (cur.isQuery()) - res = new JdbcQueryExecuteResult(qryId, cur.fetchRows(), !cur.hasNext()); + JdbcQueryExecuteResult res; + + if (cur.isQuery()) + res = new JdbcQueryExecuteResult(qryId, cur.fetchRows(), !cur.hasNext()); + else { + List> items = cur.fetchRows(); + + assert items != null && items.size() == 1 && items.get(0).size() == 1 + && items.get(0).get(0) instanceof Long : + "Invalid result set for not-SELECT query. [qry=" + sql + + ", res=" + S.toString(List.class, items) + ']'; + + res = new JdbcQueryExecuteResult(qryId, (Long)items.get(0).get(0)); + } + + if (res.last() && (!res.isQuery() || autoCloseCursors)) + cur.close(); + else + qryCursors.put(qryId, cur); + + return new JdbcResponse(res); + } else { - List> items = cur.fetchRows(); + List jdbcResults = new ArrayList<>(results.size()); + + for (FieldsQueryCursor> c : results) { + QueryCursorImpl qryCur = (QueryCursorImpl)c; + + JdbcStatementResults jdbcRes; - assert items != null && items.size() == 1 && items.get(0).size() == 1 - && items.get(0).get(0) instanceof Long : - "Invalid result set for not-SELECT query. [qry=" + sql + - ", res=" + S.toString(List.class, items) + ']'; + if (qryCur.isQuery()) { + jdbcRes = new JdbcStatementResults(true, qryId); - res = new JdbcQueryExecuteResult(qryId, (Long)items.get(0).get(0)); + JdbcQueryCursor cur = new JdbcQueryCursor(qryId, req.pageSize(), req.maxRows(), (QueryCursorImpl)qryCur); + + qryCursors.put(qryId, cur); + + qryId = QRY_ID_GEN.getAndIncrement(); + } + else + jdbcRes = new JdbcStatementResults(false, (Long)((List)qryCur.getAll().get(0)).get(0)); + + jdbcResults.add(jdbcRes); + } + + return new JdbcResponse(new JdbcQueryExecuteMultipleStatementsResult(jdbcResults)); } - if (res.last() && (!res.isQuery() || autoCloseCursors)) - cur.close(); - else - qryCursors.put(qryId, cur); - return new JdbcResponse(res); } catch (Exception e) { qryCursors.remove(qryId); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java index 202905bbc9e4d..0df3db89d13e4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java @@ -56,6 +56,9 @@ public class JdbcResult implements JdbcRawBinarylizable { /** Database schemas metadata result. */ static final byte META_SCHEMAS = 12; + /** Multiple statements query results. */ + static final byte QRY_EXEC_MULT = 13; + /** Success status. */ private byte type; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java new file mode 100644 index 0000000000000..6c6a9ce40ccc0 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java @@ -0,0 +1,88 @@ +/* + * 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.processors.odbc.jdbc; + +import org.apache.ignite.internal.binary.BinaryReaderExImpl; +import org.apache.ignite.internal.binary.BinaryWriterExImpl; +import org.apache.ignite.internal.util.typedef.internal.S; + +/** + * JDBC multiple statements results. + */ +public class JdbcStatementResults implements JdbcRawBinarylizable { + /** Query flag. */ + private boolean isQuery; + + /** Update count. */ + private long updCntOrQryId; + + /** + * Default constructor is used for serialization. + */ + JdbcStatementResults() { + // No-op. + } + + + /** + * @param isQuery Query flag. + * @param updCntOrQryId Update count. + */ + JdbcStatementResults(boolean isQuery, long updCntOrQryId) { + this.isQuery = isQuery; + this.updCntOrQryId= updCntOrQryId; + } + + /** + * @return Query flag. + */ + public boolean isQuery() { + return isQuery; + } + + /** + * @return Query ID. + */ + public long queryId() { + return isQuery ? updCntOrQryId : -1; + } + + /** + * @return Update count. + */ + public long updateCount() { + return !isQuery ? updCntOrQryId : -1; + } + + /** {@inheritDoc} */ + @Override public void writeBinary(BinaryWriterExImpl writer) { + writer.writeBoolean(isQuery); + writer.writeLong(updCntOrQryId); + } + + /** {@inheritDoc} */ + @Override public void readBinary(BinaryReaderExImpl reader) { + isQuery = reader.readBoolean(); + updCntOrQryId = reader.readLong(); + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcStatementResults.class, this); + } +} From 5cef75bcab5d8f31712b0ad5dcbe53ebca110dc4 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 5 Sep 2017 09:53:32 +0300 Subject: [PATCH 04/36] IGNITE-6046: save the progress --- .../internal/jdbc/thin/JdbcThinStatement.java | 40 ++++++++++++------- ...cQueryExecuteMultipleStatementsResult.java | 20 ++++++++++ .../odbc/jdbc/JdbcQueryExecuteResult.java | 7 ++++ 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 4818eec4a4edf..37138c11f613c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -26,6 +26,8 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; +import java.util.Iterator; import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.query.SqlQuery; @@ -35,6 +37,7 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteMultipleStatementsResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementResults; import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.FETCH_FORWARD; @@ -60,18 +63,21 @@ public class JdbcThinStatement implements Statement { /** Query timeout. */ private int timeout; - /** Current result set. */ - protected JdbcThinResultSet rs; + /** Result sets. */ + protected List resultSets; + + /** Current result. */ + protected int curRes; /** Fetch size. */ private int pageSize = DFLT_PAGE_SIZE; - /** */ - private boolean alreadyRead; - /** Batch. */ protected List batch; + /** Multiple statement result info. */ + protected Iterator resInfoIter; + /** * Creates new statement. * @@ -104,13 +110,14 @@ public class JdbcThinStatement implements Statement { protected void execute0(String sql, List args) throws SQLException { ensureNotClosed(); - if (rs != null) { - rs.close(); + if (resultSets != null) { + for (ResultSet rs : resultSets) + rs.close(); - rs = null; - } + resultSets = null; - alreadyRead = false; + curRes = 0; + } if (sql == null || sql.isEmpty()) throw new SQLException("SQL query is empty."); @@ -124,16 +131,16 @@ protected void execute0(String sql, List args) throws SQLException { if (res0 instanceof JdbcQueryExecuteResult) { JdbcQueryExecuteResult res = (JdbcQueryExecuteResult)res0; - rs = new JdbcThinResultSet(this, res.getQueryId(), pageSize, res.last(), res.items(), - res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount()); + resultSets = Collections.singletonList(new JdbcThinResultSet(this, res.getQueryId(), pageSize, + res.last(), res.items(), res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount())); } else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; + resInfoIter = res.results().iterator(); } - else { + else throw new SQLException("Unexpected result [res=" + res0 + ']'); - } } catch (IOException e) { conn.close(); @@ -281,7 +288,10 @@ else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { private JdbcThinResultSet lastResultSet() throws SQLException { ensureNotClosed(); - if (rs == null || alreadyRead) + if (rs != null && !alreadyRead) + return rs; + + if ((rs == null || alreadyRead) && (resIter == null || !resIter.hasNext())) return null; return rs; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java index 4f0c5d4edfd44..f1341d60fc820 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java @@ -39,6 +39,26 @@ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { super(QRY_EXEC_MULT); } +// /** +// * @param queryId Query ID. +// * @param items Query result rows. +// * @param last Flag indicates the query has no unfetched results. +// * @param results Statements results. +// */ +// public JdbcQueryExecuteMultipleStatementsResult(long queryId, List> items, boolean last, List results) { +// super(QRY_EXEC_MULT); +// this.results = results; +// } +// +// /** +// * @param updCnt Update count. +// * @param results Statements results. +// */ +// public JdbcQueryExecuteMultipleStatementsResult(long updCnt, List results) { +// super(QRY_EXEC_MULT); +// this.results = results; +// } + /** * @param results Statements results. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java index fdebdb8c3c450..4ab5e1c547ee2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java @@ -49,6 +49,13 @@ public class JdbcQueryExecuteResult extends JdbcResult { super(QRY_EXEC); } + /** + * @param type Result type. + */ + protected JdbcQueryExecuteResult(byte type) { + super(type); + } + /** * @param queryId Query ID. * @param items Query result rows. From 1c7173a8979f8ef876d522bb1b017287f139f9bc Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 5 Sep 2017 11:53:41 +0300 Subject: [PATCH 05/36] IGNITE-6046: save the progress --- .../jdbc/thin/JdbcThinPreparedStatement.java | 2 +- .../internal/jdbc/thin/JdbcThinStatement.java | 118 ++++--- .../odbc/jdbc/JdbcStatementResults.java | 2 +- ...niteClientCacheInitializationFailTest.java | 1 - .../processors/query/h2/IgniteH2Indexing.java | 306 +++++++++--------- 5 files changed, 241 insertions(+), 188 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java index e6dfa59690af4..dec8ad577e981 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java @@ -216,7 +216,7 @@ public class JdbcThinPreparedStatement extends JdbcThinStatement implements Prep @Override public boolean execute() throws SQLException { executeWithArguments(); - return rs.isQuery(); + return resInfo.get(0).isQuery(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 37138c11f613c..c5ccc227b913a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteMultipleStatementsResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementResults; @@ -76,7 +77,7 @@ public class JdbcThinStatement implements Statement { protected List batch; /** Multiple statement result info. */ - protected Iterator resInfoIter; + protected List resInfo; /** * Creates new statement. @@ -110,14 +111,7 @@ public class JdbcThinStatement implements Statement { protected void execute0(String sql, List args) throws SQLException { ensureNotClosed(); - if (resultSets != null) { - for (ResultSet rs : resultSets) - rs.close(); - - resultSets = null; - - curRes = 0; - } + closeResults(); if (sql == null || sql.isEmpty()) throw new SQLException("SQL query is empty."); @@ -133,14 +127,21 @@ protected void execute0(String sql, List args) throws SQLException { resultSets = Collections.singletonList(new JdbcThinResultSet(this, res.getQueryId(), pageSize, res.last(), res.items(), res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount())); + + resInfo = Collections.singletonList(new JdbcStatementResults(res.isQuery(), + res.isQuery() ? res.getQueryId() : res.updateCount())); } else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; - resInfoIter = res.results().iterator(); + resultSets = Collections.emptyList(); + + resInfo = res.results(); } else throw new SQLException("Unexpected result [res=" + res0 + ']'); + + assert resInfo.size() > 0 : "At least one results set is expected"; } catch (IOException e) { conn.close(); @@ -169,12 +170,26 @@ else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { if (isClosed()) return; - if (rs != null) - rs.close(); + closeResults(); closed = true; } + /** + * Close results. + * @throws SQLException On error. + */ + private void closeResults() throws SQLException { + if (resultSets != null) { + for (ResultSet rs : resultSets) + rs.close(); + + resultSets = null; + resInfo = null; + curRes = 0; + } + } + /** {@inheritDoc} */ @Override public int getMaxFieldSize() throws SQLException { ensureNotClosed(); @@ -252,31 +267,39 @@ else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { execute0(sql, null); - return rs.isQuery(); + return resInfo.get(0).isQuery(); } /** {@inheritDoc} */ @Override public ResultSet getResultSet() throws SQLException { - JdbcThinResultSet rs = lastResultSet(); + JdbcThinResultSet rs = nextResultSet(); - ResultSet res = rs == null || !rs.isQuery() ? null : rs; + if (rs == null) + return null; - if (res != null) - alreadyRead = true; + if (!rs.isQuery()) { + curRes--; - return res; + return null; + } + + return rs; } /** {@inheritDoc} */ @Override public int getUpdateCount() throws SQLException { - JdbcThinResultSet rs = lastResultSet(); + JdbcThinResultSet rs = nextResultSet(); - int res = rs == null || rs.isQuery() ? -1 : (int)rs.updatedCount(); + if (rs == null) + return -1; - if (res != -1) - alreadyRead = true; + if (rs.isQuery()) { + curRes--; - return res; + return -1; + } + + return (int)rs.updatedCount(); } /** @@ -285,23 +308,50 @@ else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { * @return Result set or null. * @throws SQLException If failed. */ - private JdbcThinResultSet lastResultSet() throws SQLException { + private JdbcThinResultSet nextResultSet() throws SQLException { ensureNotClosed(); - if (rs != null && !alreadyRead) - return rs; - - if ((rs == null || alreadyRead) && (resIter == null || !resIter.hasNext())) + if (resultSets == null || resInfo == null || curRes >= resInfo.size()) return null; - return rs; + if (curRes >= resultSets.size()) { + try { + JdbcThinResultSet rs; + + if (resInfo.get(curRes).isQuery()) { + long qryId = resInfo.get(curRes).queryId(); + + JdbcQueryFetchResult res = conn.io().queryFetch(qryId, pageSize); + + rs = new JdbcThinResultSet(this, qryId, pageSize, + res.last(), res.items(), true, conn.io().autoCloseServerCursor(),-1); + } + else { + rs = new JdbcThinResultSet(this, -1, pageSize, + true, Collections.>emptyList(), false, + conn.io().autoCloseServerCursor(),resInfo.get(curRes).updateCount()); + } + + resultSets.add(rs); + } + catch (IOException e) { + conn.close(); + + throw new SQLException("Failed get next results.", e); + } + catch (IgniteCheckedException e) { + throw new SQLException("Failed get next results.", e); + } + } + + return resultSets.get(curRes++); } /** {@inheritDoc} */ @Override public boolean getMoreResults() throws SQLException { ensureNotClosed(); - return false; + return (resInfo != null && curRes < resInfo.size()); } /** {@inheritDoc} */ @@ -371,13 +421,7 @@ private JdbcThinResultSet lastResultSet() throws SQLException { @Override public int[] executeBatch() throws SQLException { ensureNotClosed(); - if (rs != null) { - rs.close(); - - rs = null; - } - - alreadyRead = false; + closeResults(); if (batch == null || batch.isEmpty()) throw new SQLException("Batch is empty."); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java index 6c6a9ce40ccc0..3bfd86da26c04 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java @@ -43,7 +43,7 @@ public class JdbcStatementResults implements JdbcRawBinarylizable { * @param isQuery Query flag. * @param updCntOrQryId Update count. */ - JdbcStatementResults(boolean isQuery, long updCntOrQryId) { + public JdbcStatementResults(boolean isQuery, long updCntOrQryId) { this.isQuery = isQuery; this.updCntOrQryId= updCntOrQryId; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java index 8fefd81933baf..38e53544ade2a 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java @@ -49,7 +49,6 @@ import org.apache.ignite.internal.processors.query.GridQueryProcessor; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; import org.apache.ignite.internal.processors.query.GridRunningQueryInfo; -import org.apache.ignite.internal.processors.query.MultipleStatementsQuery; import org.apache.ignite.internal.processors.query.QueryIndexDescriptorImpl; import org.apache.ignite.internal.processors.query.schema.SchemaIndexCacheVisitor; import org.apache.ignite.internal.util.GridSpinBusyLock; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index f02c9e3ab1e46..db1bd3e531888 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -149,6 +149,7 @@ import org.h2.table.IndexColumn; import org.h2.tools.Server; import org.h2.util.JdbcUtils; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jsr166.ConcurrentHashMap8; @@ -1271,87 +1272,102 @@ private Iterable> runQueryTwoStep( GridCacheTwoStepQuery twoStepQry = null; List meta; + String sqlQry = qry.getSql(); + + H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, + distributedJoins, enforceJoinOrder, qry.isLocal()); + H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); + + if (cachedQry != null) { + twoStepQry = cachedQry.query().copy(); + meta = cachedQry.meta(); + + return Collections.singletonList(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), + qry.getArgs(), keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, + twoStepQry, meta, cachedQryKey, cachedQry)); + } + List>> results = new ArrayList<>(); - String sqlQry = qry.getSql(); Object[] argsOrig = qry.getArgs(); int firstArg = 0; Object[] args = null; String remainingSql = sqlQry; while (remainingSql != null) { + final UUID locNodeId = ctx.localNodeId(); - final H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, - distributedJoins, enforceJoinOrder, qry.isLocal()); - H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); - - if (cachedQry != null) { - twoStepQry = cachedQry.query().copy(); - meta = cachedQry.meta(); - } - else { - final UUID locNodeId = ctx.localNodeId(); - - // Here we will just parse the statement, no need to optimize it at all. - H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); + // Here we will just parse the statement, no need to optimize it at all. + H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); - GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) - .distributedJoinMode(distributedJoinMode)); + GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) + .distributedJoinMode(distributedJoinMode)); - PreparedStatement stmt = null; - Prepared prepared; + PreparedStatement stmt = null; + Prepared prepared; - boolean cachesCreated = false; + boolean cachesCreated = false; + try { try { - try { - while (true) { - try { - // Do not cache this statement because the whole query object will be cached later on. - stmt = prepareStatement(c, remainingSql, false); + while (true) { + try { + // Do not cache this statement because the whole query object will be cached later on. + stmt = prepareStatement(c, remainingSql, false); - break; - } - catch (SQLException e) { - if (!cachesCreated && ( - e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) - ) { - try { - ctx.cache().createMissingQueryCaches(); - } - catch (IgniteCheckedException ignored) { - throw new CacheException("Failed to create missing caches.", e); - } - - cachesCreated = true; + break; + } + catch (SQLException e) { + if (!cachesCreated && ( + e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || + e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) + ) { + try { + ctx.cache().createMissingQueryCaches(); } - else - throw new IgniteSQLException("Failed to parse query: " + sqlQry, - IgniteQueryErrorCode.PARSING, e); + catch (IgniteCheckedException ignored) { + throw new CacheException("Failed to create missing caches.", e); + } + + cachesCreated = true; } + else + throw new IgniteSQLException("Failed to parse query: " + sqlQry, + IgniteQueryErrorCode.PARSING, e); } + } - GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt); + GridSqlQueryParser.PreparedWithRemaining prep = GridSqlQueryParser.preparedWithRemaining(stmt); - // remaining == null if the query string contains single SQL statement. - remainingSql = prep.remainingSql(); + // remaining == null if the query string contains single SQL statement. + remainingSql = prep.remainingSql(); - sqlQry = prep.prepared().getSQL(); + sqlQry = prep.prepared().getSQL(); - prepared = prep.prepared(); + prepared = prep.prepared(); - int paramsCnt = prepared.getParameters().size(); + int paramsCnt = prepared.getParameters().size(); - if (argsOrig != null && paramsCnt > 0) { - args = Arrays.copyOfRange(argsOrig, firstArg, firstArg + paramsCnt); + if (argsOrig != null && paramsCnt > 0) { + args = Arrays.copyOfRange(argsOrig, firstArg, firstArg + paramsCnt); - firstArg += paramsCnt; - } - else - args = null; + firstArg += paramsCnt; + } + else + args = null; + + if (cachedQry != null) { + twoStepQry = cachedQry.query().copy(); + meta = cachedQry.meta(); + + results.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, + qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, + twoStepQry, meta, cachedQryKey, cachedQry)); + continue; + } + else { if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery)qry).isQuery() != prepared.isQuery()) throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", IgniteQueryErrorCode.STMT_TYPE_MISMATCH); @@ -1365,115 +1381,85 @@ private Iterable> runQueryTwoStep( assert twoStepQry != null; } } - finally { - GridH2QueryContext.clearThreadLocal(); - } + } + finally { + GridH2QueryContext.clearThreadLocal(); + } - // It is a DML statement if we did not create a twoStepQuery. - if (twoStepQry == null) { - if (DmlStatementsProcessor.isDmlStatement(prepared)) { - try { - results.add(dmlProc.updateSqlFieldsDistributed(schemaName, prepared, - new SqlFieldsQuery(qry).setSql(sqlQry).setArgs(args), cancel)); + // It is a DML statement if we did not create a twoStepQuery. + if (twoStepQry == null) { + if (DmlStatementsProcessor.isDmlStatement(prepared)) { + try { + results.add(dmlProc.updateSqlFieldsDistributed(schemaName, prepared, + new SqlFieldsQuery(qry).setSql(sqlQry).setArgs(args), cancel)); - continue; - } - catch (IgniteCheckedException e) { - throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + - ", params=" + Arrays.deepToString(args) + "]", e); - } + continue; } - - if (DdlStatementsProcessor.isDdlStatement(prepared)) { - try { - results.add(ddlProc.runDdlStatement(sqlQry, prepared)); - - continue; - } - catch (IgniteCheckedException e) { - throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); - } + catch (IgniteCheckedException e) { + throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + + ", params=" + Arrays.deepToString(args) + "]", e); } } - LinkedHashSet caches0 = new LinkedHashSet<>(); - - assert twoStepQry != null; - - int tblCnt = twoStepQry.tablesCount(); - - if (mainCacheId != null) - caches0.add(mainCacheId); - - if (tblCnt > 0) { - for (QueryTable tblKey : twoStepQry.tables()) { - GridH2Table tbl = dataTable(tblKey); - - int cacheId = CU.cacheId(tbl.cacheName()); + if (DdlStatementsProcessor.isDdlStatement(prepared)) { + try { + results.add(ddlProc.runDdlStatement(sqlQry, prepared)); - caches0.add(cacheId); + continue; + } + catch (IgniteCheckedException e) { + throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); } } + } - if (caches0.isEmpty()) - twoStepQry.local(true); - else { - //Prohibit usage indices with different numbers of segments in same query. - List cacheIds = new ArrayList<>(caches0); - - checkCacheIndexSegmentation(cacheIds); - - twoStepQry.cacheIds(cacheIds); - twoStepQry.local(qry.isLocal()); - } + LinkedHashSet caches0 = new LinkedHashSet<>(); - meta = H2Utils.meta(stmt.getMetaData()); - } - catch (IgniteCheckedException e) { - throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + - Arrays.deepToString(qry.getArgs()) + "]", e); - } - catch (SQLException e) { - throw new IgniteSQLException(e); - } - finally { - U.close(stmt, log); - } - } + assert twoStepQry != null; - if (log.isDebugEnabled()) - log.debug("Parsed query: `" + sqlQry + "` into two step query: " + twoStepQry); + int tblCnt = twoStepQry.tablesCount(); - twoStepQry.pageSize(qry.getPageSize()); + if (mainCacheId != null) + caches0.add(mainCacheId); - if (cancel == null) - cancel = new GridQueryCancel(); + if (tblCnt > 0) { + for (QueryTable tblKey : twoStepQry.tables()) { + GridH2Table tbl = dataTable(tblKey); - int partitions[] = qry.getPartitions(); + int cacheId = CU.cacheId(tbl.cacheName()); - if (partitions == null && twoStepQry.derivedPartitions() != null) { - try { - partitions = calculateQueryPartitions(twoStepQry.derivedPartitions(), args); - } - catch (IgniteCheckedException e) { - throw new CacheException("Failed to calculate derived partitions: [qry=" + sqlQry + ", params=" + - Arrays.deepToString(args) + "]", e); + caches0.add(cacheId); + } } - } - QueryCursorImpl> cursor = new QueryCursorImpl<>( - runQueryTwoStep(schemaName, twoStepQry, keepBinary, enforceJoinOrder, qry.getTimeout(), cancel, - args, partitions, qry.isLazy()), cancel); + if (caches0.isEmpty()) + twoStepQry.local(true); + else { + //Prohibit usage indices with different numbers of segments in same query. + List cacheIds = new ArrayList<>(caches0); - cursor.fieldsMeta(meta); + checkCacheIndexSegmentation(cacheIds); - if (cachedQry == null && !twoStepQry.explain()) { - cachedQry = new H2TwoStepCachedQuery(meta, twoStepQry.copy()); + twoStepQry.cacheIds(cacheIds); + twoStepQry.local(qry.isLocal()); + } - twoStepCache.putIfAbsent(cachedQryKey, cachedQry); + meta = H2Utils.meta(stmt.getMetaData()); + } + catch (IgniteCheckedException e) { + throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + + Arrays.deepToString(qry.getArgs()) + "]", e); + } + catch (SQLException e) { + throw new IgniteSQLException(e); + } + finally { + U.close(stmt, log); } - results.add(cursor); + results.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, + qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, + twoStepQry, meta, cachedQryKey, cachedQry)); } return results; @@ -1633,28 +1619,52 @@ private Iterable> runQueryTwoStep( } } + return executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, + qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, + meta, cachedQryKey, cachedQry); + } + + /** + * @param schemaName Schema name. + * @param pageSize Page size. + * @param partitions Partitions. + * @param args Arguments. + * @param keepBinary Keep binary flag. + * @param lazy Lazy flag. + * @param timeout Timeout. + * @param cancel Cancel. + * @param sqlQry SQL query string. + * @param enforceJoinOrder Enforce join orded flag. + * @param twoStepQry Two-steps query. + * @param meta Metadata. + * @param cachedQryKey Cached query key. + * @param cachedQry Cached query. + * @return Cursor. + */ + public FieldsQueryCursor> executeTwoStepsQuery(String schemaName, int pageSize, int partitions[], + Object[] args, boolean keepBinary, boolean lazy, int timeout, + GridQueryCancel cancel, String sqlQry, boolean enforceJoinOrder, GridCacheTwoStepQuery twoStepQry, + List meta, H2TwoStepCachedQueryKey cachedQryKey, H2TwoStepCachedQuery cachedQry) { if (log.isDebugEnabled()) log.debug("Parsed query: `" + sqlQry + "` into two step query: " + twoStepQry); - twoStepQry.pageSize(qry.getPageSize()); + twoStepQry.pageSize(pageSize); if (cancel == null) cancel = new GridQueryCancel(); - int partitions[] = qry.getPartitions(); - if (partitions == null && twoStepQry.derivedPartitions() != null) { try { - partitions = calculateQueryPartitions(twoStepQry.derivedPartitions(), qry.getArgs()); + partitions = calculateQueryPartitions(twoStepQry.derivedPartitions(), args); } catch (IgniteCheckedException e) { throw new CacheException("Failed to calculate derived partitions: [qry=" + sqlQry + ", params=" + - Arrays.deepToString(qry.getArgs()) + "]", e); + Arrays.deepToString(args) + "]", e); } } QueryCursorImpl> cursor = new QueryCursorImpl<>( - runQueryTwoStep(schemaName, twoStepQry, keepBinary, enforceJoinOrder, qry.getTimeout(), cancel, - qry.getArgs(), partitions, qry.isLazy()), cancel); + runQueryTwoStep(schemaName, twoStepQry, keepBinary, enforceJoinOrder, timeout, cancel, + args, partitions, lazy), cancel); cursor.fieldsMeta(meta); From 44295708f0d46f430680954c9bdb20ae4843d783 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 12:39:35 +0300 Subject: [PATCH 06/36] IGNITE-6046: add jdbc test --- .../jdbc/thin/JdbcThinStatementSelfTest.java | 49 +++++++------------ .../jdbc/thin/JdbcThinDatabaseMetadata.java | 2 +- .../internal/jdbc/thin/JdbcThinStatement.java | 27 ++++++---- .../internal/jdbc/thin/JdbcThinTcpIo.java | 2 +- .../processors/odbc/jdbc/JdbcResult.java | 5 ++ 5 files changed, 43 insertions(+), 42 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java index 97e3300fa2728..705cd9d3fc799 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java @@ -415,21 +415,27 @@ public void testExecuteQueryTimeout() throws Exception { * @throws Exception If failed. */ public void testExecuteQueryMultipleResultSets() throws Exception { - assert !conn.getMetaData().supportsMultipleResultSets(); + assert conn.getMetaData().supportsMultipleResultSets(); - fail("https://issues.apache.org/jira/browse/IGNITE-6046"); + final String sqlText = "select 1; select 2"; - final String sqlText = "select 1; select 1"; + assert stmt.execute(sqlText); - GridTestUtils.assertThrows(log, - new Callable() { - @Override public Object call() throws Exception { - return stmt.executeQuery(sqlText); - } - }, - SQLException.class, - "Multiple result sets" - ); + ResultSet rs = stmt.getResultSet(); + + assert rs.next(); + assert rs.getInt(1) == 1; + assert !rs.next(); + + assert stmt.getMoreResults(); + + rs = stmt.getResultSet(); + + assert rs.next(); + assert rs.getInt(1) == 2; + assert !rs.next(); + + assert !stmt.getMoreResults(); } /** @@ -948,25 +954,6 @@ public void testAutogenerated() throws Exception { }); } - /** - * @throws Exception If failed. - */ - public void testCloseOnCompletion() throws Exception { - fail("https://issues.apache.org/jira/browse/IGNITE-5344"); - - assert !stmt.isCloseOnCompletion() : "Default value of CloseOnCompletion is invalid"; - - stmt.execute("select 1"); - - stmt.closeOnCompletion(); - - assert stmt.isCloseOnCompletion(); - - stmt.getResultSet().close(); - - assert stmt.isClosed() : "Must be closed on complete"; - } - /** * @throws Exception If failed. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java index b27fee6ef2e35..2f322d426bec0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinDatabaseMetadata.java @@ -305,7 +305,7 @@ public class JdbcThinDatabaseMetadata implements DatabaseMetaData { /** {@inheritDoc} */ @Override public boolean supportsMultipleResultSets() throws SQLException { - return false; + return true; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 4fea127fa2498..857d0c001552d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -142,9 +142,9 @@ protected void execute0(String sql, List args) throws SQLException { else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; - resultSets = Collections.emptyList(); - resInfo = res.results(); + + resultSets = new ArrayList<>(resInfo.size()); } else throw new SQLException("Unexpected result [res=" + res0 + ']'); @@ -341,12 +341,12 @@ private JdbcThinResultSet nextResultSet() throws SQLException { JdbcQueryFetchResult res = conn.io().queryFetch(qryId, pageSize); rs = new JdbcThinResultSet(this, qryId, pageSize, - res.last(), res.items(), true, conn.io().autoCloseServerCursor(),-1); + res.last(), res.items(), true, conn.io().autoCloseServerCursor(), -1, closeOnCompletion); } else { rs = new JdbcThinResultSet(this, -1, pageSize, true, Collections.>emptyList(), false, - conn.io().autoCloseServerCursor(),resInfo.get(curRes).updateCount()); + conn.io().autoCloseServerCursor(),resInfo.get(curRes).updateCount(), closeOnCompletion); } resultSets.add(rs); @@ -369,7 +369,6 @@ private JdbcThinResultSet nextResultSet() throws SQLException { ensureNotClosed(); return getMoreResults(CLOSE_CURRENT_RESULT); - return (resInfo != null && curRes < resInfo.size()); } /** {@inheritDoc} */ @@ -478,8 +477,16 @@ private JdbcThinResultSet nextResultSet() throws SQLException { switch (curr) { case CLOSE_CURRENT_RESULT: + if (resultSets != null && curRes < resultSets.size()) + resultSets.get(curRes - 1).close0(); + + break; + case CLOSE_ALL_RESULTS: - closeResults(); + if (resultSets != null) { + for (int i = 0; i < curRes; ++i) + resultSets.get(i).close0(); + } break; @@ -490,7 +497,7 @@ private JdbcThinResultSet nextResultSet() throws SQLException { throw new SQLException("Invalid 'current' parameter."); } - return false; + return (resInfo != null && curRes < resInfo.size()); } /** {@inheritDoc} */ @@ -612,8 +619,10 @@ private JdbcThinResultSet nextResultSet() throws SQLException { closeOnCompletion = true; - if (rs != null) - rs.closeStatement(true); + if (resultSets != null) { + for (JdbcThinResultSet rs : resultSets) + rs.closeStatement(true); + } } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java index b9dce0504332f..9f8538a578c39 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java @@ -265,7 +265,7 @@ public void handshake() throws IOException, IgniteCheckedException { * @throws IOException On error. * @throws IgniteCheckedException On error. */ - public JdbcQueryExecuteResult queryExecute(String cache, int fetchSize, int maxRows, + public JdbcResult queryExecute(String cache, int fetchSize, int maxRows, String sql, List args) throws IOException, IgniteCheckedException { return sendRequest(new JdbcQueryExecuteRequest(cache, fetchSize, maxRows, sql, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java index 0df3db89d13e4..c6c74383381f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResult.java @@ -142,6 +142,11 @@ public static JdbcResult readResult(BinaryReaderExImpl reader) throws BinaryObje break; + case QRY_EXEC_MULT: + res = new JdbcQueryExecuteMultipleStatementsResult(); + + break; + default: throw new IgniteException("Unknown SQL listener request ID: [request ID=" + resId + ']'); } From 96e22b6cb72a09ef04b78693f2957322e48a1c56 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 12:44:34 +0300 Subject: [PATCH 07/36] IGNITE-6046: minors --- .../org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java | 1 - .../ignite/internal/processors/query/h2/IgniteH2Indexing.java | 2 -- 2 files changed, 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 857d0c001552d..9630e983570e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -27,7 +27,6 @@ import java.sql.Statement; import java.util.ArrayList; import java.util.Collections; -import java.util.Iterator; import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.query.SqlQuery; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 573ad994669d7..afa8606bd12f6 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -144,13 +144,11 @@ import org.h2.engine.Session; import org.h2.engine.SysProperties; import org.h2.index.Index; -import org.h2.jdbc.JdbcPreparedStatement; import org.h2.jdbc.JdbcStatement; import org.h2.server.web.WebServer; import org.h2.table.IndexColumn; import org.h2.tools.Server; import org.h2.util.JdbcUtils; -import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jsr166.ConcurrentHashMap8; From 1d4de2f43c15527df21bf94e0b909d1fb34c3cea Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 14:47:35 +0300 Subject: [PATCH 08/36] IGNITE-6046: refactoring --- .../internal/jdbc/thin/JdbcThinStatement.java | 26 +- .../odbc/jdbc/JdbcRequestHandler.java | 4 +- .../odbc/odbc/OdbcRequestHandler.java | 23 +- .../processors/query/GridQueryIndexing.java | 16 +- .../processors/query/GridQueryProcessor.java | 60 +--- ...niteClientCacheInitializationFailTest.java | 8 +- .../query/h2/DmlStatementsProcessor.java | 10 +- .../processors/query/h2/IgniteH2Indexing.java | 331 +++++++++--------- .../index/DynamicColumnsAbstractTest.java | 5 +- .../index/H2DynamicIndexingComplexTest.java | 7 +- .../cache/index/H2DynamicTableSelfTest.java | 4 +- .../MultipleStatementsSqlQuerySelfTest.java | 4 +- .../processors/query/SqlSchemaSelfTest.java | 8 +- 13 files changed, 250 insertions(+), 256 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 9630e983570e5..86d2ff4d6141f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -474,26 +474,28 @@ private JdbcThinResultSet nextResultSet() throws SQLException { @Override public boolean getMoreResults(int curr) throws SQLException { ensureNotClosed(); - switch (curr) { - case CLOSE_CURRENT_RESULT: - if (resultSets != null && curRes < resultSets.size()) + if (resultSets != null) { + assert curRes <= resultSets.size() : "Invalid results state: [resultsCount=" + resultSets.size() + + ", curRes=" + curRes + ']'; + + switch (curr) { + case CLOSE_CURRENT_RESULT: resultSets.get(curRes - 1).close0(); - break; + break; - case CLOSE_ALL_RESULTS: - if (resultSets != null) { + case CLOSE_ALL_RESULTS: for (int i = 0; i < curRes; ++i) resultSets.get(i).close0(); - } - break; + break; - case KEEP_CURRENT_RESULT: - break; + case KEEP_CURRENT_RESULT: + break; - default: - throw new SQLException("Invalid 'current' parameter."); + default: + throw new SQLException("Invalid 'current' parameter."); + } } return (resInfo != null && curRes < resInfo.size()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index a8cc0fab93ca0..6d1f1349a5f0d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -246,7 +246,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qry.setSchema(schemaName); - List>> results = ctx.query().querySqlFieldsNoCache0(qry, true); + List>> results = ctx.query().querySqlFieldsNoCache(qry, true); if (results.size() == 1) { FieldsQueryCursor> qryCur = results.get(0); @@ -433,7 +433,7 @@ private SqlListenerResponse executeBatch(JdbcBatchExecuteRequest req) { qry.setSchema(schemaName); QueryCursorImpl> qryCur = (QueryCursorImpl>)ctx.query() - .querySqlFieldsNoCache(qry, true); + .querySqlFieldsNoCache(qry, true).get(0); if (qryCur.isQuery()) throw new IgniteCheckedException("Query produced result set [qry=" + q.sql() + ", args=" + diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java index 7677c03bfd9ad..c40c7f14dabee 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java @@ -29,6 +29,7 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.GridKernalContext; @@ -42,6 +43,7 @@ import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; import org.apache.ignite.internal.processors.query.GridQueryIndexing; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; +import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; @@ -216,7 +218,12 @@ private SqlListenerResponse executeQuery(OdbcQueryExecuteRequest req) { SqlFieldsQuery qry = makeQuery(req.schema(), sql, req.arguments()); - QueryCursor qryCur = ctx.query().querySqlFieldsNoCache(qry, true); + List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + QueryCursor qryCur = curLst.get(0); qryCursors.put(qryId, new IgniteBiTuple(qryCur, null)); @@ -263,7 +270,12 @@ private SqlListenerResponse executeBatchQuery(OdbcQueryExecuteBatchRequest req) // Getting meta and do the checks for the first execution. qry.setArgs(paramSet[0]); - QueryCursorImpl> qryCur = (QueryCursorImpl>)ctx.query().querySqlFieldsNoCache(qry, true); + List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + QueryCursorImpl> qryCur = (QueryCursorImpl>)curLst.get(0); if (qryCur.isQuery()) throw new IgniteException("Batching of parameters only supported for DML statements. [query=" + @@ -297,7 +309,12 @@ private SqlListenerResponse executeBatchQuery(OdbcQueryExecuteBatchRequest req) private long executeQuery(SqlFieldsQuery qry, Object[] row) { qry.setArgs(row); - QueryCursor> cur = ctx.query().querySqlFieldsNoCache(qry, true); + List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + QueryCursor> cur = curLst.get(0); return getRowsAffected(cur); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 00b7ce1d59f74..d7bd322975a97 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -86,21 +86,7 @@ public QueryCursor> queryDistributedSql(String schemaNa * @return Cursor. * @throws IgniteCheckedException If failed. */ - public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, - boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException; - - /** - * Parses SQL query into two step query and executes it. - * - * @param schemaName Schema name. - * @param qry Query. - * @param keepBinary Keep binary flag. - * @param cancel Query cancel. - * @param mainCacheId Main cache ID. - * @return Cursor. - * @throws IgniteCheckedException If failed. - */ - public List>> queryDistributedSqlFieldsMultiple(String schemaName, SqlFieldsQuery qry, + public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException; /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index a9fa764837206..16058534b9687 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1862,7 +1862,13 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct if (cctx.config().getQueryParallelism() > 1) { qry.setDistributedJoins(true); - cur = idx.queryDistributedSqlFields(schemaName, qry, keepBinary, cancel, mainCacheId); + List>> curLst = idx.queryDistributedSqlFields(schemaName, qry, + keepBinary, cancel, mainCacheId); + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + cur = curLst.get(0); } else { IndexingQueryFilter filter = idx.backupFilter(requestTopVer.get(), qry.getPartitions()); @@ -1879,7 +1885,13 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct else { clo = new IgniteOutClosureX>>() { @Override public FieldsQueryCursor> applyx() throws IgniteCheckedException { - return idx.queryDistributedSqlFields(schemaName, qry, keepBinary, null, mainCacheId); + List>> curLst = + idx.queryDistributedSqlFields(schemaName, qry, keepBinary, null, mainCacheId); + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + return curLst.get(0); } }; } @@ -1901,47 +1913,7 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct * @param keepBinary Keep binary flag. * @return Cursor. */ - public FieldsQueryCursor> querySqlFieldsNoCache(final SqlFieldsQuery qry, final boolean keepBinary) { - checkxEnabled(); - - validateSqlFieldsQuery(qry); - - if (qry.isLocal()) - throw new IgniteException("Local query is not supported without specific cache."); - - if (qry.getSchema() == null) - qry.setSchema(QueryUtils.DFLT_SCHEMA); - - if (!busyLock.enterBusy()) - throw new IllegalStateException("Failed to execute query (grid is stopping)."); - - try { - IgniteOutClosureX>> clo = new IgniteOutClosureX>>() { - @Override public FieldsQueryCursor> applyx() throws IgniteCheckedException { - GridQueryCancel cancel = new GridQueryCancel(); - - return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null); - } - }; - - return executeQuery(GridCacheQueryType.SQL_FIELDS, qry.getSql(), null, clo, true); - } - catch (IgniteCheckedException e) { - throw new CacheException(e); - } - finally { - busyLock.leaveBusy(); - } - } - - /** - * Query SQL fields without strict dependency on concrete cache. - * - * @param qry Query. - * @param keepBinary Keep binary flag. - * @return Cursor. - */ - public List>> querySqlFieldsNoCache0(final SqlFieldsQuery qry, final boolean keepBinary) { + public List>> querySqlFieldsNoCache(final SqlFieldsQuery qry, final boolean keepBinary) { checkxEnabled(); validateSqlFieldsQuery(qry); @@ -1960,7 +1932,7 @@ public List>> querySqlFieldsNoCache0(final SqlFieldsQu @Override public List>> applyx() throws IgniteCheckedException { GridQueryCancel cancel = new GridQueryCancel(); - return idx.queryDistributedSqlFieldsMultiple(qry.getSchema(), qry, keepBinary, cancel, null); + return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null); } }; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java index 430f663330494..1e325e28be3d3 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java @@ -242,13 +242,7 @@ private static class FailedIndexing implements GridQueryIndexing { } /** {@inheritDoc} */ - @Override public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, - boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException { - return null; - } - - /** {@inheritDoc} */ - @Override public List>> queryDistributedSqlFieldsMultiple(String schemaName, SqlFieldsQuery qry, + @Override public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException { return null; } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index ed894afa1fcc2..60fda83f585aa 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -46,6 +46,8 @@ import org.apache.ignite.IgniteLogger; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectBuilder; +import org.apache.ignite.cache.query.FieldsQueryCursor; +import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridKernalContext; @@ -377,8 +379,12 @@ private UpdateResult executeUpdateStatement(String schemaName, final GridCacheCo .setPageSize(fieldsQry.getPageSize()) .setTimeout(fieldsQry.getTimeout(), TimeUnit.MILLISECONDS); - cur = (QueryCursorImpl>) idx.queryDistributedSqlFields(schemaName, newFieldsQry, true, cancel, - mainCacheId); + List>> curLst = idx.queryDistributedSqlFields(schemaName, newFieldsQry, true, + cancel, mainCacheId); + + assert curLst.size() == 1 : "Multiple statements query is not expected in DML select"; + + cur = (QueryCursorImpl>)curLst.get(0); } else { final GridQueryFieldsResult res = idx.queryLocalSqlFields(schemaName, plan.selectQry, diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index afa8606bd12f6..c6dd0c6db4b03 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1243,7 +1243,12 @@ private Iterable> runQueryTwoStep( if (qry.getTimeout() > 0) fqry.setTimeout(qry.getTimeout(), TimeUnit.MILLISECONDS); - final QueryCursor> res = queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId); + List>> curLst = queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId);; + + if (curLst.size() > 1) + throw new IgniteSQLException("Multiple statements queries are not supported"); + + final QueryCursor> res = curLst.get(0); final Iterable> converted = new Iterable>() { @Override public Iterator> iterator() { @@ -1276,7 +1281,7 @@ private Iterable> runQueryTwoStep( } /** {@inheritDoc} */ - @Override public List>> queryDistributedSqlFieldsMultiple(String schemaName, + @Override public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { Connection c = connectionForSchema(schemaName); @@ -1375,6 +1380,10 @@ private Iterable> runQueryTwoStep( else args = null; + cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, + distributedJoins, enforceJoinOrder, qry.isLocal()); + cachedQry = twoStepCache.get(cachedQryKey); + if (cachedQry != null) { twoStepQry = cachedQry.query().copy(); meta = cachedQry.meta(); @@ -1483,165 +1492,165 @@ private Iterable> runQueryTwoStep( return results; } - /** {@inheritDoc} */ - @Override public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, - SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { - final String sqlQry = qry.getSql(); - - Connection c = connectionForSchema(schemaName); - - final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); - final boolean distributedJoins = qry.isDistributedJoins(); - final boolean grpByCollocated = qry.isCollocated(); - - final DistributedJoinMode distributedJoinMode = distributedJoinMode(qry.isLocal(), distributedJoins); - - GridCacheTwoStepQuery twoStepQry = null; - List meta; - - final H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, - distributedJoins, enforceJoinOrder, qry.isLocal()); - H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); - - if (cachedQry != null) { - twoStepQry = cachedQry.query().copy(); - meta = cachedQry.meta(); - } - else { - final UUID locNodeId = ctx.localNodeId(); - - // Here we will just parse the statement, no need to optimize it at all. - H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); - - GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) - .distributedJoinMode(distributedJoinMode)); - - PreparedStatement stmt = null; - Prepared prepared; - - boolean cachesCreated = false; - - try { - try { - while (true) { - try { - // Do not cache this statement because the whole query object will be cached later on. - stmt = prepareStatement(c, sqlQry, false); - - break; - } - catch (SQLException e) { - if (!cachesCreated && ( - e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || - e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) - ) { - try { - ctx.cache().createMissingQueryCaches(); - } - catch (IgniteCheckedException ignored) { - throw new CacheException("Failed to create missing caches.", e); - } - - cachesCreated = true; - } - else - throw new IgniteSQLException("Failed to parse query: " + sqlQry, - IgniteQueryErrorCode.PARSING, e); - } - } - - prepared = GridSqlQueryParser.prepared(stmt); - - if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery) qry).isQuery() != prepared.isQuery()) - throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", - IgniteQueryErrorCode.STMT_TYPE_MISMATCH); - - if (prepared.isQuery()) { - bindParameters(stmt, F.asList(qry.getArgs())); - - twoStepQry = GridSqlQuerySplitter.split(c, prepared, qry.getArgs(), - grpByCollocated, distributedJoins, enforceJoinOrder, this); - - assert twoStepQry != null; - } - } - finally { - GridH2QueryContext.clearThreadLocal(); - } - - // It is a DML statement if we did not create a twoStepQuery. - if (twoStepQry == null) { - if (DmlStatementsProcessor.isDmlStatement(prepared)) { - try { - return dmlProc.updateSqlFieldsDistributed(schemaName, prepared, qry, cancel); - } - catch (IgniteCheckedException e) { - throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + - ", params=" + Arrays.deepToString(qry.getArgs()) + "]", e); - } - } - - if (DdlStatementsProcessor.isDdlStatement(prepared)) { - try { - return ddlProc.runDdlStatement(sqlQry, prepared); - } - catch (IgniteCheckedException e) { - throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); - } - } - } - - LinkedHashSet caches0 = new LinkedHashSet<>(); - - assert twoStepQry != null; - - int tblCnt = twoStepQry.tablesCount(); - - if (mainCacheId != null) - caches0.add(mainCacheId); - - if (tblCnt > 0) { - for (QueryTable tblKey : twoStepQry.tables()) { - GridH2Table tbl = dataTable(tblKey); - - int cacheId = CU.cacheId(tbl.cacheName()); - - caches0.add(cacheId); - } - } - - if (caches0.isEmpty()) - twoStepQry.local(true); - else { - //Prohibit usage indices with different numbers of segments in same query. - List cacheIds = new ArrayList<>(caches0); - - checkCacheIndexSegmentation(cacheIds); - - twoStepQry.cacheIds(cacheIds); - twoStepQry.local(qry.isLocal()); - } - - meta = H2Utils.meta(stmt.getMetaData()); - } - catch (IgniteCheckedException e) { - throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + - Arrays.deepToString(qry.getArgs()) + "]", e); - } - catch (SQLException e) { - throw new IgniteSQLException(e); - } - finally { - U.close(stmt, log); - } - } - - return executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, - qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, - meta, cachedQryKey, cachedQry); - } - +// /** {@inheritDoc} */ +// @Override public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, +// SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { +// final String sqlQry = qry.getSql(); +// +// Connection c = connectionForSchema(schemaName); +// +// final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); +// final boolean distributedJoins = qry.isDistributedJoins(); +// final boolean grpByCollocated = qry.isCollocated(); +// +// final DistributedJoinMode distributedJoinMode = distributedJoinMode(qry.isLocal(), distributedJoins); +// +// GridCacheTwoStepQuery twoStepQry = null; +// List meta; +// +// final H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, +// distributedJoins, enforceJoinOrder, qry.isLocal()); +// H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); +// +// if (cachedQry != null) { +// twoStepQry = cachedQry.query().copy(); +// meta = cachedQry.meta(); +// } +// else { +// final UUID locNodeId = ctx.localNodeId(); +// +// // Here we will just parse the statement, no need to optimize it at all. +// H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); +// +// GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) +// .distributedJoinMode(distributedJoinMode)); +// +// PreparedStatement stmt = null; +// Prepared prepared; +// +// boolean cachesCreated = false; +// +// try { +// try { +// while (true) { +// try { +// // Do not cache this statement because the whole query object will be cached later on. +// stmt = prepareStatement(c, sqlQry, false); +// +// break; +// } +// catch (SQLException e) { +// if (!cachesCreated && ( +// e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || +// e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || +// e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) +// ) { +// try { +// ctx.cache().createMissingQueryCaches(); +// } +// catch (IgniteCheckedException ignored) { +// throw new CacheException("Failed to create missing caches.", e); +// } +// +// cachesCreated = true; +// } +// else +// throw new IgniteSQLException("Failed to parse query: " + sqlQry, +// IgniteQueryErrorCode.PARSING, e); +// } +// } +// +// prepared = GridSqlQueryParser.prepared(stmt); +// +// if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery) qry).isQuery() != prepared.isQuery()) +// throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", +// IgniteQueryErrorCode.STMT_TYPE_MISMATCH); +// +// if (prepared.isQuery()) { +// bindParameters(stmt, F.asList(qry.getArgs())); +// +// twoStepQry = GridSqlQuerySplitter.split(c, prepared, qry.getArgs(), +// grpByCollocated, distributedJoins, enforceJoinOrder, this); +// +// assert twoStepQry != null; +// } +// } +// finally { +// GridH2QueryContext.clearThreadLocal(); +// } +// +// // It is a DML statement if we did not create a twoStepQuery. +// if (twoStepQry == null) { +// if (DmlStatementsProcessor.isDmlStatement(prepared)) { +// try { +// return dmlProc.updateSqlFieldsDistributed(schemaName, prepared, qry, cancel); +// } +// catch (IgniteCheckedException e) { +// throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + +// ", params=" + Arrays.deepToString(qry.getArgs()) + "]", e); +// } +// } +// +// if (DdlStatementsProcessor.isDdlStatement(prepared)) { +// try { +// return ddlProc.runDdlStatement(sqlQry, prepared); +// } +// catch (IgniteCheckedException e) { +// throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); +// } +// } +// } +// +// LinkedHashSet caches0 = new LinkedHashSet<>(); +// +// assert twoStepQry != null; +// +// int tblCnt = twoStepQry.tablesCount(); +// +// if (mainCacheId != null) +// caches0.add(mainCacheId); +// +// if (tblCnt > 0) { +// for (QueryTable tblKey : twoStepQry.tables()) { +// GridH2Table tbl = dataTable(tblKey); +// +// int cacheId = CU.cacheId(tbl.cacheName()); +// +// caches0.add(cacheId); +// } +// } +// +// if (caches0.isEmpty()) +// twoStepQry.local(true); +// else { +// //Prohibit usage indices with different numbers of segments in same query. +// List cacheIds = new ArrayList<>(caches0); +// +// checkCacheIndexSegmentation(cacheIds); +// +// twoStepQry.cacheIds(cacheIds); +// twoStepQry.local(qry.isLocal()); +// } +// +// meta = H2Utils.meta(stmt.getMetaData()); +// } +// catch (IgniteCheckedException e) { +// throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + +// Arrays.deepToString(qry.getArgs()) + "]", e); +// } +// catch (SQLException e) { +// throw new IgniteSQLException(e); +// } +// finally { +// U.close(stmt, log); +// } +// } +// +// return executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, +// qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, +// meta, cachedQryKey, cachedQry); +// } +// /** * @param schemaName Schema name. * @param pageSize Page size. diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java index 75b9a3051e7e8..050829c15deda 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java @@ -280,13 +280,15 @@ IgniteConfiguration serverConfiguration(int idx) throws Exception { */ protected List> run(Ignite node, String sql) { return ((IgniteEx)node).context().query() - .querySqlFieldsNoCache(new SqlFieldsQuery(sql).setSchema(QueryUtils.DFLT_SCHEMA), true).getAll(); + .querySqlFieldsNoCache(new SqlFieldsQuery(sql).setSchema(QueryUtils.DFLT_SCHEMA), true) + .get(0).getAll(); } /** * Execute SQL command and return resulting dataset. * @param cache Cache to initiate query from. * @param sql Statement. + * @param args Query parameters. * @return result. */ protected List> run(IgniteCache cache, String sql, Object... args) { @@ -295,6 +297,7 @@ protected List> run(IgniteCache cache, String sql, Object... args) /** * Run specified statement expected to throw {@code IgniteSqlException} with expected specified message. + * @param node Ignite node. * @param sql Statement. * @param msg Expected message. */ diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java index 0be691e072f1f..ab169ee1250fb 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java @@ -314,16 +314,20 @@ private void assertPerson(int id, String name, int age, String company, String c /** * Run SQL statement on specified node. + * @param node Ignite node. * @param stmt Statement to run. + * @param args Query parameters * @return Run result. */ private List> executeSql(IgniteEx node, String stmt, Object... args) { - return node.context().query().querySqlFieldsNoCache(new SqlFieldsQuery(stmt).setArgs(args), true).getAll(); + return node.context().query().querySqlFieldsNoCache(new SqlFieldsQuery(stmt).setArgs(args), true) + .get(0).getAll(); } /** * Run SQL statement on default node. * @param stmt Statement to run. + * @param args Query parameters. * @return Run result. */ private List> executeSql(String stmt, Object... args) { @@ -333,6 +337,7 @@ private List> executeSql(String stmt, Object... args) { /** * Run SQL statement that is expected to return strictly one value (like COUNT(*)). * @param stmt Statement to run. + * @param args Query parameters. * @return Run result. */ private Object executeSqlSingle(String stmt, Object... args) { diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java index d737a0f28dd6c..147a8835a2f72 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java @@ -595,12 +595,12 @@ public void testAffinityKey() throws Exception { personId2cityCode.put(i, cityCode); queryProcessor(client()).querySqlFieldsNoCache(new SqlFieldsQuery("insert into \"Person2\"(\"id\", " + - "\"city\") values (?, ?)").setArgs(i, cityName), true).getAll(); + "\"city\") values (?, ?)").setArgs(i, cityName), true).get(0).getAll(); } List> res = queryProcessor(client()).querySqlFieldsNoCache(new SqlFieldsQuery("select \"id\", " + "c.\"code\" from \"Person2\" p left join \"City\" c on p.\"city\" = c.\"name\" where c.\"name\" " + - "is not null"), true).getAll(); + "is not null"), true).get(0).getAll(); assertEquals(100, res.size()); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index 905b9a3455280..bd6c319484424 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -58,7 +58,7 @@ public void testQuery() throws Exception { "select * from test;") .setSchema("PUBLIC"); - List>> res = qryProc.querySqlFieldsNoCache0(qry, true); + List>> res = qryProc.querySqlFieldsNoCache(qry, true); assert res.size() == 4 : "Unexpected cursors count: " + res.size(); @@ -104,7 +104,7 @@ public void testQueryWithParameters() throws Exception { .setSchema("PUBLIC") .setArgs(1, "name_1", 2, "name2", 3, "name_3"); - List>> res = qryProc.querySqlFieldsNoCache0(qry, true); + List>> res = qryProc.querySqlFieldsNoCache(qry, true); assert res.size() == 4 : "Unexpected cursors count: " + res.size(); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java index 8aaccefcfa0f2..467b958e42c61 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java @@ -63,13 +63,13 @@ public void testQueryWithoutCacheOnPublicSchema() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery("SELECT 1").setSchema("PUBLIC"); - List> res = qryProc.querySqlFieldsNoCache(qry, true).getAll(); + List> res = qryProc.querySqlFieldsNoCache(qry, true).get(0).getAll(); assertEquals(1, res.size()); assertEquals(1, res.get(0).size()); assertEquals(1, res.get(0).get(0)); - Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).iterator(); + Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).get(0).iterator(); assertTrue(iter.hasNext()); @@ -95,13 +95,13 @@ public void testQueryWithoutCacheOnCacheSchema() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery("SELECT 1").setSchema(CACHE_PERSON); - List> res = qryProc.querySqlFieldsNoCache(qry, true).getAll(); + List> res = qryProc.querySqlFieldsNoCache(qry, true).get(0).getAll(); assertEquals(1, res.size()); assertEquals(1, res.get(0).size()); assertEquals(1, res.get(0).get(0)); - Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).iterator(); + Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).get(0).iterator(); assertTrue(iter.hasNext()); From df43b69b2c88fe7788cbe09865e62cf1ba4f3464 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 15:48:43 +0300 Subject: [PATCH 09/36] IGNITE-6046: cosmetic --- ...cQueryExecuteMultipleStatementsResult.java | 20 ------------------- .../odbc/jdbc/JdbcQueryExecuteResult.java | 7 ------- .../query/h2/ddl/DdlStatementsProcessor.java | 2 ++ 3 files changed, 2 insertions(+), 27 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java index f1341d60fc820..4f0c5d4edfd44 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java @@ -39,26 +39,6 @@ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { super(QRY_EXEC_MULT); } -// /** -// * @param queryId Query ID. -// * @param items Query result rows. -// * @param last Flag indicates the query has no unfetched results. -// * @param results Statements results. -// */ -// public JdbcQueryExecuteMultipleStatementsResult(long queryId, List> items, boolean last, List results) { -// super(QRY_EXEC_MULT); -// this.results = results; -// } -// -// /** -// * @param updCnt Update count. -// * @param results Statements results. -// */ -// public JdbcQueryExecuteMultipleStatementsResult(long updCnt, List results) { -// super(QRY_EXEC_MULT); -// this.results = results; -// } - /** * @param results Statements results. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java index 4ab5e1c547ee2..fdebdb8c3c450 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteResult.java @@ -49,13 +49,6 @@ public class JdbcQueryExecuteResult extends JdbcResult { super(QRY_EXEC); } - /** - * @param type Result type. - */ - protected JdbcQueryExecuteResult(byte type) { - super(type); - } - /** * @param queryId Query ID. * @param items Query result rows. diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index 32f9c8d7da897..ac2d8af51d49e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -89,6 +89,8 @@ public void start(final GridKernalContext ctx, IgniteH2Indexing idx) { * * @param sql SQL. * @param prepared Prepared. + * @return Cursor on query results. + * @throws IgniteCheckedException On error. */ @SuppressWarnings({"unchecked", "ThrowableResultOfMethodCallIgnored"}) public FieldsQueryCursor> runDdlStatement(String sql, Prepared prepared) From 0442727cea44e3287f7aee19f9322e0fda1a5c64 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 17:00:08 +0300 Subject: [PATCH 10/36] IGNITE-6046: saver progress --- .../jdbc/thin/JdbcThinPreparedStatement.java | 2 +- .../internal/jdbc/thin/JdbcThinResultSet.java | 2 +- .../internal/jdbc/thin/JdbcThinStatement.java | 80 ++++++++----------- ...cQueryExecuteMultipleStatementsResult.java | 38 ++++++++- .../odbc/jdbc/JdbcRequestHandler.java | 9 ++- .../query/h2/DmlStatementsProcessor.java | 2 + .../processors/query/h2/IgniteH2Indexing.java | 1 + .../MultipleStatementsSqlQuerySelfTest.java | 3 +- 8 files changed, 85 insertions(+), 52 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java index bad388584910a..6279840bd648b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinPreparedStatement.java @@ -232,7 +232,7 @@ public class JdbcThinPreparedStatement extends JdbcThinStatement implements Prep @Override public boolean execute() throws SQLException { executeWithArguments(); - return resInfo.get(0).isQuery(); + return resultSets.get(0).isQuery(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java index 0a0c9780f3654..9aef035668f11 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java @@ -185,7 +185,7 @@ public class JdbcThinResultSet implements ResultSet { this.fetchSize = fetchSize; this.rows = rows; - rowsIter = rows.iterator(); + rowsIter = rows != null ? rows.iterator() : null; } else this.updCnt = updCnt; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 86d2ff4d6141f..f2d9c3347bc55 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -35,7 +35,6 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteMultipleStatementsResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementResults; @@ -77,9 +76,6 @@ public class JdbcThinStatement implements Statement { /** Result sets. */ protected List resultSets; - /** Multiple statement result info. */ - protected List resInfo; - /** Current result. */ protected int curRes; @@ -134,21 +130,42 @@ protected void execute0(String sql, List args) throws SQLException { resultSets = Collections.singletonList(new JdbcThinResultSet(this, res.getQueryId(), pageSize, res.last(), res.items(), res.isQuery(), conn.io().autoCloseServerCursor(), res.updateCount(), closeOnCompletion)); - - resInfo = Collections.singletonList(new JdbcStatementResults(res.isQuery(), - res.isQuery() ? res.getQueryId() : res.updateCount())); } else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; - resInfo = res.results(); - - resultSets = new ArrayList<>(resInfo.size()); + List resInfos = res.results(); + + resultSets = new ArrayList<>(resInfos.size()); + + boolean firstRes = true; + + for(JdbcStatementResults rsInfo : resInfos) { + if (!rsInfo.isQuery()) { + resultSets.add(new JdbcThinResultSet(this, -1, pageSize, + true, Collections.>emptyList(), false, + conn.io().autoCloseServerCursor(), rsInfo.updateCount(), closeOnCompletion)); + } + else { + if (firstRes) { + firstRes = false; + + resultSets.add(new JdbcThinResultSet(this, rsInfo.queryId(), pageSize, + res.isLast(), res.items(), true, + conn.io().autoCloseServerCursor(), -1, closeOnCompletion)); + } + else { + resultSets.add(new JdbcThinResultSet(this, rsInfo.queryId(), pageSize, + false, null, true, + conn.io().autoCloseServerCursor(), -1, closeOnCompletion)); + } + } + } } else throw new SQLException("Unexpected result [res=" + res0 + ']'); - assert resInfo.size() > 0 : "At least one results set is expected"; + assert resultSets.size() > 0 : "At least one results set is expected"; } catch (IOException e) { conn.close(); @@ -192,7 +209,6 @@ private void closeResults() throws SQLException { rs.close0(); resultSets = null; - resInfo = null; curRes = 0; } } @@ -283,7 +299,7 @@ private void closeResults() throws SQLException { execute0(sql, null); - return resInfo.get(0).isQuery(); + return resultSets.get(0).isQuery(); } /** {@inheritDoc} */ @@ -327,40 +343,10 @@ private void closeResults() throws SQLException { private JdbcThinResultSet nextResultSet() throws SQLException { ensureNotClosed(); - if (resultSets == null || resInfo == null || curRes >= resInfo.size()) + if (resultSets == null || curRes >= resultSets.size()) return null; - - if (curRes >= resultSets.size()) { - try { - JdbcThinResultSet rs; - - if (resInfo.get(curRes).isQuery()) { - long qryId = resInfo.get(curRes).queryId(); - - JdbcQueryFetchResult res = conn.io().queryFetch(qryId, pageSize); - - rs = new JdbcThinResultSet(this, qryId, pageSize, - res.last(), res.items(), true, conn.io().autoCloseServerCursor(), -1, closeOnCompletion); - } - else { - rs = new JdbcThinResultSet(this, -1, pageSize, - true, Collections.>emptyList(), false, - conn.io().autoCloseServerCursor(),resInfo.get(curRes).updateCount(), closeOnCompletion); - } - - resultSets.add(rs); - } - catch (IOException e) { - conn.close(); - - throw new SQLException("Failed get next results.", e); - } - catch (IgniteCheckedException e) { - throw new SQLException("Failed get next results.", e); - } - } - - return resultSets.get(curRes++); + else + return resultSets.get(curRes++); } /** {@inheritDoc} */ @@ -498,7 +484,7 @@ private JdbcThinResultSet nextResultSet() throws SQLException { } } - return (resInfo != null && curRes < resInfo.size()); + return (resultSets != null && curRes < resultSets.size()); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java index 4f0c5d4edfd44..24363937129ee 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java @@ -32,6 +32,12 @@ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { /** Statements results. */ private List results; + /** Query result rows for the first query. */ + private List> items; + + /** Flag indicating the query has no unfetched results for the first query. */ + private boolean last; + /** * Default constructor. */ @@ -41,10 +47,15 @@ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { /** * @param results Statements results. + * @param items Query result rows for the first query. + * @param last Flag indicating the query has no unfetched results for the first query. */ - public JdbcQueryExecuteMultipleStatementsResult(List results) { + public JdbcQueryExecuteMultipleStatementsResult(List results, + List> items, boolean last) { super(QRY_EXEC_MULT); this.results = results; + this.items = items; + this.last = last; } /** @@ -54,6 +65,20 @@ public List results() { return results; } + /** + * @return Query result rows for the first query. + */ + public List> items() { + return items; + } + + /** + * @return Flag indicating the query has no unfetched results for the first query. + */ + public boolean isLast() { + return last; + } + /** {@inheritDoc} */ @Override public void writeBinary(BinaryWriterExImpl writer) throws BinaryObjectException { super.writeBinary(writer); @@ -64,6 +89,11 @@ public List results() { for (JdbcStatementResults r : results) r.writeBinary(writer); + if (results.get(0).isQuery()) { + writer.writeBoolean(last); + + JdbcUtils.writeItems(writer, items); + } } else writer.writeInt(0); } @@ -87,6 +117,12 @@ public List results() { results.add(r); } + + if (results.get(0).isQuery()) { + last = reader.readBoolean(); + + items = JdbcUtils.readItems(reader); + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 6d1f1349a5f0d..668f209970e59 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -277,6 +277,8 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { } else { List jdbcResults = new ArrayList<>(results.size()); + List> items = null; + boolean last = true; for (FieldsQueryCursor> c : results) { QueryCursorImpl qryCur = (QueryCursorImpl)c; @@ -291,6 +293,11 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qryCursors.put(qryId, cur); qryId = QRY_ID_GEN.getAndIncrement(); + + if (items == null) { + items = cur.fetchRows(); + last = cur.hasNext(); + } } else jdbcRes = new JdbcStatementResults(false, (Long)((List)qryCur.getAll().get(0)).get(0)); @@ -298,7 +305,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { jdbcResults.add(jdbcRes); } - return new JdbcResponse(new JdbcQueryExecuteMultipleStatementsResult(jdbcResults)); + return new JdbcResponse(new JdbcQueryExecuteMultipleStatementsResult(jdbcResults, items, last)); } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index 60fda83f585aa..3d44d9b5ba24d 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -343,7 +343,9 @@ long streamUpdateQuery(IgniteDataStreamer streamer, PreparedStatement stmt, Obje * @param cctx Cache context. * @param prepared Prepared statement for DML query. * @param fieldsQry Fields query. + * @param loc Local query flag. * @param filters Cache name and key filter. + * @param cancel Query cancel state holder. * @param failedKeys Keys to restrict UPDATE and DELETE operations with. Null or empty array means no restriction. * @return Pair [number of successfully processed items; keys that have failed to be processed] * @throws IgniteCheckedException if failed. diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index c6dd0c6db4b03..1e680dd29079e 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1385,6 +1385,7 @@ private Iterable> runQueryTwoStep( cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { + System.out.println("+++ cached " + cachedQry); twoStepQry = cachedQry.query().copy(); meta = cachedQry.meta(); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index bd6c319484424..c450098a59162 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -99,7 +99,8 @@ public void testQueryWithParameters() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery( "create table test(ID int primary key, NAME varchar(20)); " + "insert into test (ID, NAME) values (?, ?);" + - "insert into test (ID, NAME) values (?, ?), (?, ?);" + + "insert into test (ID, NAME) values (?, ?);" + + "insert into test (ID, NAME) values (?, ?);" + "select * from test;") .setSchema("PUBLIC") .setArgs(1, "name_1", 2, "name2", 3, "name_3"); From df05d6387c828347a07b4d8e272c170c16a19b27 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 7 Sep 2017 18:45:14 +0300 Subject: [PATCH 11/36] IGNITE-6046: fix query cache usage, add tests --- .../jdbc/thin/JdbcThinStatementSelfTest.java | 108 +++++++++-- .../internal/jdbc/thin/JdbcThinStatement.java | 3 +- .../processors/query/h2/IgniteH2Indexing.java | 176 +----------------- .../MultipleStatementsSqlQuerySelfTest.java | 3 +- .../IgniteCacheQuerySelfTestSuite.java | 2 + 5 files changed, 109 insertions(+), 183 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java index 705cd9d3fc799..a2e53c62d189f 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java @@ -92,7 +92,6 @@ public class JdbcThinStatementSelfTest extends JdbcThinAbstractSelfTest { startGridsMultiThreaded(3); - fillCache(); } @@ -414,26 +413,109 @@ public void testExecuteQueryTimeout() throws Exception { /** * @throws Exception If failed. */ - public void testExecuteQueryMultipleResultSets() throws Exception { + public void testExecuteQueryMultipleOnlyResultSets() throws Exception { assert conn.getMetaData().supportsMultipleResultSets(); - final String sqlText = "select 1; select 2"; + int stmtCnt = 10; - assert stmt.execute(sqlText); + StringBuilder sql = new StringBuilder(); - ResultSet rs = stmt.getResultSet(); + for (int i = 0; i < stmtCnt; ++i) + sql.append("select ").append(i).append("; "); + + assert stmt.execute(sql.toString()); + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + ResultSet rs = stmt.getResultSet(); + assert rs.next(); + assert rs.getInt(1) == i; + assert !rs.next(); + } - assert rs.next(); - assert rs.getInt(1) == 1; - assert !rs.next(); + assert !stmt.getMoreResults(); + } + + /** + * @throws Exception If failed. + */ + public void testExecuteQueryMultipleOnlyDml() throws Exception { + conn.setSchema(null); - assert stmt.getMoreResults(); + int stmtCnt = 10; + + StringBuilder sql = new StringBuilder("create table test(ID int primary key, NAME varchar(20)); "); + + for (int i = 0; i < stmtCnt; ++i) + sql.append("insert into test (ID, NAME) values (" + i + ", 'name_" + i +"'); "); + + assert !stmt.execute(sql.toString()); + + // CREATE TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 1; + } + + assert !stmt.getMoreResults(); + } - rs = stmt.getResultSet(); + /** + * @throws Exception If failed. + */ + public void testExecuteQueryMultipleMixed() throws Exception { + conn.setSchema(null); + + int stmtCnt = 10; + + StringBuilder sql = new StringBuilder("create table test(ID int primary key, NAME varchar(20)); "); + + for (int i = 0; i < stmtCnt; ++i) { + if (i % 2 == 0) + sql.append(" insert into test (ID, NAME) values (" + i + ", 'name_" + i + "'); "); + else + sql.append(" select * from test where id < " + i + "; "); + } + + assert !stmt.execute(sql.toString()); + + // CREATE TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + boolean notEmptyResult = false; + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + if (i % 2 == 0) { + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 1; + } + else { + assert stmt.getUpdateCount() == -1; + + ResultSet rs = stmt.getResultSet(); + + int rowsCnt = 0; + + while(rs.next()) + rowsCnt++; + + assert rowsCnt <= (i + 1) / 2; + + if (rowsCnt == (i + 1) / 2) + notEmptyResult = true; + } + } - assert rs.next(); - assert rs.getInt(1) == 2; - assert !rs.next(); + assert notEmptyResult; assert !stmt.getMoreResults(); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index f2d9c3347bc55..cb2e3e656a2a1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -466,7 +466,8 @@ private JdbcThinResultSet nextResultSet() throws SQLException { switch (curr) { case CLOSE_CURRENT_RESULT: - resultSets.get(curRes - 1).close0(); + if (curRes > 0) + resultSets.get(curRes - 1).close0(); break; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 1e680dd29079e..373ad71978803 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1283,7 +1283,6 @@ private Iterable> runQueryTwoStep( /** {@inheritDoc} */ @Override public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { - Connection c = connectionForSchema(schemaName); final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); @@ -1292,9 +1291,6 @@ private Iterable> runQueryTwoStep( final DistributedJoinMode distributedJoinMode = distributedJoinMode(qry.isLocal(), distributedJoins); - GridCacheTwoStepQuery twoStepQry = null; - List meta; - String sqlQry = qry.getSql(); H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, @@ -1302,8 +1298,8 @@ private Iterable> runQueryTwoStep( H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { - twoStepQry = cachedQry.query().copy(); - meta = cachedQry.meta(); + GridCacheTwoStepQuery twoStepQry = cachedQry.query().copy(); + List meta = cachedQry.meta(); return Collections.singletonList(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, @@ -1314,10 +1310,13 @@ private Iterable> runQueryTwoStep( Object[] argsOrig = qry.getArgs(); int firstArg = 0; - Object[] args = null; + Object[] args; String remainingSql = sqlQry; while (remainingSql != null) { + GridCacheTwoStepQuery twoStepQry = null; + List meta; + final UUID locNodeId = ctx.localNodeId(); // Here we will just parse the statement, no need to optimize it at all. @@ -1385,7 +1384,6 @@ private Iterable> runQueryTwoStep( cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { - System.out.println("+++ cached " + cachedQry); twoStepQry = cachedQry.query().copy(); meta = cachedQry.meta(); @@ -1472,6 +1470,9 @@ private Iterable> runQueryTwoStep( twoStepQry.local(qry.isLocal()); } + if (stmt.getMetaData() == null) + System.out.println(""); + meta = H2Utils.meta(stmt.getMetaData()); } catch (IgniteCheckedException e) { @@ -1493,165 +1494,6 @@ private Iterable> runQueryTwoStep( return results; } -// /** {@inheritDoc} */ -// @Override public FieldsQueryCursor> queryDistributedSqlFields(String schemaName, -// SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { -// final String sqlQry = qry.getSql(); -// -// Connection c = connectionForSchema(schemaName); -// -// final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); -// final boolean distributedJoins = qry.isDistributedJoins(); -// final boolean grpByCollocated = qry.isCollocated(); -// -// final DistributedJoinMode distributedJoinMode = distributedJoinMode(qry.isLocal(), distributedJoins); -// -// GridCacheTwoStepQuery twoStepQry = null; -// List meta; -// -// final H2TwoStepCachedQueryKey cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, -// distributedJoins, enforceJoinOrder, qry.isLocal()); -// H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); -// -// if (cachedQry != null) { -// twoStepQry = cachedQry.query().copy(); -// meta = cachedQry.meta(); -// } -// else { -// final UUID locNodeId = ctx.localNodeId(); -// -// // Here we will just parse the statement, no need to optimize it at all. -// H2Utils.setupConnection(c, /*distributedJoins*/false, /*enforceJoinOrder*/true); -// -// GridH2QueryContext.set(new GridH2QueryContext(locNodeId, locNodeId, 0, PREPARE) -// .distributedJoinMode(distributedJoinMode)); -// -// PreparedStatement stmt = null; -// Prepared prepared; -// -// boolean cachesCreated = false; -// -// try { -// try { -// while (true) { -// try { -// // Do not cache this statement because the whole query object will be cached later on. -// stmt = prepareStatement(c, sqlQry, false); -// -// break; -// } -// catch (SQLException e) { -// if (!cachesCreated && ( -// e.getErrorCode() == ErrorCode.SCHEMA_NOT_FOUND_1 || -// e.getErrorCode() == ErrorCode.TABLE_OR_VIEW_NOT_FOUND_1 || -// e.getErrorCode() == ErrorCode.INDEX_NOT_FOUND_1) -// ) { -// try { -// ctx.cache().createMissingQueryCaches(); -// } -// catch (IgniteCheckedException ignored) { -// throw new CacheException("Failed to create missing caches.", e); -// } -// -// cachesCreated = true; -// } -// else -// throw new IgniteSQLException("Failed to parse query: " + sqlQry, -// IgniteQueryErrorCode.PARSING, e); -// } -// } -// -// prepared = GridSqlQueryParser.prepared(stmt); -// -// if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery) qry).isQuery() != prepared.isQuery()) -// throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", -// IgniteQueryErrorCode.STMT_TYPE_MISMATCH); -// -// if (prepared.isQuery()) { -// bindParameters(stmt, F.asList(qry.getArgs())); -// -// twoStepQry = GridSqlQuerySplitter.split(c, prepared, qry.getArgs(), -// grpByCollocated, distributedJoins, enforceJoinOrder, this); -// -// assert twoStepQry != null; -// } -// } -// finally { -// GridH2QueryContext.clearThreadLocal(); -// } -// -// // It is a DML statement if we did not create a twoStepQuery. -// if (twoStepQry == null) { -// if (DmlStatementsProcessor.isDmlStatement(prepared)) { -// try { -// return dmlProc.updateSqlFieldsDistributed(schemaName, prepared, qry, cancel); -// } -// catch (IgniteCheckedException e) { -// throw new IgniteSQLException("Failed to execute DML statement [stmt=" + sqlQry + -// ", params=" + Arrays.deepToString(qry.getArgs()) + "]", e); -// } -// } -// -// if (DdlStatementsProcessor.isDdlStatement(prepared)) { -// try { -// return ddlProc.runDdlStatement(sqlQry, prepared); -// } -// catch (IgniteCheckedException e) { -// throw new IgniteSQLException("Failed to execute DDL statement [stmt=" + sqlQry + ']', e); -// } -// } -// } -// -// LinkedHashSet caches0 = new LinkedHashSet<>(); -// -// assert twoStepQry != null; -// -// int tblCnt = twoStepQry.tablesCount(); -// -// if (mainCacheId != null) -// caches0.add(mainCacheId); -// -// if (tblCnt > 0) { -// for (QueryTable tblKey : twoStepQry.tables()) { -// GridH2Table tbl = dataTable(tblKey); -// -// int cacheId = CU.cacheId(tbl.cacheName()); -// -// caches0.add(cacheId); -// } -// } -// -// if (caches0.isEmpty()) -// twoStepQry.local(true); -// else { -// //Prohibit usage indices with different numbers of segments in same query. -// List cacheIds = new ArrayList<>(caches0); -// -// checkCacheIndexSegmentation(cacheIds); -// -// twoStepQry.cacheIds(cacheIds); -// twoStepQry.local(qry.isLocal()); -// } -// -// meta = H2Utils.meta(stmt.getMetaData()); -// } -// catch (IgniteCheckedException e) { -// throw new CacheException("Failed to bind parameters: [qry=" + sqlQry + ", params=" + -// Arrays.deepToString(qry.getArgs()) + "]", e); -// } -// catch (SQLException e) { -// throw new IgniteSQLException(e); -// } -// finally { -// U.close(stmt, log); -// } -// } -// -// return executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, -// qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, -// meta, cachedQryKey, cachedQry); -// } -// /** * @param schemaName Schema name. * @param pageSize Page size. diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index c450098a59162..bd6c319484424 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -99,8 +99,7 @@ public void testQueryWithParameters() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery( "create table test(ID int primary key, NAME varchar(20)); " + "insert into test (ID, NAME) values (?, ?);" + - "insert into test (ID, NAME) values (?, ?);" + - "insert into test (ID, NAME) values (?, ?);" + + "insert into test (ID, NAME) values (?, ?), (?, ?);" + "select * from test;") .setSchema("PUBLIC") .setArgs(1, "name_1", 2, "name2", 3, "name_3"); diff --git a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java index 947bb4dbacc6e..57a77860f9ef4 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java +++ b/modules/indexing/src/test/java/org/apache/ignite/testsuites/IgniteCacheQuerySelfTestSuite.java @@ -135,6 +135,7 @@ import org.apache.ignite.internal.processors.query.IgniteSqlSegmentedIndexSelfTest; import org.apache.ignite.internal.processors.query.IgniteSqlSplitterSelfTest; import org.apache.ignite.internal.processors.query.LazyQuerySelfTest; +import org.apache.ignite.internal.processors.query.MultipleStatementsSqlQuerySelfTest; import org.apache.ignite.internal.processors.query.SqlSchemaSelfTest; import org.apache.ignite.internal.processors.query.h2.GridH2IndexingInMemSelfTest; import org.apache.ignite.internal.processors.query.h2.GridH2IndexingOffheapSelfTest; @@ -161,6 +162,7 @@ public static TestSuite suite() throws Exception { suite.addTestSuite(SqlConnectorConfigurationValidationSelfTest.class); suite.addTestSuite(SqlSchemaSelfTest.class); + suite.addTestSuite(MultipleStatementsSqlQuerySelfTest.class); // Misc tests. // TODO: Enable when IGNITE-1094 is fixed. From 59228fe25b050217acd18ee9f366c8b9454f2a7c Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Fri, 8 Sep 2017 15:35:52 +0300 Subject: [PATCH 12/36] IGNITE-6046: check parameters count --- .../internal/processors/query/h2/IgniteH2Indexing.java | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 373ad71978803..423d39c01b519 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1314,6 +1314,7 @@ private Iterable> runQueryTwoStep( String remainingSql = sqlQry; while (remainingSql != null) { + args = null; GridCacheTwoStepQuery twoStepQry = null; List meta; @@ -1371,13 +1372,16 @@ private Iterable> runQueryTwoStep( int paramsCnt = prepared.getParameters().size(); - if (argsOrig != null && paramsCnt > 0) { + if (paramsCnt > 0) { + if (argsOrig == null || argsOrig.length < firstArg + paramsCnt) { + throw new IgniteException("Invalid number of query parameters. " + + "Cannot find " + (argsOrig.length + 1 - firstArg) + " parameter."); + } + args = Arrays.copyOfRange(argsOrig, firstArg, firstArg + paramsCnt); firstArg += paramsCnt; } - else - args = null; cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, distributedJoins, enforceJoinOrder, qry.isLocal()); From 08c2eb368c147f02924c73ca353caeb70717177e Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Fri, 8 Sep 2017 16:28:51 +0300 Subject: [PATCH 13/36] IGNITE-6046: fix closeOnCompletion and test --- .../jdbc/thin/JdbcThinStatementSelfTest.java | 12 +++++++++-- .../internal/jdbc/thin/JdbcThinResultSet.java | 6 +++--- .../internal/jdbc/thin/JdbcThinStatement.java | 20 +++++++++++++++++++ 3 files changed, 33 insertions(+), 5 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java index a2e53c62d189f..1b15769950fe4 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/thin/JdbcThinStatementSelfTest.java @@ -445,13 +445,17 @@ public void testExecuteQueryMultipleOnlyDml() throws Exception { int stmtCnt = 10; - StringBuilder sql = new StringBuilder("create table test(ID int primary key, NAME varchar(20)); "); + StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); for (int i = 0; i < stmtCnt; ++i) sql.append("insert into test (ID, NAME) values (" + i + ", 'name_" + i +"'); "); assert !stmt.execute(sql.toString()); + // DROP TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + // CREATE TABLE statement assert stmt.getResultSet() == null; assert stmt.getUpdateCount() == 0; @@ -474,7 +478,7 @@ public void testExecuteQueryMultipleMixed() throws Exception { int stmtCnt = 10; - StringBuilder sql = new StringBuilder("create table test(ID int primary key, NAME varchar(20)); "); + StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); for (int i = 0; i < stmtCnt; ++i) { if (i % 2 == 0) @@ -485,6 +489,10 @@ public void testExecuteQueryMultipleMixed() throws Exception { assert !stmt.execute(sql.toString()); + // DROP TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + // CREATE TABLE statement assert stmt.getResultSet() == null; assert stmt.getUpdateCount() == 0; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java index 9aef035668f11..2dcd78a5a1006 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinResultSet.java @@ -236,10 +236,10 @@ public class JdbcThinResultSet implements ResultSet { /** {@inheritDoc} */ @Override public void close() throws SQLException { - if (closeStmt) - stmt.close(); - close0(); + + if (closeStmt) + stmt.closeIfAllResultsClosed(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index cb2e3e656a2a1..255a88f173215 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -645,4 +645,24 @@ protected void ensureNotClosed() throws SQLException { if (isClosed()) throw new SQLException("Statement is closed."); } + + /** + * Used by statement on closeOnCompletion mode. + * @throws SQLException On error. + */ + void closeIfAllResultsClosed() throws SQLException { + if (isClosed()) + return; + + boolean allRsClosed = true; + if (resultSets != null) { + for (JdbcThinResultSet rs : resultSets) { + if (!rs.isClosed()) + allRsClosed = false; + } + } + + if (allRsClosed) + close(); + } } From c59769809b0dc7eee0b7ab4acc16dc6db001cd4c Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 11 Sep 2017 18:14:35 +0300 Subject: [PATCH 14/36] IGNITE-6046: fix after merge --- .../ignite/internal/processors/query/SqlSchemaSelfTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java index e14ae9dbe9604..7b731d2d8fd92 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java @@ -218,7 +218,7 @@ public void testCustomSchemaName() throws Exception { assertEquals(1, node.context().query().querySqlFieldsNoCache( new SqlFieldsQuery("SELECT id, name, orgId FROM TEST.Person where (id = ?)").setArgs(1L), false - ).getAll().size()); + ).get(0).getAll().size()); } /** From 46eec0ad2e8a0596c6f3faafc5d4d766d8017313 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 12:02:59 +0300 Subject: [PATCH 15/36] IGNITE-6046: minors --- .../processors/query/h2/IgniteH2Indexing.java | 26 ++++++++++++------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 85bc13a07f75f..84af7e9d83894 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1301,9 +1301,7 @@ private Iterable> runQueryTwoStep( H2TwoStepCachedQuery cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { - if (qry instanceof JdbcSqlFieldsQuery && !((JdbcSqlFieldsQuery)qry).isQuery()) - throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", - IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + checkQueryType(qry, true); GridCacheTwoStepQuery twoStepQry = cachedQry.query().copy(); List meta = cachedQry.meta(); @@ -1395,9 +1393,7 @@ private Iterable> runQueryTwoStep( cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { - if (qry instanceof JdbcSqlFieldsQuery && !((JdbcSqlFieldsQuery)qry).isQuery()) - throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", - IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + checkQueryType(qry, true); twoStepQry = cachedQry.query().copy(); meta = cachedQry.meta(); @@ -1409,9 +1405,7 @@ private Iterable> runQueryTwoStep( continue; } else { - if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery)qry).isQuery() != prepared.isQuery()) - throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", - IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + checkQueryType(qry, prepared.isQuery()); if (prepared.isQuery()) { bindParameters(stmt, F.asList(args)); @@ -1509,6 +1503,18 @@ private Iterable> runQueryTwoStep( return results; } + /** + * Check expected statement type (when it is set by JDBC) and given statement type. + * + * @param qry Query. + * @param isQry {@code true} for select queries, otherwise (DML/DDL queries) {@code false}. + */ + private void checkQueryType(SqlFieldsQuery qry, boolean isQry) { + if (qry instanceof JdbcSqlFieldsQuery && ((JdbcSqlFieldsQuery)qry).isQuery() != isQry) + throw new IgniteSQLException("Given statement type does not match that declared by JDBC driver", + IgniteQueryErrorCode.STMT_TYPE_MISMATCH); + } + /** * @param schemaName Schema name. * @param pageSize Page size. @@ -1526,7 +1532,7 @@ private Iterable> runQueryTwoStep( * @param cachedQry Cached query. * @return Cursor. */ - public FieldsQueryCursor> executeTwoStepsQuery(String schemaName, int pageSize, int partitions[], + private FieldsQueryCursor> executeTwoStepsQuery(String schemaName, int pageSize, int partitions[], Object[] args, boolean keepBinary, boolean lazy, int timeout, GridQueryCancel cancel, String sqlQry, boolean enforceJoinOrder, GridCacheTwoStepQuery twoStepQry, List meta, H2TwoStepCachedQueryKey cachedQryKey, H2TwoStepCachedQuery cachedQry) { From 600f8e4f322ebc21564343b127e024af146daeed Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 12:06:39 +0300 Subject: [PATCH 16/36] IGNITE-6046: self review --- .../ignite/internal/jdbc/thin/JdbcThinStatement.java | 6 +++--- .../ignite/internal/jdbc/thin/JdbcThinTcpIo.java | 1 - .../JdbcQueryExecuteMultipleStatementsResult.java | 10 +++++----- .../processors/odbc/jdbc/JdbcRequestHandler.java | 8 ++++---- ...{JdbcStatementResults.java => JdbcResultInfo.java} | 11 ++++++----- 5 files changed, 18 insertions(+), 18 deletions(-) rename modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/{JdbcStatementResults.java => JdbcResultInfo.java} (86%) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 8a4091419f220..b6f1c5c2cf011 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -37,7 +37,7 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResult; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementResults; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcResultInfo; import static java.sql.ResultSet.CONCUR_READ_ONLY; import static java.sql.ResultSet.FETCH_FORWARD; @@ -136,13 +136,13 @@ protected void execute0(JdbcStatementType stmtType, String sql, List arg else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { JdbcQueryExecuteMultipleStatementsResult res = (JdbcQueryExecuteMultipleStatementsResult)res0; - List resInfos = res.results(); + List resInfos = res.results(); resultSets = new ArrayList<>(resInfos.size()); boolean firstRes = true; - for(JdbcStatementResults rsInfo : resInfos) { + for(JdbcResultInfo rsInfo : resInfos) { if (!rsInfo.isQuery()) { resultSets.add(new JdbcThinResultSet(this, -1, pageSize, true, Collections.>emptyList(), false, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java index 99eacbe029181..330932ea1b9f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java @@ -49,7 +49,6 @@ import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQuery; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryCloseRequest; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteRequest; -import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryExecuteResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchRequest; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryFetchResult; import org.apache.ignite.internal.processors.odbc.jdbc.JdbcQueryMetadataRequest; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java index 24363937129ee..3ea72878c8023 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcQueryExecuteMultipleStatementsResult.java @@ -30,7 +30,7 @@ */ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { /** Statements results. */ - private List results; + private List results; /** Query result rows for the first query. */ private List> items; @@ -50,7 +50,7 @@ public class JdbcQueryExecuteMultipleStatementsResult extends JdbcResult { * @param items Query result rows for the first query. * @param last Flag indicating the query has no unfetched results for the first query. */ - public JdbcQueryExecuteMultipleStatementsResult(List results, + public JdbcQueryExecuteMultipleStatementsResult(List results, List> items, boolean last) { super(QRY_EXEC_MULT); this.results = results; @@ -61,7 +61,7 @@ public JdbcQueryExecuteMultipleStatementsResult(List resul /** * @return Update counts of query IDs. */ - public List results() { + public List results() { return results; } @@ -86,7 +86,7 @@ public boolean isLast() { if (results != null && results.size() > 0) { writer.writeInt(results.size()); - for (JdbcStatementResults r : results) + for (JdbcResultInfo r : results) r.writeBinary(writer); if (results.get(0).isQuery()) { @@ -111,7 +111,7 @@ public boolean isLast() { results = new ArrayList<>(cnt); for (int i = 0; i < cnt; ++i) { - JdbcStatementResults r = new JdbcStatementResults(); + JdbcResultInfo r = new JdbcResultInfo(); r.readBinary(reader); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 2f6b2ef1da6ff..0ffda163798f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -293,17 +293,17 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { return new JdbcResponse(res); } else { - List jdbcResults = new ArrayList<>(results.size()); + List jdbcResults = new ArrayList<>(results.size()); List> items = null; boolean last = true; for (FieldsQueryCursor> c : results) { QueryCursorImpl qryCur = (QueryCursorImpl)c; - JdbcStatementResults jdbcRes; + JdbcResultInfo jdbcRes; if (qryCur.isQuery()) { - jdbcRes = new JdbcStatementResults(true, qryId); + jdbcRes = new JdbcResultInfo(true, qryId); JdbcQueryCursor cur = new JdbcQueryCursor(qryId, req.pageSize(), req.maxRows(), (QueryCursorImpl)qryCur); @@ -317,7 +317,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { } } else - jdbcRes = new JdbcStatementResults(false, (Long)((List)qryCur.getAll().get(0)).get(0)); + jdbcRes = new JdbcResultInfo(false, (Long)((List)qryCur.getAll().get(0)).get(0)); jdbcResults.add(jdbcRes); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java similarity index 86% rename from modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java rename to modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java index 3bfd86da26c04..2e0b9a9988a9d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcStatementResults.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java @@ -22,9 +22,10 @@ import org.apache.ignite.internal.util.typedef.internal.S; /** - * JDBC multiple statements results. + * JDBC statement result information. Keeps statement type (SELECT or UPDATE) and + * queryId or update count (depends on statement type). */ -public class JdbcStatementResults implements JdbcRawBinarylizable { +public class JdbcResultInfo implements JdbcRawBinarylizable { /** Query flag. */ private boolean isQuery; @@ -34,7 +35,7 @@ public class JdbcStatementResults implements JdbcRawBinarylizable { /** * Default constructor is used for serialization. */ - JdbcStatementResults() { + JdbcResultInfo() { // No-op. } @@ -43,7 +44,7 @@ public class JdbcStatementResults implements JdbcRawBinarylizable { * @param isQuery Query flag. * @param updCntOrQryId Update count. */ - public JdbcStatementResults(boolean isQuery, long updCntOrQryId) { + public JdbcResultInfo(boolean isQuery, long updCntOrQryId) { this.isQuery = isQuery; this.updCntOrQryId= updCntOrQryId; } @@ -83,6 +84,6 @@ public long updateCount() { /** {@inheritDoc} */ @Override public String toString() { - return S.toString(JdbcStatementResults.class, this); + return S.toString(JdbcResultInfo.class, this); } } From bb9afad504acd9ddb4dda0e9b5a03e3f3992925a Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 12:14:45 +0300 Subject: [PATCH 17/36] IGNITE-6046: self review --- .../ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java index 2e0b9a9988a9d..768f27207b3e5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java @@ -29,7 +29,7 @@ public class JdbcResultInfo implements JdbcRawBinarylizable { /** Query flag. */ private boolean isQuery; - /** Update count. */ + /** Update count or queryId. When isQuery == tue the member holds queryId, otherwise - update count. */ private long updCntOrQryId; /** @@ -39,7 +39,6 @@ public class JdbcResultInfo implements JdbcRawBinarylizable { // No-op. } - /** * @param isQuery Query flag. * @param updCntOrQryId Update count. From f9263dec93f8e32bd2865ccb04b90d708678fd6a Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 12:45:14 +0300 Subject: [PATCH 18/36] IGNITE-6046: compatibility --- .../odbc/jdbc/JdbcConnectionContext.java | 2 +- .../processors/odbc/jdbc/JdbcRequestHandler.java | 15 ++++++++++++++- 2 files changed, 15 insertions(+), 2 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java index 035cb77b5dbfe..8d13ff06214d4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java @@ -101,7 +101,7 @@ public JdbcConnectionContext(GridKernalContext ctx, GridSpinBusyLock busyLock, i lazyExec = reader.readBoolean(); handler = new JdbcRequestHandler(ctx, busyLock, maxCursors, distributedJoins, - enforceJoinOrder, collocated, replicatedOnly, autoCloseCursors, lazyExec); + enforceJoinOrder, collocated, replicatedOnly, autoCloseCursors, lazyExec, ver); parser = new JdbcMessageParser(ctx); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 0ffda163798f7..f4de48aebb506 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.binary.BinaryWriterExImpl; import org.apache.ignite.internal.jdbc2.JdbcSqlFieldsQuery; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.processors.odbc.SqlListenerProtocolVersion; import org.apache.ignite.internal.processors.odbc.SqlListenerRequest; import org.apache.ignite.internal.processors.odbc.SqlListenerRequestHandler; import org.apache.ignite.internal.processors.odbc.SqlListenerResponse; @@ -64,6 +65,9 @@ * JDBC request handler. */ public class JdbcRequestHandler implements SqlListenerRequestHandler { + /** Multiple statements query supports since version 2.1.5. */ + private static final SqlListenerProtocolVersion MULTIPLE_STMTS_SUPPORT_SINCE = SqlListenerProtocolVersion.create(2, 1, 5); + /** Query ID sequence. */ private static final AtomicLong QRY_ID_GEN = new AtomicLong(); @@ -100,6 +104,9 @@ public class JdbcRequestHandler implements SqlListenerRequestHandler { /** Automatic close of cursors. */ private final boolean autoCloseCursors; + /** Protocol version. */ + private SqlListenerProtocolVersion protocolVer; + /** * Constructor. * @@ -112,10 +119,11 @@ public class JdbcRequestHandler implements SqlListenerRequestHandler { * @param replicatedOnly Replicated only flag. * @param autoCloseCursors Flag to automatically close server cursors. * @param lazy Lazy query execution flag. + * @param protocolVer Protocol version. */ public JdbcRequestHandler(GridKernalContext ctx, GridSpinBusyLock busyLock, int maxCursors, boolean distributedJoins, boolean enforceJoinOrder, boolean collocated, boolean replicatedOnly, - boolean autoCloseCursors, boolean lazy) { + boolean autoCloseCursors, boolean lazy, SqlListenerProtocolVersion protocolVer) { this.ctx = ctx; this.busyLock = busyLock; this.maxCursors = maxCursors; @@ -125,6 +133,7 @@ public JdbcRequestHandler(GridKernalContext ctx, GridSpinBusyLock busyLock, int this.replicatedOnly = replicatedOnly; this.autoCloseCursors = autoCloseCursors; this.lazy = lazy; + this.protocolVer = protocolVer; log = ctx.log(getClass()); } @@ -293,6 +302,10 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { return new JdbcResponse(res); } else { + if (protocolVer.compareTo(MULTIPLE_STMTS_SUPPORT_SINCE) < 0) + return new JdbcResponse(SqlListenerResponse.STATUS_FAILED, + "Multiple statements query is not supported."); + List jdbcResults = new ArrayList<>(results.size()); List> items = null; boolean last = true; From 5b53829313c2de90cabd6dd729eb3b26b04a8b60 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 13:01:06 +0300 Subject: [PATCH 19/36] IGNITE-6046: minors --- .../processors/query/h2/ddl/DdlStatementsProcessor.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java index dcda84e064743..8d8d7ba34d776 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/ddl/DdlStatementsProcessor.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.query.h2.ddl; -import java.sql.PreparedStatement; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedHashMap; @@ -56,7 +55,6 @@ import org.h2.command.ddl.CreateTable; import org.h2.command.ddl.DropIndex; import org.h2.command.ddl.DropTable; -import org.h2.jdbc.JdbcPreparedStatement; import org.h2.table.Column; import org.h2.value.DataType; From 44ffae3d65a810d51150505150772d783b6c36b4 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 17:59:11 +0300 Subject: [PATCH 20/36] IGNITE-6046: fix review comments --- .../odbc/jdbc/JdbcConnectionContext.java | 2 +- .../odbc/jdbc/JdbcRequestHandler.java | 13 +++---- .../processors/odbc/jdbc/JdbcResultInfo.java | 25 +++++++++----- .../odbc/odbc/OdbcRequestHandler.java | 23 ++----------- .../processors/query/GridQueryIndexing.java | 4 ++- .../processors/query/GridQueryProcessor.java | 34 ++++++++++--------- ...niteClientCacheInitializationFailTest.java | 3 +- .../query/h2/DmlStatementsProcessor.java | 10 ++---- .../processors/query/h2/IgniteH2Indexing.java | 17 ++++------ .../query/h2/sql/GridSqlQuerySplitter.java | 1 - .../index/DynamicColumnsAbstractTest.java | 5 +-- .../index/H2DynamicIndexingComplexTest.java | 7 +--- .../cache/index/H2DynamicTableSelfTest.java | 4 +-- .../MultipleStatementsSqlQuerySelfTest.java | 4 +-- .../processors/query/SqlSchemaSelfTest.java | 10 +++--- 15 files changed, 67 insertions(+), 95 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java index 8d13ff06214d4..165b4916514ed 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcConnectionContext.java @@ -35,7 +35,7 @@ public class JdbcConnectionContext implements SqlListenerConnectionContext { private static final SqlListenerProtocolVersion VER_2_1_0 = SqlListenerProtocolVersion.create(2, 1, 0); /** Version 2.1.5: added "lazy" flag. */ - private static final SqlListenerProtocolVersion VER_2_1_5 = SqlListenerProtocolVersion.create(2, 1, 5); + public static final SqlListenerProtocolVersion VER_2_1_5 = SqlListenerProtocolVersion.create(2, 1, 5); /** Current version. */ private static final SqlListenerProtocolVersion CURRENT_VER = VER_2_1_5; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index f4de48aebb506..6512b2ab389a5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -65,9 +65,6 @@ * JDBC request handler. */ public class JdbcRequestHandler implements SqlListenerRequestHandler { - /** Multiple statements query supports since version 2.1.5. */ - private static final SqlListenerProtocolVersion MULTIPLE_STMTS_SUPPORT_SINCE = SqlListenerProtocolVersion.create(2, 1, 5); - /** Query ID sequence. */ private static final AtomicLong QRY_ID_GEN = new AtomicLong(); @@ -272,7 +269,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qry.setSchema(schemaName); - List>> results = ctx.query().querySqlFieldsNoCache(qry, true); + List>> results = ctx.query().querySqlFieldsNoCache(qry, true, false); if (results.size() == 1) { FieldsQueryCursor> qryCur = results.get(0); @@ -302,7 +299,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { return new JdbcResponse(res); } else { - if (protocolVer.compareTo(MULTIPLE_STMTS_SUPPORT_SINCE) < 0) + if (protocolVer.compareTo(JdbcConnectionContext.VER_2_1_5) < 0) return new JdbcResponse(SqlListenerResponse.STATUS_FAILED, "Multiple statements query is not supported."); @@ -316,7 +313,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { JdbcResultInfo jdbcRes; if (qryCur.isQuery()) { - jdbcRes = new JdbcResultInfo(true, qryId); + jdbcRes = new JdbcResultInfo(true, -1, qryId); JdbcQueryCursor cur = new JdbcQueryCursor(qryId, req.pageSize(), req.maxRows(), (QueryCursorImpl)qryCur); @@ -330,7 +327,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { } } else - jdbcRes = new JdbcResultInfo(false, (Long)((List)qryCur.getAll().get(0)).get(0)); + jdbcRes = new JdbcResultInfo(false, (Long)((List)qryCur.getAll().get(0)).get(0), -1); jdbcResults.add(jdbcRes); } @@ -470,7 +467,7 @@ private SqlListenerResponse executeBatch(JdbcBatchExecuteRequest req) { qry.setSchema(schemaName); QueryCursorImpl> qryCur = (QueryCursorImpl>)ctx.query() - .querySqlFieldsNoCache(qry, true).get(0); + .querySqlFieldsNoCache(qry, true, true).get(0); assert !qryCur.isQuery(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java index 768f27207b3e5..f0706e4a40cb0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcResultInfo.java @@ -29,8 +29,11 @@ public class JdbcResultInfo implements JdbcRawBinarylizable { /** Query flag. */ private boolean isQuery; - /** Update count or queryId. When isQuery == tue the member holds queryId, otherwise - update count. */ - private long updCntOrQryId; + /** Update count. */ + private long updCnt; + + /** Query ID. */ + private long qryId; /** * Default constructor is used for serialization. @@ -41,11 +44,13 @@ public class JdbcResultInfo implements JdbcRawBinarylizable { /** * @param isQuery Query flag. - * @param updCntOrQryId Update count. + * @param updCnt Update count. + * @param qryId Query ID. */ - public JdbcResultInfo(boolean isQuery, long updCntOrQryId) { + public JdbcResultInfo(boolean isQuery, long updCnt, long qryId) { this.isQuery = isQuery; - this.updCntOrQryId= updCntOrQryId; + this.updCnt = updCnt; + this.qryId = qryId; } /** @@ -59,26 +64,28 @@ public boolean isQuery() { * @return Query ID. */ public long queryId() { - return isQuery ? updCntOrQryId : -1; + return qryId; } /** * @return Update count. */ public long updateCount() { - return !isQuery ? updCntOrQryId : -1; + return updCnt; } /** {@inheritDoc} */ @Override public void writeBinary(BinaryWriterExImpl writer) { writer.writeBoolean(isQuery); - writer.writeLong(updCntOrQryId); + writer.writeLong(updCnt); + writer.writeLong(qryId); } /** {@inheritDoc} */ @Override public void readBinary(BinaryReaderExImpl reader) { isQuery = reader.readBoolean(); - updCntOrQryId = reader.readLong(); + updCnt = reader.readLong(); + qryId = reader.readLong(); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java index e2508cc704b0d..19fe796963e7c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/odbc/OdbcRequestHandler.java @@ -29,7 +29,6 @@ import java.util.concurrent.atomic.AtomicLong; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; -import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.GridKernalContext; @@ -43,7 +42,6 @@ import org.apache.ignite.internal.processors.query.GridQueryFieldMetadata; import org.apache.ignite.internal.processors.query.GridQueryIndexing; import org.apache.ignite.internal.processors.query.GridQueryTypeDescriptor; -import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.GridSpinBusyLock; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.U; @@ -218,12 +216,7 @@ private SqlListenerResponse executeQuery(OdbcQueryExecuteRequest req) { SqlFieldsQuery qry = makeQuery(req.schema(), sql, req.arguments()); - List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - QueryCursorImpl> qryCur = (QueryCursorImpl>)curLst.get(0); + QueryCursorImpl> qryCur = (QueryCursorImpl>)ctx.query().querySqlFieldsNoCache(qry, true); long rowsAffected = 0; @@ -278,12 +271,7 @@ private SqlListenerResponse executeBatchQuery(OdbcQueryExecuteBatchRequest req) // Getting meta and do the checks for the first execution. qry.setArgs(paramSet[0]); - List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - QueryCursorImpl> qryCur = (QueryCursorImpl>)curLst.get(0); + QueryCursorImpl> qryCur = (QueryCursorImpl>)ctx.query().querySqlFieldsNoCache(qry, true); if (qryCur.isQuery()) throw new IgniteException("Batching of parameters only supported for DML statements. [query=" + @@ -317,12 +305,7 @@ private SqlListenerResponse executeBatchQuery(OdbcQueryExecuteBatchRequest req) private long executeQuery(SqlFieldsQuery qry, Object[] row) { qry.setArgs(row); - List>> curLst = ctx.query().querySqlFieldsNoCache(qry, true); - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - QueryCursor> cur = curLst.get(0); + QueryCursor> cur = ctx.query().querySqlFieldsNoCache(qry, true); return getRowsAffected(cur); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index d7bd322975a97..86b461a8e3351 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -83,11 +83,13 @@ public QueryCursor> queryDistributedSql(String schemaNa * @param keepBinary Keep binary flag. * @param cancel Query cancel. * @param mainCacheId Main cache ID. + * @param failOnMultipleStmts If {@code true} the method must throws exception when query contains + * more then one SQL statement. * @return Cursor. * @throws IgniteCheckedException If failed. */ public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, - boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException; + boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId, boolean failOnMultipleStmts) throws IgniteCheckedException; /** * Perform a MERGE statement using data streamer as receiver. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index 3b9c81ce0ee07..d76854c3e73f1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1867,13 +1867,8 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct if (cctx.config().getQueryParallelism() > 1) { qry.setDistributedJoins(true); - List>> curLst = idx.queryDistributedSqlFields(schemaName, qry, - keepBinary, cancel, mainCacheId); - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - cur = curLst.get(0); + cur = idx.queryDistributedSqlFields(schemaName, qry, + keepBinary, cancel, mainCacheId, true).get(0); } else { IndexingQueryFilter filter = idx.backupFilter(requestTopVer.get(), qry.getPartitions()); @@ -1890,13 +1885,7 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct else { clo = new IgniteOutClosureX>>() { @Override public FieldsQueryCursor> applyx() throws IgniteCheckedException { - List>> curLst = - idx.queryDistributedSqlFields(schemaName, qry, keepBinary, null, mainCacheId); - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - return curLst.get(0); + return idx.queryDistributedSqlFields(schemaName, qry, keepBinary, null, mainCacheId, true).get(0); } }; } @@ -1918,7 +1907,20 @@ public FieldsQueryCursor> querySqlFields(final GridCacheContext cct * @param keepBinary Keep binary flag. * @return Cursor. */ - public List>> querySqlFieldsNoCache(final SqlFieldsQuery qry, final boolean keepBinary) { + public FieldsQueryCursor> querySqlFieldsNoCache(final SqlFieldsQuery qry, + final boolean keepBinary) { + return querySqlFieldsNoCache(qry, keepBinary, true).get(0); + } + + /** + * Query SQL fields without strict dependency on concrete cache. + * + * @param qry Query. + * @param keepBinary Keep binary flag. + * @return Cursor. + */ + public List>> querySqlFieldsNoCache(final SqlFieldsQuery qry, + final boolean keepBinary, final boolean failOnMultipleStmts) { checkxEnabled(); validateSqlFieldsQuery(qry); @@ -1937,7 +1939,7 @@ public List>> querySqlFieldsNoCache(final SqlFieldsQue @Override public List>> applyx() throws IgniteCheckedException { GridQueryCancel cancel = new GridQueryCancel(); - return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null); + return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null, failOnMultipleStmts); } }; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java index 1e325e28be3d3..1ebf5568fa544 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteClientCacheInitializationFailTest.java @@ -243,7 +243,8 @@ private static class FailedIndexing implements GridQueryIndexing { /** {@inheritDoc} */ @Override public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, - boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) throws IgniteCheckedException { + boolean keepBinary, GridQueryCancel cancel, + @Nullable Integer mainCacheId, boolean failOnMultipleStmts) throws IgniteCheckedException { return null; } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index 742d28af996e0..e5e163def4be9 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -46,8 +46,6 @@ import org.apache.ignite.IgniteLogger; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.binary.BinaryObjectBuilder; -import org.apache.ignite.cache.query.FieldsQueryCursor; -import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridKernalContext; @@ -381,12 +379,8 @@ private UpdateResult executeUpdateStatement(String schemaName, final GridCacheCo .setPageSize(fieldsQry.getPageSize()) .setTimeout(fieldsQry.getTimeout(), TimeUnit.MILLISECONDS); - List>> curLst = idx.queryDistributedSqlFields(schemaName, newFieldsQry, true, - cancel, mainCacheId); - - assert curLst.size() == 1 : "Multiple statements query is not expected in DML select"; - - cur = (QueryCursorImpl>)curLst.get(0); + cur = (QueryCursorImpl>)idx.queryDistributedSqlFields(schemaName, newFieldsQry, true, + cancel, mainCacheId, true).get(0); } else { final GridQueryFieldsResult res = idx.queryLocalSqlFields(schemaName, plan.selectQry, diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index ba0b68d82e3ca..9207d8693bad5 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1246,12 +1246,7 @@ private Iterable> runQueryTwoStep( if (qry.getTimeout() > 0) fqry.setTimeout(qry.getTimeout(), TimeUnit.MILLISECONDS); - List>> curLst = queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId);; - - if (curLst.size() > 1) - throw new IgniteSQLException("Multiple statements queries are not supported"); - - final QueryCursor> res = curLst.get(0); + final QueryCursor> res = queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId, true).get(0); final Iterable> converted = new Iterable>() { @Override public Iterator> iterator() { @@ -1284,8 +1279,8 @@ private Iterable> runQueryTwoStep( } /** {@inheritDoc} */ - @Override public List>> queryDistributedSqlFields(String schemaName, - SqlFieldsQuery qry, boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId) { + @Override public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, + boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId, boolean failOnMultipleStmts) { Connection c = connectionForSchema(schemaName); final boolean enforceJoinOrder = qry.isEnforceJoinOrder(); @@ -1371,6 +1366,9 @@ private Iterable> runQueryTwoStep( // remaining == null if the query string contains single SQL statement. remainingSql = prep.remainingSql(); + if (remainingSql != null && failOnMultipleStmts) + throw new IgniteSQLException("Multiple statements queries are not supported"); + sqlQry = prep.prepared().getSQL(); prepared = prep.prepared(); @@ -1479,9 +1477,6 @@ private Iterable> runQueryTwoStep( twoStepQry.local(qry.isLocal()); } - if (stmt.getMetaData() == null) - System.out.println(""); - meta = H2Utils.meta(stmt.getMetaData()); } catch (IgniteCheckedException e) { diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java index 6df70d0df7446..aaeda8f1bf958 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/sql/GridSqlQuerySplitter.java @@ -51,7 +51,6 @@ import org.h2.command.Prepared; import org.h2.command.dml.Query; import org.h2.command.dml.SelectUnion; -import org.h2.jdbc.JdbcPreparedStatement; import org.h2.table.IndexColumn; import org.h2.value.Value; import org.jetbrains.annotations.Nullable; diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java index 316fe8a689a2a..978c504c56793 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/DynamicColumnsAbstractTest.java @@ -292,15 +292,13 @@ IgniteConfiguration serverConfiguration(int idx) throws Exception { */ protected List> run(Ignite node, String sql) { return ((IgniteEx)node).context().query() - .querySqlFieldsNoCache(new SqlFieldsQuery(sql).setSchema(QueryUtils.DFLT_SCHEMA), true) - .get(0).getAll(); + .querySqlFieldsNoCache(new SqlFieldsQuery(sql).setSchema(QueryUtils.DFLT_SCHEMA), true).getAll(); } /** * Execute SQL command and return resulting dataset. * @param cache Cache to initiate query from. * @param sql Statement. - * @param args Query parameters. * @return result. */ protected List> run(IgniteCache cache, String sql, Object... args) { @@ -309,7 +307,6 @@ protected List> run(IgniteCache cache, String sql, Object... args) /** * Run specified statement expected to throw {@code IgniteSqlException} with expected specified message. - * @param node Ignite node. * @param sql Statement. * @param msg Expected message. */ diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java index ab169ee1250fb..0be691e072f1f 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicIndexingComplexTest.java @@ -314,20 +314,16 @@ private void assertPerson(int id, String name, int age, String company, String c /** * Run SQL statement on specified node. - * @param node Ignite node. * @param stmt Statement to run. - * @param args Query parameters * @return Run result. */ private List> executeSql(IgniteEx node, String stmt, Object... args) { - return node.context().query().querySqlFieldsNoCache(new SqlFieldsQuery(stmt).setArgs(args), true) - .get(0).getAll(); + return node.context().query().querySqlFieldsNoCache(new SqlFieldsQuery(stmt).setArgs(args), true).getAll(); } /** * Run SQL statement on default node. * @param stmt Statement to run. - * @param args Query parameters. * @return Run result. */ private List> executeSql(String stmt, Object... args) { @@ -337,7 +333,6 @@ private List> executeSql(String stmt, Object... args) { /** * Run SQL statement that is expected to return strictly one value (like COUNT(*)). * @param stmt Statement to run. - * @param args Query parameters. * @return Run result. */ private Object executeSqlSingle(String stmt, Object... args) { diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java index c11f44d843466..0be6c7037241f 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/index/H2DynamicTableSelfTest.java @@ -660,12 +660,12 @@ public void testAffinityKey() throws Exception { personId2cityCode.put(i, cityCode); queryProcessor(client()).querySqlFieldsNoCache(new SqlFieldsQuery("insert into \"Person2\"(\"id\", " + - "\"city\") values (?, ?)").setArgs(i, cityName), true).get(0).getAll(); + "\"city\") values (?, ?)").setArgs(i, cityName), true).getAll(); } List> res = queryProcessor(client()).querySqlFieldsNoCache(new SqlFieldsQuery("select \"id\", " + "c.\"code\" from \"Person2\" p left join \"City\" c on p.\"city\" = c.\"name\" where c.\"name\" " + - "is not null"), true).get(0).getAll(); + "is not null"), true).getAll(); assertEquals(100, res.size()); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index bd6c319484424..b66a2c6796215 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -58,7 +58,7 @@ public void testQuery() throws Exception { "select * from test;") .setSchema("PUBLIC"); - List>> res = qryProc.querySqlFieldsNoCache(qry, true); + List>> res = qryProc.querySqlFieldsNoCache(qry, true, false); assert res.size() == 4 : "Unexpected cursors count: " + res.size(); @@ -104,7 +104,7 @@ public void testQueryWithParameters() throws Exception { .setSchema("PUBLIC") .setArgs(1, "name_1", 2, "name2", 3, "name_3"); - List>> res = qryProc.querySqlFieldsNoCache(qry, true); + List>> res = qryProc.querySqlFieldsNoCache(qry, true, false); assert res.size() == 4 : "Unexpected cursors count: " + res.size(); diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java index 7b731d2d8fd92..183a88442c73b 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/SqlSchemaSelfTest.java @@ -65,13 +65,13 @@ public void testQueryWithoutCacheOnPublicSchema() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery("SELECT 1").setSchema("PUBLIC"); - List> res = qryProc.querySqlFieldsNoCache(qry, true).get(0).getAll(); + List> res = qryProc.querySqlFieldsNoCache(qry, true).getAll(); assertEquals(1, res.size()); assertEquals(1, res.get(0).size()); assertEquals(1, res.get(0).get(0)); - Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).get(0).iterator(); + Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).iterator(); assertTrue(iter.hasNext()); @@ -97,13 +97,13 @@ public void testQueryWithoutCacheOnCacheSchema() throws Exception { SqlFieldsQuery qry = new SqlFieldsQuery("SELECT 1").setSchema(CACHE_PERSON); - List> res = qryProc.querySqlFieldsNoCache(qry, true).get(0).getAll(); + List> res = qryProc.querySqlFieldsNoCache(qry, true).getAll(); assertEquals(1, res.size()); assertEquals(1, res.get(0).size()); assertEquals(1, res.get(0).get(0)); - Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).get(0).iterator(); + Iterator> iter = qryProc.querySqlFieldsNoCache(qry, true).iterator(); assertTrue(iter.hasNext()); @@ -218,7 +218,7 @@ public void testCustomSchemaName() throws Exception { assertEquals(1, node.context().query().querySqlFieldsNoCache( new SqlFieldsQuery("SELECT id, name, orgId FROM TEST.Person where (id = ?)").setArgs(1L), false - ).get(0).getAll().size()); + ).getAll().size()); } /** From 76e65a27f41c59ec62ef8c89e828a0f64a61e184 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Tue, 12 Sep 2017 18:24:12 +0300 Subject: [PATCH 21/36] IGNITE-6046: fix review comments --- .../org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index b6f1c5c2cf011..eafed17e75c89 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -77,7 +77,7 @@ public class JdbcThinStatement implements Statement { /** Result sets. */ protected List resultSets; - /** Current result. */ + /** Current result index. */ protected int curRes; /** From f8e590450d9b526f045001a789ba859f22725d46 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Wed, 13 Sep 2017 17:04:40 +0300 Subject: [PATCH 22/36] IGNITE-6046: compatibility fix --- .../processors/odbc/jdbc/JdbcRequestHandler.java | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 6512b2ab389a5..9920ba15896e7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -269,7 +269,10 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qry.setSchema(schemaName); - List>> results = ctx.query().querySqlFieldsNoCache(qry, true, false); + List>> results; + + results = ctx.query().querySqlFieldsNoCache(qry, true, + protocolVer.compareTo(JdbcConnectionContext.VER_2_1_5) < 0); if (results.size() == 1) { FieldsQueryCursor> qryCur = results.get(0); @@ -299,10 +302,6 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { return new JdbcResponse(res); } else { - if (protocolVer.compareTo(JdbcConnectionContext.VER_2_1_5) < 0) - return new JdbcResponse(SqlListenerResponse.STATUS_FAILED, - "Multiple statements query is not supported."); - List jdbcResults = new ArrayList<>(results.size()); List> items = null; boolean last = true; From 43cdee1558f6e2b2aa32ac01b0b16df5af2e7011 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Wed, 13 Sep 2017 17:08:14 +0300 Subject: [PATCH 23/36] IGNITE-6046: minor --- .../internal/processors/odbc/jdbc/JdbcRequestHandler.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java index 9920ba15896e7..05e38dc1e2131 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/odbc/jdbc/JdbcRequestHandler.java @@ -269,9 +269,7 @@ private JdbcResponse executeQuery(JdbcQueryExecuteRequest req) { qry.setSchema(schemaName); - List>> results; - - results = ctx.query().querySqlFieldsNoCache(qry, true, + List>> results = ctx.query().querySqlFieldsNoCache(qry, true, protocolVer.compareTo(JdbcConnectionContext.VER_2_1_5) < 0); if (results.size() == 1) { From 4ca2c9e8b8d7113899031e6e4e0999a5918ad933 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 14 Sep 2017 13:01:52 +0300 Subject: [PATCH 24/36] IGNITE-6046: add test for fail on multiple statements --- .../MultipleStatementsSqlQuerySelfTest.java | 20 ++++++++++++++++++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java index b66a2c6796215..8b9bf40eab6f2 100644 --- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java +++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/query/MultipleStatementsSqlQuerySelfTest.java @@ -18,10 +18,12 @@ package org.apache.ignite.internal.processors.query; import java.util.List; +import java.util.concurrent.Callable; import org.apache.ignite.cache.query.FieldsQueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; /** @@ -133,4 +135,20 @@ public void testQueryWithParameters() throws Exception { : "Invalid ID: " + rows.get(i).get(0); } } -} + + /** + * @throws Exception If failed. + */ + public void testQueryMultipleStatementsFailed() throws Exception { + final SqlFieldsQuery qry = new SqlFieldsQuery("select 1; select 1;").setSchema("PUBLIC"); + + GridTestUtils.assertThrows(log, + new Callable() { + @Override public Object call() throws Exception { + node.context().query().querySqlFieldsNoCache(qry, true); + + return null; + } + }, IgniteSQLException.class, "Multiple statements queries are not supported"); + } +} \ No newline at end of file From b5d6297723dc02bc6066ca8ed866fe8a2e854eda Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 14 Sep 2017 16:17:48 +0300 Subject: [PATCH 25/36] IGNITE-6358: save the progress --- .../jdbc/suite/IgniteJdbcDriverTestSuite.java | 88 ++--- .../ignite/internal/jdbc2/JdbcConnection.java | 7 + .../internal/jdbc2/JdbcDatabaseMetadata.java | 52 +-- .../JdbcQueryMultipleStatementsTask.java | 244 ++++++++++++ .../ignite/internal/jdbc2/JdbcQueryTask.java | 12 +- .../ignite/internal/jdbc2/JdbcResultSet.java | 73 +++- .../ignite/internal/jdbc2/JdbcStatement.java | 354 ++++++++++++++---- 7 files changed, 671 insertions(+), 159 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java index c2ac6cb016573..aaea9665ef969 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java @@ -67,20 +67,20 @@ public class IgniteJdbcDriverTestSuite extends TestSuite { public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Ignite JDBC Driver Test Suite"); - // Thin client based driver tests. - suite.addTest(new TestSuite(JdbcConnectionSelfTest.class)); - suite.addTest(new TestSuite(JdbcStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcPreparedStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcResultSetSelfTest.class)); - suite.addTest(new TestSuite(JdbcComplexQuerySelfTest.class)); - suite.addTest(new TestSuite(JdbcMetadataSelfTest.class)); - suite.addTest(new TestSuite(JdbcEmptyCacheSelfTest.class)); - suite.addTest(new TestSuite(JdbcLocalCachesSelfTest.class)); - suite.addTest(new TestSuite(JdbcNoDefaultCacheTest.class)); - suite.addTest(new TestSuite(JdbcDefaultNoOpCacheTest.class)); - suite.addTest(new TestSuite(JdbcPojoQuerySelfTest.class)); - suite.addTest(new TestSuite(JdbcPojoLegacyQuerySelfTest.class)); - suite.addTest(new TestSuite(JdbcConnectionReopenTest.class)); +// // Thin client based driver tests. +// suite.addTest(new TestSuite(JdbcConnectionSelfTest.class)); +// suite.addTest(new TestSuite(JdbcStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcPreparedStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcResultSetSelfTest.class)); +// suite.addTest(new TestSuite(JdbcComplexQuerySelfTest.class)); +// suite.addTest(new TestSuite(JdbcMetadataSelfTest.class)); +// suite.addTest(new TestSuite(JdbcEmptyCacheSelfTest.class)); +// suite.addTest(new TestSuite(JdbcLocalCachesSelfTest.class)); +// suite.addTest(new TestSuite(JdbcNoDefaultCacheTest.class)); +// suite.addTest(new TestSuite(JdbcDefaultNoOpCacheTest.class)); +// suite.addTest(new TestSuite(JdbcPojoQuerySelfTest.class)); +// suite.addTest(new TestSuite(JdbcPojoLegacyQuerySelfTest.class)); +// suite.addTest(new TestSuite(JdbcConnectionReopenTest.class)); // Ignite client node based driver tests suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcConnectionSelfTest.class)); @@ -114,36 +114,36 @@ public static TestSuite suite() throws Exception { suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcDynamicIndexTransactionalPartitionedSelfTest.class)); suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcDynamicIndexTransactionalReplicatedSelfTest.class)); - // New thin JDBC - suite.addTest(new TestSuite(JdbcThinConnectionSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinPreparedStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinResultSetSelfTest.class)); - - suite.addTest(new TestSuite(JdbcThinStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinComplexQuerySelfTest.class)); - suite.addTest(new TestSuite(JdbcThinNoDefaultSchemaTest.class)); - suite.addTest(new TestSuite(JdbcThinEmptyCacheSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinMetadataSelfTest.class)); - - suite.addTest(new TestSuite(JdbcThinInsertStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinUpdateStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinMergeStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDeleteStatementSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinAutoCloseServerCursorTest.class)); - suite.addTest(new TestSuite(JdbcThinBatchSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinMissingLongArrayResultsTest.class)); - - // New thin JDBC driver, DDL tests - suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedNearSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicReplicatedSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedNearSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedSelfTest.class)); - suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalReplicatedSelfTest.class)); - - // New thin JDBC driver, full SQL tests - suite.addTest(new TestSuite(JdbcThinComplexDmlDdlSelfTest.class)); - +// // New thin JDBC +// suite.addTest(new TestSuite(JdbcThinConnectionSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinPreparedStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinResultSetSelfTest.class)); +// +// suite.addTest(new TestSuite(JdbcThinStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinComplexQuerySelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinNoDefaultSchemaTest.class)); +// suite.addTest(new TestSuite(JdbcThinEmptyCacheSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinMetadataSelfTest.class)); +// +// suite.addTest(new TestSuite(JdbcThinInsertStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinUpdateStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinMergeStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDeleteStatementSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinAutoCloseServerCursorTest.class)); +// suite.addTest(new TestSuite(JdbcThinBatchSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinMissingLongArrayResultsTest.class)); +// +// // New thin JDBC driver, DDL tests +// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedNearSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicReplicatedSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedNearSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedSelfTest.class)); +// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalReplicatedSelfTest.class)); +// +// // New thin JDBC driver, full SQL tests +// suite.addTest(new TestSuite(JdbcThinComplexDmlDdlSelfTest.class)); +// return suite; } } 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 1c37fe205353a..676b1d3d502e8 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 @@ -831,6 +831,13 @@ boolean isDmlSupported() { return ignite.version().greaterThanEqual(1, 8, 0); } + /** + * @return {@code true} if target node has DML support, {@code false} otherwise. + */ + boolean isMultipleStatementsSupported() { + return ignite.version().greaterThanEqual(2, 1, 5); + } + /** * @return Local query flag. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java index f4bb799f0146e..24a26c42d9c0d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java @@ -672,7 +672,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { /** {@inheritDoc} */ @Override public ResultSet getProcedures(String catalog, String schemaPtrn, String procedureNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("PROCEDURE_CAT", "PROCEDURE_SCHEM", "PROCEDURE_NAME", @@ -686,7 +686,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { /** {@inheritDoc} */ @Override public ResultSet getProcedureColumns(String catalog, String schemaPtrn, String procedureNamePtrn, String colNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("PROCEDURE_CAT", "PROCEDURE_SCHEM", "PROCEDURE_NAME", @@ -722,7 +722,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { } } - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "TABLE_TYPE", "REMARKS", "TYPE_CAT", @@ -763,7 +763,7 @@ private List tableRow(String schema, String tbl) { /** {@inheritDoc} */ @Override public ResultSet getCatalogs() throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.singletonList("TABLE_CAT"), @@ -775,7 +775,7 @@ private List tableRow(String schema, String tbl) { /** {@inheritDoc} */ @Override public ResultSet getTableTypes() throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.singletonList("TABLE_TYPE"), @@ -809,7 +809,7 @@ private List tableRow(String schema, String tbl) { } } - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "DATA_TYPE", @@ -867,7 +867,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getColumnPrivileges(String catalog, String schema, String tbl, String colNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -880,7 +880,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getTablePrivileges(String catalog, String schemaPtrn, String tblNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -893,7 +893,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getBestRowIdentifier(String catalog, String schema, String tbl, int scope, boolean nullable) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -905,7 +905,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getVersionColumns(String catalog, String schema, String tbl) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -933,7 +933,7 @@ private List columnRow(String schema, String tbl, String col, int type, } } - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "COLUMN_NAME", "KEY_SEQ", "PK_NAME"), @@ -945,7 +945,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getImportedKeys(String catalog, String schema, String tbl) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -957,7 +957,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getExportedKeys(String catalog, String schema, String tbl) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -970,7 +970,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getCrossReference(String parentCatalog, String parentSchema, String parentTbl, String foreignCatalog, String foreignSchema, String foreignTbl) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -982,7 +982,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getTypeInfo() throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -997,7 +997,7 @@ private List columnRow(String schema, String tbl, String col, int type, boolean approximate) throws SQLException { updateMetaData(); - Collection> rows = new ArrayList<>(indexes.size()); + List> rows = new ArrayList<>(indexes.size()); if (validCatalogPattern(catalog)) { for (List idx : indexes) { @@ -1026,7 +1026,7 @@ private List columnRow(String schema, String tbl, String col, int type, } } - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("TABLE_CAT", "TABLE_SCHEM", "TABLE_NAME", "NON_UNIQUE", "INDEX_QUALIFIER", @@ -1103,7 +1103,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getUDTs(String catalog, String schemaPtrn, String typeNamePtrn, int[] types) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -1141,7 +1141,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getSuperTypes(String catalog, String schemaPtrn, String typeNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -1154,7 +1154,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getSuperTables(String catalog, String schemaPtrn, String tblNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -1167,7 +1167,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getAttributes(String catalog, String schemaPtrn, String typeNamePtrn, String attributeNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -1230,7 +1230,7 @@ private List columnRow(String schema, String tbl, String col, int type, } } - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("TABLE_SCHEM", "TABLE_CATALOG"), @@ -1256,7 +1256,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getClientInfoProperties() throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), @@ -1269,7 +1269,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getFunctions(String catalog, String schemaPtrn, String functionNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("FUNCTION_CAT", "FUNCTION_SCHEM", "FUNCTION_NAME", @@ -1283,7 +1283,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getFunctionColumns(String catalog, String schemaPtrn, String functionNamePtrn, String colNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Arrays.asList("FUNCTION_CAT", "FUNCTION_SCHEM", "FUNCTION_NAME", @@ -1302,7 +1302,7 @@ private List columnRow(String schema, String tbl, String col, int type, /** {@inheritDoc} */ @Override public ResultSet getPseudoColumns(String catalog, String schemaPtrn, String tblNamePtrn, String colNamePtrn) throws SQLException { - return new JdbcResultSet(null, + return new JdbcResultSet(true, null, conn.createStatement0(), Collections.emptyList(), Collections.emptyList(), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java new file mode 100644 index 0000000000000..eede363bbe226 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java @@ -0,0 +1,244 @@ +/* + * 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.io.Serializable; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.UUID; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.Ignite; +import org.apache.ignite.IgniteJdbcDriver; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.cache.query.FieldsQueryCursor; +import org.apache.ignite.cache.query.QueryCursor; +import org.apache.ignite.cache.query.SqlFieldsQuery; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.internal.processors.cache.QueryCursorImpl; +import org.apache.ignite.internal.util.typedef.CAX; +import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.lang.IgniteCallable; +import org.apache.ignite.resources.IgniteInstanceResource; + +/** + * Task for SQL queries execution through {@link IgniteJdbcDriver}. + */ +class JdbcQueryMultipleStatementsTask implements IgniteCallable { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Ignite. */ + @IgniteInstanceResource + private Ignite ignite; + + /** Schema name. */ + private final String schemaName; + + /** Sql. */ + private final String sql; + + /** Operation type flag - query or not. */ + private Boolean isQry; + + /** Args. */ + private final Object[] args; + + /** Fetch size. */ + private final int fetchSize; + + /** Local execution flag. */ + private final boolean loc; + + /** Local query flag. */ + private final boolean locQry; + + /** Collocated query flag. */ + private final boolean collocatedQry; + + /** Distributed joins flag. */ + private final boolean distributedJoins; + + /** Enforce join order flag. */ + private final boolean enforceJoinOrder; + + /** Lazy query execution flag. */ + private final boolean lazy; + + /** + * @param ignite Ignite. + * @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 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 JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String sql, Boolean isQry, boolean loc, + Object[] args, int fetchSize, boolean locQry, boolean collocatedQry, boolean distributedJoins, + boolean enforceJoinOrder, boolean lazy) { + this.ignite = ignite; + this.args = args; + this.schemaName = schemaName; + this.sql = sql; + this.isQry = isQry; + this.fetchSize = fetchSize; + this.loc = loc; + this.locQry = locQry; + this.collocatedQry = collocatedQry; + this.distributedJoins = distributedJoins; + this.enforceJoinOrder = enforceJoinOrder; + this.lazy = lazy; + } + + /** {@inheritDoc} */ + @Override public QueryResult call() throws Exception { + SqlFieldsQuery qry = (isQry != null ? new JdbcSqlFieldsQuery(sql, isQry) : new SqlFieldsQuery(sql)) + .setArgs(args); + + qry.setPageSize(fetchSize); + qry.setLocal(locQry); + qry.setCollocated(collocatedQry); + qry.setDistributedJoins(distributedJoins); + qry.setEnforceJoinOrder(enforceJoinOrder); + qry.setLazy(lazy); + qry.setSchema(schemaName); + + GridKernalContext ctx = ((IgniteKernal)ignite).context(); + + List>> curs = ctx.query().querySqlFieldsNoCache(qry, true, false); + + List resultsInfo = new ArrayList<>(curs.size()); + + for (FieldsQueryCursor> cur0 : curs) { + QueryCursorImpl> cur = (QueryCursorImpl>)cur0; + + JdbcQueryTask.Cursor jdbcCur = new JdbcQueryTask.Cursor(cur, cur.iterator()); + + long updCnt = -1; + + if (!cur.isQuery()) { + List> items = cur.getAll(); + + assert items != null && items.size() == 1 && items.get(0).size() == 1 + && items.get(0).get(0) instanceof Long : + "Invalid result set for not-SELECT query. [qry=" + sql + + ", res=" + S.toString(List.class, items) + ']'; + + updCnt = (Long)items.get(0).get(0); + } + + ResultInfo resInfo = new ResultInfo(cur.isQuery(), updCnt); + + JdbcQueryTask.addCursor(resInfo.qryId, jdbcCur); + + resultsInfo.add(resInfo); + } + + return new QueryResult(resultsInfo); + } + + /** + * Result of query execution. + */ + static class QueryResult implements Serializable { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Uuid. */ + private final List results; + + /** + * @param results Results info list. + */ + public QueryResult(List results) { + this.results = results; + } + + /** + * @return Results info list. + */ + public List results() { + return results; + } + } + + /** + * JDBC statement result information. Keeps statement type (SELECT or UPDATE) and + * queryId or update count (depends on statement type). + */ + public class ResultInfo { + /** Query flag. */ + private boolean isQuery; + + /** Update count. */ + private long updCnt; + + /** Query ID. */ + private UUID qryId; + + /** + * @param isQuery Query flag. + * @param updCnt Update count. + */ + public ResultInfo(boolean isQuery, long updCnt) { + this.isQuery = isQuery; + this.updCnt = updCnt; + + if (isQuery) + qryId = UUID.randomUUID(); + } + + /** + * @return Query flag. + */ + public boolean isQuery() { + return isQuery; + } + + /** + * @return Query ID. + */ + public UUID queryId() { + return qryId; + } + + /** + * @return Update count. + */ + public long updateCount() { + return updCnt; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(ResultInfo.class, this); + } + } +} 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 485412944db4e..53cf2f4f2fca3 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 @@ -278,6 +278,14 @@ private static boolean remove(UUID uuid, Cursor c) { return rmv; } + /** + * @param uuid Cursor UUID. + * @param c Cursor. + */ + static void addCursor(UUID uuid, Cursor c) { + CURSORS.putIfAbsent(uuid, c); + } + /** * Closes and removes cursor. * @@ -391,7 +399,7 @@ public boolean isQuery() { /** * Cursor. */ - private static final class Cursor implements Iterable> { + static final class Cursor implements Iterable> { /** Cursor. */ final QueryCursor> cursor; @@ -405,7 +413,7 @@ private static final class Cursor implements Iterable> { * @param cursor Cursor. * @param iter Iterator. */ - private Cursor(QueryCursor> cursor, Iterator> iter) { + Cursor(QueryCursor> cursor, Iterator> iter) { this.cursor = cursor; this.iter = iter; this.lastAccessTime = U.currentTimeMillis(); 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 baddb88c390fe..4f5a5f214d27c 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 @@ -46,12 +46,19 @@ import java.util.UUID; import org.apache.ignite.Ignite; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.util.typedef.F; import org.jetbrains.annotations.Nullable; /** * JDBC result set implementation. */ public class JdbcResultSet implements ResultSet { + /** Is query. */ + private final boolean isQry; + + /** Update count. */ + private final long updCnt; + /** Uuid. */ private final UUID uuid; @@ -91,6 +98,7 @@ public class JdbcResultSet implements ResultSet { /** * Creates new result set. * + * @param isQry Is query flag. * @param uuid Query UUID. * @param stmt Statement. * @param tbls Table names. @@ -98,23 +106,35 @@ public class JdbcResultSet implements ResultSet { * @param types Types. * @param fields Fields. * @param finished Result set finished flag (the last result set). + * @throws SQLException On error. */ - JdbcResultSet(@Nullable UUID uuid, JdbcStatement stmt, List tbls, List cols, - List types, Collection> fields, boolean finished) { + JdbcResultSet(boolean isQry, @Nullable UUID uuid, JdbcStatement stmt, List tbls, List cols, + List types, List> fields, boolean finished) throws SQLException { assert stmt != null; assert tbls != null; assert cols != null; assert types != null; assert fields != null; + this.isQry = isQry; this.uuid = uuid; this.stmt = stmt; - this.tbls = tbls; - this.cols = cols; - this.types = types; - this.finished = finished; - this.it = fields.iterator(); + if (isQry) { + updCnt = -1; + this.tbls = tbls; + this.cols = cols; + this.types = types; + this.finished = finished; + this.it = fields.iterator(); + } else { + updCnt = updateCounterFromQueryResult(fields); + this.tbls = null; + this.cols = null; + this.types = null; + this.finished = true; + this.it = null; + } } /** {@inheritDoc} */ @@ -1524,4 +1544,43 @@ private void ensureHasCurrentRow() throws SQLException { if (curr == null) throw new SQLException("Result set is not positioned on a row."); } + + /** + * @return Is Query flag. + */ + public boolean isQuery() { + return isQry; + } + + /** + * @return Update count. + */ + public long updateCount() { + return updCnt; + } + + /** + * @param rows query result. + * @return update counter, if found. + * @throws SQLException if getting an update counter from result proved to be impossible. + */ + private static long updateCounterFromQueryResult(List> rows) throws SQLException { + if (F.isEmpty(rows)) + return -1; + + if (rows.size() != 1) + throw new SQLException("Expected fetch size of 1 for update operation"); + + List row = rows.get(0); + + if (row.size() != 1) + throw new SQLException("Expected row size of 1 for update operation"); + + Object objRes = row.get(0); + + if (!(objRes instanceof Long)) + throw new SQLException("Unexpected update result type"); + + return (Long)objRes; + } } 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 4e05db4ee3f4d..7f466459bab69 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 @@ -24,6 +24,7 @@ import java.sql.SQLWarning; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; @@ -32,6 +33,8 @@ import java.util.Set; import java.util.UUID; import org.apache.ignite.Ignite; +import org.apache.ignite.internal.jdbc.thin.JdbcThinResultSet; +import org.apache.ignite.internal.processors.odbc.jdbc.JdbcStatementType; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.typedef.F; @@ -77,6 +80,12 @@ public class JdbcStatement implements Statement { /** Batch of statements. */ private List batch; + /** Results. */ + private List results; + + /** Current result set index. */ + private int curRes = 0; + /** * Creates new statement. * @@ -91,11 +100,61 @@ public class JdbcStatement implements Statement { /** {@inheritDoc} */ @SuppressWarnings("deprecation") @Override public ResultSet executeQuery(String sql) throws SQLException { - ensureNotClosed(); +// ensureNotClosed(); +// +// rs = null; +// +// updateCnt = -1; +// +// if (F.isEmpty(sql)) +// throw new SQLException("SQL query is empty"); +// +// Ignite ignite = conn.ignite(); +// +// UUID nodeId = conn.nodeId(); +// +// UUID uuid = UUID.randomUUID(); +// +// boolean loc = nodeId == null; +// +// 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 = +// loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); +// +// JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), res.getTypes(), +// res.getRows(), res.isFinished()); +// +// rs.setFetchSize(fetchSize); +// +// resSets.add(rs); +// +// return rs; +// } +// catch (IgniteSQLException e) { +// throw e.toJdbcException(); +// } +// catch (Exception e) { +// throw new SQLException("Failed to query Ignite.", e); +// } + + execute0(sql, true); + + return getResultSet(); + } - rs = null; + /** + * @param sql SQL query. + * @param isQuery Expected type of statements are contained in the query. + * @throws SQLException On error. + */ + void executeMultipleStmt(String sql, Boolean isQuery) throws SQLException { + ensureNotClosed(); - updateCnt = -1; + closeResults(); if (F.isEmpty(sql)) throw new SQLException("SQL query is empty"); @@ -104,44 +163,112 @@ public class JdbcStatement implements Statement { UUID nodeId = conn.nodeId(); + boolean loc = nodeId == null; + + JdbcQueryMultipleStatementsTask qryTask = new JdbcQueryMultipleStatementsTask(loc ? ignite : null, conn.schemaName(), + sql, isQuery, loc, getArgs(), fetchSize, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); + + try { + JdbcQueryMultipleStatementsTask.QueryResult res = + loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); + + results = new ArrayList<>(res.results().size()); + + for (JdbcQueryMultipleStatementsTask.ResultInfo rsInfo : res.results()) { + if (rsInfo.isQuery()) { + + } + else { + + } + } + } + catch (IgniteSQLException e) { + throw e.toJdbcException(); + } + catch (Exception e) { + throw new SQLException("Failed to query Ignite.", e); + } + } + + /** + * @param sql SQL query. + * @param isQuery Expected type of statements are contained in the query. + * @throws SQLException On error. + */ + private void executeSingle(String sql, Boolean isQuery) throws SQLException { + ensureNotClosed(); + + Ignite ignite = conn.ignite(); + + UUID nodeId = conn.nodeId(); + UUID uuid = UUID.randomUUID(); boolean loc = nodeId == null; + if (!conn.isDmlSupported()) + if(isQuery != null && !isQuery) + throw new SQLException("Failed to query Ignite: DML operations are supported in versions 1.8.0 and newer"); + else + isQuery = true; + JdbcQueryTask qryTask = JdbcQueryTaskV2.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), - sql, true, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + sql, isQuery, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { - JdbcQueryTask.QueryResult res = + JdbcQueryTask.QueryResult qryRes = loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); - JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), res.getTypes(), - res.getRows(), res.isFinished()); + JdbcResultSet rs = new JdbcResultSet(qryRes.isQuery(), uuid, this, qryRes.getTbls(), qryRes.getCols(), + qryRes.getTypes(), qryRes.getRows(), qryRes.isFinished()); rs.setFetchSize(fetchSize); - resSets.add(rs); - - return rs; + results = Collections.singletonList(rs); + curRes = 0; } catch (IgniteSQLException e) { throw e.toJdbcException(); } + catch (SQLException e) { + throw e; + } catch (Exception e) { throw new SQLException("Failed to query Ignite.", e); } + + } + + /** + * @param sql SQL query. + * @param isQuery Expected type of statements are contained in the query. + * @throws SQLException On error. + */ + private void execute0(String sql, Boolean isQuery) throws SQLException { + executeSingle(sql, isQuery); + +// if (conn.isMultipleStatementsSupported()) +// executeSingle(sql, isQuery); +// else +// executeMultipleStmt(sql, isQuery); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { - ensureNotClosed(); +// ensureNotClosed(); +// +// rs = null; +// +// updateCnt = -1; +// +// return Long.valueOf(doUpdate(sql, getArgs())).intValue(); - rs = null; + execute0(sql, false); - updateCnt = -1; - - return Long.valueOf(doUpdate(sql, getArgs())).intValue(); + return getUpdateCount(); } /** @@ -310,82 +437,96 @@ void closeInternal() throws SQLException { /** {@inheritDoc} */ @Override public boolean execute(String sql) throws SQLException { - if (!conn.isDmlSupported()) { - // We attempt to run a query without any checks as long as server does not support DML anyway, - // so it simply will throw an exception when given a DML statement instead of a query. - rs = executeQuery(sql); - - return true; - } - - ensureNotClosed(); - - rs = null; - - updateCnt = -1; - - if (F.isEmpty(sql)) - throw new SQLException("SQL query is empty"); - - Ignite ignite = conn.ignite(); - - UUID nodeId = conn.nodeId(); - - UUID uuid = UUID.randomUUID(); - - boolean loc = nodeId == null; - - 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 = - loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); - - if (res.isQuery()) { - JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), - res.getTypes(), res.getRows(), res.isFinished()); - - rs.setFetchSize(fetchSize); - - resSets.add(rs); - - this.rs = rs; - } - else - updateCnt = updateCounterFromQueryResult(res.getRows()); - - return res.isQuery(); - } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } - catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); - } +// if (!conn.isDmlSupported()) { +// // We attempt to run a query without any checks as long as server does not support DML anyway, +// // so it simply will throw an exception when given a DML statement instead of a query. +// rs = executeQuery(sql); +// +// return true; +// } +// +// ensureNotClosed(); +// +// rs = null; +// +// updateCnt = -1; +// +// if (F.isEmpty(sql)) +// throw new SQLException("SQL query is empty"); +// +// Ignite ignite = conn.ignite(); +// +// UUID nodeId = conn.nodeId(); +// +// UUID uuid = UUID.randomUUID(); +// +// boolean loc = nodeId == null; +// +// 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 = +// loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); +// +// if (res.isQuery()) { +// JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), +// res.getTypes(), res.getRows(), res.isFinished()); +// +// rs.setFetchSize(fetchSize); +// +// resSets.add(rs); +// +// this.rs = rs; +// } +// else +// updateCnt = updateCounterFromQueryResult(res.getRows()); +// +// return res.isQuery(); +// } +// catch (IgniteSQLException e) { +// throw e.toJdbcException(); +// } +// catch (Exception e) { +// throw new SQLException("Failed to query Ignite.", e); +// } + + execute0(sql, null); + + return results.get(0).isQuery(); } /** {@inheritDoc} */ @Override public ResultSet getResultSet() throws SQLException { - ensureNotClosed(); + JdbcResultSet rs = nextResultSet(); - ResultSet rs0 = rs; + if (rs == null) + return null; - rs = null; + if (!rs.isQuery()) { + curRes--; - return rs0; + return null; + } + + return rs; } /** {@inheritDoc} */ @Override public int getUpdateCount() throws SQLException { - ensureNotClosed(); + JdbcResultSet rs = nextResultSet(); - long res = updateCnt; + if (rs == null) + return -1; - updateCnt = -1; + if (rs.isQuery()) { + curRes--; - return Long.valueOf(res).intValue(); + return -1; + } + + return (int)rs.updateCount(); } /** {@inheritDoc} */ @@ -531,11 +672,34 @@ protected int[] doBatchUpdate(String command, List batch, List= results.size()) + return null; + else + return results.get(curRes++); + } + + /** + * Close results. + * @throws SQLException On error. + */ + private void closeResults() throws SQLException { + if (results != null) { + for (JdbcResultSet rs : results) + rs.close(); + + results = null; + curRes = 0; + } + } + } From 1becd5841271d849a4d0544dffe3200a2c5f50c6 Mon Sep 17 00:00:00 2001 From: devozerov Date: Thu, 14 Sep 2017 17:20:50 +0300 Subject: [PATCH 26/36] Cosmetics. --- .../processors/query/GridQueryIndexing.java | 3 ++- .../processors/query/GridQueryProcessor.java | 6 ++++-- .../query/h2/DmlStatementsProcessor.java | 3 ++- .../processors/query/h2/IgniteH2Indexing.java | 17 ++++++++++------- 4 files changed, 18 insertions(+), 11 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java index 86b461a8e3351..b8445ca7dcc3c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryIndexing.java @@ -89,7 +89,8 @@ public QueryCursor> queryDistributedSql(String schemaNa * @throws IgniteCheckedException If failed. */ public List>> queryDistributedSqlFields(String schemaName, SqlFieldsQuery qry, - boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId, boolean failOnMultipleStmts) throws IgniteCheckedException; + boolean keepBinary, GridQueryCancel cancel, @Nullable Integer mainCacheId, boolean failOnMultipleStmts) + throws IgniteCheckedException; /** * Perform a MERGE statement using data streamer as receiver. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java index d76854c3e73f1..3237f046797eb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/GridQueryProcessor.java @@ -1935,11 +1935,13 @@ public List>> querySqlFieldsNoCache(final SqlFieldsQue throw new IllegalStateException("Failed to execute query (grid is stopping)."); try { - IgniteOutClosureX>>> clo = new IgniteOutClosureX>>>() { + IgniteOutClosureX>>> clo = + new IgniteOutClosureX>>>() { @Override public List>> applyx() throws IgniteCheckedException { GridQueryCancel cancel = new GridQueryCancel(); - return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null, failOnMultipleStmts); + return idx.queryDistributedSqlFields(qry.getSchema(), qry, keepBinary, cancel, null, + failOnMultipleStmts); } }; diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java index e5e163def4be9..3bbf7261f1443 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/DmlStatementsProcessor.java @@ -246,7 +246,8 @@ QueryCursorImpl> updateSqlFieldsDistributed(String schemaName, Prepared GridQueryFieldsResult updateSqlFieldsLocal(String schemaName, PreparedStatement stmt, SqlFieldsQuery fieldsQry, IndexingQueryFilter filters, GridQueryCancel cancel) throws IgniteCheckedException { - UpdateResult res = updateSqlFields(schemaName, GridSqlQueryParser.prepared(stmt), fieldsQry, true, filters, cancel); + UpdateResult res = updateSqlFields(schemaName, GridSqlQueryParser.prepared(stmt), fieldsQry, true, + filters, cancel); return new GridQueryFieldsResultAdapter(UPDATE_RESULT_META, new IgniteSingletonIterator(Collections.singletonList(res.cnt))); diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 9207d8693bad5..8bb75260807b0 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1246,7 +1246,8 @@ private Iterable> runQueryTwoStep( if (qry.getTimeout() > 0) fqry.setTimeout(qry.getTimeout(), TimeUnit.MILLISECONDS); - final QueryCursor> res = queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId, true).get(0); + final QueryCursor> res = + queryDistributedSqlFields(schemaName, fqry, keepBinary, null, mainCacheId, true).get(0); final Iterable> converted = new Iterable>() { @Override public Iterator> iterator() { @@ -1299,6 +1300,7 @@ private Iterable> runQueryTwoStep( checkQueryType(qry, true); GridCacheTwoStepQuery twoStepQry = cachedQry.query().copy(); + List meta = cachedQry.meta(); return Collections.singletonList(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), @@ -1306,7 +1308,7 @@ private Iterable> runQueryTwoStep( twoStepQry, meta, cachedQryKey, cachedQry)); } - List>> results = new ArrayList<>(); + List>> res = new ArrayList<>(1); Object[] argsOrig = qry.getArgs(); int firstArg = 0; @@ -1388,6 +1390,7 @@ private Iterable> runQueryTwoStep( cachedQryKey = new H2TwoStepCachedQueryKey(schemaName, sqlQry, grpByCollocated, distributedJoins, enforceJoinOrder, qry.isLocal()); + cachedQry = twoStepCache.get(cachedQryKey); if (cachedQry != null) { @@ -1396,7 +1399,7 @@ private Iterable> runQueryTwoStep( twoStepQry = cachedQry.query().copy(); meta = cachedQry.meta(); - results.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, + res.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, meta, cachedQryKey, cachedQry)); @@ -1423,7 +1426,7 @@ private Iterable> runQueryTwoStep( if (twoStepQry == null) { if (DmlStatementsProcessor.isDmlStatement(prepared)) { try { - results.add(dmlProc.updateSqlFieldsDistributed(schemaName, prepared, + res.add(dmlProc.updateSqlFieldsDistributed(schemaName, prepared, new SqlFieldsQuery(qry).setSql(sqlQry).setArgs(args), cancel)); continue; @@ -1436,7 +1439,7 @@ private Iterable> runQueryTwoStep( if (DdlStatementsProcessor.isDdlStatement(prepared)) { try { - results.add(ddlProc.runDdlStatement(sqlQry, prepared)); + res.add(ddlProc.runDdlStatement(sqlQry, prepared)); continue; } @@ -1490,12 +1493,12 @@ private Iterable> runQueryTwoStep( U.close(stmt, log); } - results.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, + res.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, twoStepQry, meta, cachedQryKey, cachedQry)); } - return results; + return res; } /** From 2297d40531943f9b9ef0b0d96abb426d74558fab Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 14 Sep 2017 18:06:36 +0300 Subject: [PATCH 27/36] IGNITE-6358: save the progress --- .../jdbc2/JdbcNoDefaultCacheTest.java | 12 +- .../internal/jdbc2/JdbcStatementSelfTest.java | 119 +++++++++++++ .../jdbc/suite/IgniteJdbcDriverTestSuite.java | 88 +++++----- .../internal/jdbc2/JdbcDatabaseMetadata.java | 2 +- .../JdbcQueryMultipleStatementsTask.java | 22 ++- .../ignite/internal/jdbc2/JdbcQueryTask.java | 24 ++- .../internal/jdbc2/JdbcQueryTaskV3.java | 100 +++++++++++ .../ignite/internal/jdbc2/JdbcResultSet.java | 114 ++++++++----- .../ignite/internal/jdbc2/JdbcStatement.java | 161 ++---------------- .../jdbc2/JdbcStreamedPreparedStatement.java | 18 +- 10 files changed, 411 insertions(+), 249 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java index e851319c370af..162e98f401abb 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java @@ -19,6 +19,7 @@ import java.sql.Connection; import java.sql.DriverManager; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; import java.util.concurrent.Callable; @@ -131,14 +132,11 @@ public void testNoCacheNameQuery() throws Exception { assertNotNull(stmt); assertFalse(stmt.isClosed()); - Throwable throwable = GridTestUtils.assertThrows(null, new Callable() { - @Override public Void call() throws Exception { - stmt.execute("select t._key, t._val from \"cache1\".Integer t"); - return null; - } - }, SQLException.class, "Failed to query Ignite."); + stmt.execute("select t._key, t._val from \"cache1\".Integer t"); - assertEquals(throwable.getCause().getMessage(), "Ouch! Argument is invalid: Cache name must not be null or empty."); + ResultSet rs = stmt.getResultSet(); + + assert rs.next(); } } } diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java index 138eef5a90851..8b0187022f121 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java @@ -249,6 +249,125 @@ else if (id == 3) { assert cnt == 2; } + /** + * @throws Exception If failed. + */ + public void testExecuteQueryMultipleOnlyResultSets() throws Exception { + assert conn.getMetaData().supportsMultipleResultSets(); + + int stmtCnt = 10; + + StringBuilder sql = new StringBuilder(); + + for (int i = 0; i < stmtCnt; ++i) + sql.append("select ").append(i).append("; "); + + assert stmt.execute(sql.toString()); + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + ResultSet rs = stmt.getResultSet(); + + assert rs.next(); + assert rs.getInt(1) == i; + assert !rs.next(); + } + + assert !stmt.getMoreResults(); + } + + /** + * @throws Exception If failed. + */ + public void testExecuteQueryMultipleOnlyDml() throws Exception { + conn.setSchema(null); + + int stmtCnt = 10; + + StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); + + for (int i = 0; i < stmtCnt; ++i) + sql.append("insert into test (ID, NAME) values (" + i + ", 'name_" + i +"'); "); + + assert !stmt.execute(sql.toString()); + + // DROP TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + // CREATE TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 1; + } + + assert !stmt.getMoreResults(); + } + + /** + * @throws Exception If failed. + */ + public void testExecuteQueryMultipleMixed() throws Exception { + conn.setSchema(null); + + int stmtCnt = 10; + + StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); + + for (int i = 0; i < stmtCnt; ++i) { + if (i % 2 == 0) + sql.append(" insert into test (ID, NAME) values (" + i + ", 'name_" + i + "'); "); + else + sql.append(" select * from test where id < " + i + "; "); + } + + assert !stmt.execute(sql.toString()); + + // DROP TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + // CREATE TABLE statement + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 0; + + boolean notEmptyResult = false; + + for (int i = 0; i < stmtCnt; ++i) { + assert stmt.getMoreResults(); + + if (i % 2 == 0) { + assert stmt.getResultSet() == null; + assert stmt.getUpdateCount() == 1; + } + else { + assert stmt.getUpdateCount() == -1; + + ResultSet rs = stmt.getResultSet(); + + int rowsCnt = 0; + + while(rs.next()) + rowsCnt++; + + assert rowsCnt <= (i + 1) / 2; + + if (rowsCnt == (i + 1) / 2) + notEmptyResult = true; + } + } + + assert notEmptyResult; + + assert !stmt.getMoreResults(); + } + /** * Person. */ diff --git a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java index aaea9665ef969..c2ac6cb016573 100644 --- a/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java +++ b/modules/clients/src/test/java/org/apache/ignite/jdbc/suite/IgniteJdbcDriverTestSuite.java @@ -67,20 +67,20 @@ public class IgniteJdbcDriverTestSuite extends TestSuite { public static TestSuite suite() throws Exception { TestSuite suite = new TestSuite("Ignite JDBC Driver Test Suite"); -// // Thin client based driver tests. -// suite.addTest(new TestSuite(JdbcConnectionSelfTest.class)); -// suite.addTest(new TestSuite(JdbcStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcPreparedStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcResultSetSelfTest.class)); -// suite.addTest(new TestSuite(JdbcComplexQuerySelfTest.class)); -// suite.addTest(new TestSuite(JdbcMetadataSelfTest.class)); -// suite.addTest(new TestSuite(JdbcEmptyCacheSelfTest.class)); -// suite.addTest(new TestSuite(JdbcLocalCachesSelfTest.class)); -// suite.addTest(new TestSuite(JdbcNoDefaultCacheTest.class)); -// suite.addTest(new TestSuite(JdbcDefaultNoOpCacheTest.class)); -// suite.addTest(new TestSuite(JdbcPojoQuerySelfTest.class)); -// suite.addTest(new TestSuite(JdbcPojoLegacyQuerySelfTest.class)); -// suite.addTest(new TestSuite(JdbcConnectionReopenTest.class)); + // Thin client based driver tests. + suite.addTest(new TestSuite(JdbcConnectionSelfTest.class)); + suite.addTest(new TestSuite(JdbcStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcPreparedStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcResultSetSelfTest.class)); + suite.addTest(new TestSuite(JdbcComplexQuerySelfTest.class)); + suite.addTest(new TestSuite(JdbcMetadataSelfTest.class)); + suite.addTest(new TestSuite(JdbcEmptyCacheSelfTest.class)); + suite.addTest(new TestSuite(JdbcLocalCachesSelfTest.class)); + suite.addTest(new TestSuite(JdbcNoDefaultCacheTest.class)); + suite.addTest(new TestSuite(JdbcDefaultNoOpCacheTest.class)); + suite.addTest(new TestSuite(JdbcPojoQuerySelfTest.class)); + suite.addTest(new TestSuite(JdbcPojoLegacyQuerySelfTest.class)); + suite.addTest(new TestSuite(JdbcConnectionReopenTest.class)); // Ignite client node based driver tests suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcConnectionSelfTest.class)); @@ -114,36 +114,36 @@ public static TestSuite suite() throws Exception { suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcDynamicIndexTransactionalPartitionedSelfTest.class)); suite.addTest(new TestSuite(org.apache.ignite.internal.jdbc2.JdbcDynamicIndexTransactionalReplicatedSelfTest.class)); -// // New thin JDBC -// suite.addTest(new TestSuite(JdbcThinConnectionSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinPreparedStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinResultSetSelfTest.class)); -// -// suite.addTest(new TestSuite(JdbcThinStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinComplexQuerySelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinNoDefaultSchemaTest.class)); -// suite.addTest(new TestSuite(JdbcThinEmptyCacheSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinMetadataSelfTest.class)); -// -// suite.addTest(new TestSuite(JdbcThinInsertStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinUpdateStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinMergeStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDeleteStatementSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinAutoCloseServerCursorTest.class)); -// suite.addTest(new TestSuite(JdbcThinBatchSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinMissingLongArrayResultsTest.class)); -// -// // New thin JDBC driver, DDL tests -// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedNearSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicReplicatedSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedNearSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedSelfTest.class)); -// suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalReplicatedSelfTest.class)); -// -// // New thin JDBC driver, full SQL tests -// suite.addTest(new TestSuite(JdbcThinComplexDmlDdlSelfTest.class)); -// + // New thin JDBC + suite.addTest(new TestSuite(JdbcThinConnectionSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinPreparedStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinResultSetSelfTest.class)); + + suite.addTest(new TestSuite(JdbcThinStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinComplexQuerySelfTest.class)); + suite.addTest(new TestSuite(JdbcThinNoDefaultSchemaTest.class)); + suite.addTest(new TestSuite(JdbcThinEmptyCacheSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinMetadataSelfTest.class)); + + suite.addTest(new TestSuite(JdbcThinInsertStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinUpdateStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinMergeStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDeleteStatementSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinAutoCloseServerCursorTest.class)); + suite.addTest(new TestSuite(JdbcThinBatchSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinMissingLongArrayResultsTest.class)); + + // New thin JDBC driver, DDL tests + suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedNearSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicPartitionedSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDynamicIndexAtomicReplicatedSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedNearSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalPartitionedSelfTest.class)); + suite.addTest(new TestSuite(JdbcThinDynamicIndexTransactionalReplicatedSelfTest.class)); + + // New thin JDBC driver, full SQL tests + suite.addTest(new TestSuite(JdbcThinComplexDmlDdlSelfTest.class)); + return suite; } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java index 24a26c42d9c0d..1d61dc5d225ff 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java @@ -316,7 +316,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { /** {@inheritDoc} */ @Override public boolean supportsMultipleResultSets() { - return false; + return true; } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java index eede363bbe226..df64e1689265b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java @@ -139,10 +139,10 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String for (FieldsQueryCursor> cur0 : curs) { QueryCursorImpl> cur = (QueryCursorImpl>)cur0; - JdbcQueryTask.Cursor jdbcCur = new JdbcQueryTask.Cursor(cur, cur.iterator()); - long updCnt = -1; + UUID qryId = null; + if (!cur.isQuery()) { List> items = cur.getAll(); @@ -152,11 +152,18 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String ", res=" + S.toString(List.class, items) + ']'; updCnt = (Long)items.get(0).get(0); + + cur.close(); } + else { + qryId = UUID.randomUUID(); - ResultInfo resInfo = new ResultInfo(cur.isQuery(), updCnt); + JdbcQueryTask.Cursor jdbcCur = new JdbcQueryTask.Cursor(cur, cur.iterator()); - JdbcQueryTask.addCursor(resInfo.qryId, jdbcCur); + JdbcQueryTask.addCursor(qryId, jdbcCur); + } + + ResultInfo resInfo = new ResultInfo(cur.isQuery(), qryId, updCnt); resultsInfo.add(resInfo); } @@ -205,14 +212,13 @@ public class ResultInfo { /** * @param isQuery Query flag. + * @param qryId Query ID. * @param updCnt Update count. */ - public ResultInfo(boolean isQuery, long updCnt) { + public ResultInfo(boolean isQuery, UUID qryId, long updCnt) { this.isQuery = isQuery; this.updCnt = updCnt; - - if (isQuery) - qryId = UUID.randomUUID(); + this.qryId = qryId; } /** 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 53cf2f4f2fca3..f6467b3fcc588 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 @@ -173,7 +173,11 @@ public JdbcQueryTask(Ignite ignite, String cacheName, String schemaName, String if (isQry == null) isQry = qryCursor.isQuery(); - Collection meta = qryCursor.fieldsMeta(); + CURSORS.put(uuid, cursor = new Cursor(qryCursor, qryCursor.iterator())); + } + + if (first || updateMetadata()) { + Collection meta = cursor.queryCursor().fieldsMeta(); tbls = new ArrayList<>(meta.size()); cols = new ArrayList<>(meta.size()); @@ -184,8 +188,6 @@ public JdbcQueryTask(Ignite ignite, String cacheName, String schemaName, String cols.add(desc.fieldName().toUpperCase()); types.add(desc.fieldTypeName()); } - - CURSORS.put(uuid, cursor = new Cursor(qryCursor, qryCursor.iterator())); } List> rows = new ArrayList<>(); @@ -232,6 +234,13 @@ protected boolean lazy() { return false; } + /** + * @return Flag to update metadata on demand. + */ + protected boolean updateMetadata() { + return false; + } + /** * Schedules removal of stored cursor in case of remote query execution. * @@ -329,7 +338,7 @@ static class QueryResult implements Serializable { /** * @param uuid UUID.. * @param finished Finished. - * @param isQry + * @param isQry Is query flag. * @param rows Rows. * @param cols Columns. * @param tbls Tables. @@ -430,5 +439,12 @@ static final class Cursor implements Iterable> { public boolean hasNext() { return iter.hasNext(); } + + /** + * @return Cursor. + */ + public QueryCursorImpl> queryCursor() { + return (QueryCursorImpl>)cursor; + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java new file mode 100644 index 0000000000000..9203f572789b4 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java @@ -0,0 +1,100 @@ +/* + * 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}. + *

+ * 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 JdbcQueryTaskV3 extends JdbcQueryTaskV2 { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Lazy query execution flag. */ + private final boolean updateMeta; + + /** + * @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. + * @param updateMeta Update metadata on demand. + */ + public JdbcQueryTaskV3(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, boolean updateMeta) { + super(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, uuid, locQry, + collocatedQry, distributedJoins, enforceJoinOrder, lazy); + + this.updateMeta = updateMeta; + } + + /** {@inheritDoc} */ + @Override protected boolean updateMetadata() { + return updateMeta; + } + + /** + * @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. + * @param updateMeta Update metadata on demand. + * @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, boolean updateMeta) { + + if (updateMeta) + return new JdbcQueryTaskV3(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, + uuid, locQry, collocatedQry, distributedJoins, enforceJoinOrder, lazy, true); + else + return JdbcQueryTaskV2.createTask(ignite, cacheName, schemaName, sql, isQry, loc, args, fetchSize, + uuid, locQry, collocatedQry, distributedJoins, enforceJoinOrder, lazy); + } +} \ No newline at end of file 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 4f5a5f214d27c..b014803e23e4f 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 @@ -40,10 +40,12 @@ import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; +import javax.swing.text.html.HTMLDocument; import org.apache.ignite.Ignite; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.typedef.F; @@ -66,13 +68,13 @@ public class JdbcResultSet implements ResultSet { private final JdbcStatement stmt; /** Table names. */ - private final List tbls; + private List tbls; /** Column names. */ - private final List cols; + private List cols; /** Class names. */ - private final List types; + private List types; /** Rows cursor iterator. */ private Iterator> it; @@ -110,34 +112,52 @@ public class JdbcResultSet implements ResultSet { */ JdbcResultSet(boolean isQry, @Nullable UUID uuid, JdbcStatement stmt, List tbls, List cols, List types, List> fields, boolean finished) throws SQLException { - assert stmt != null; - assert tbls != null; - assert cols != null; - assert types != null; - assert fields != null; - this.isQry = isQry; - this.uuid = uuid; this.stmt = stmt; if (isQry) { + this.uuid = uuid; updCnt = -1; this.tbls = tbls; this.cols = cols; this.types = types; this.finished = finished; - this.it = fields.iterator(); - } else { + + if (fields != null) + it = fields.iterator(); + else + it = Collections.emptyIterator(); + } + else { updCnt = updateCounterFromQueryResult(fields); + + this.uuid = null; this.tbls = null; this.cols = null; this.types = null; this.finished = true; - this.it = null; + it = null; } } - /** {@inheritDoc} */ + /** + * @param stmt Statement. + * @param updCnt Update count. + */ + JdbcResultSet(JdbcStatement stmt, long updCnt) { + isQry = false; + this.updCnt = updCnt; + this.stmt = stmt; + + uuid = null; + tbls = null; + cols = null; + types = null; + finished = true; + it = null; + } + + /** {@inheritDoc} */ @SuppressWarnings("unchecked") @Override public boolean next() throws SQLException { ensureNotClosed(); @@ -158,40 +178,55 @@ else if (it.hasNext()) { return true; } else if (!finished) { - JdbcConnection conn = (JdbcConnection)stmt.getConnection(); + fetchPage(); - Ignite ignite = conn.ignite(); + return next(); + } - UUID nodeId = conn.nodeId(); + it = null; - boolean loc = nodeId == null; + return false; + } - // Connections from new clients send queries with new tasks, so we have to continue in the same manner - 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()); + /** + * + */ + private void fetchPage() throws SQLException { + JdbcConnection conn = (JdbcConnection)stmt.getConnection(); - try { - JdbcQueryTask.QueryResult res = - loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); + Ignite ignite = conn.ignite(); - finished = res.isFinished(); + UUID nodeId = conn.nodeId(); - it = res.getRows().iterator(); + boolean loc = nodeId == null; - return next(); - } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } - catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); - } - } + boolean updateMetadata = tbls == null; - it = null; + // Connections from new clients send queries with new tasks, so we have to continue in the same manner + JdbcQueryTask qryTask = JdbcQueryTaskV3.createTask(loc ? ignite : null, conn.cacheName(), conn.schemaName(), + null,true, loc, null, fetchSize, uuid, conn.isLocalQuery(), conn.isCollocatedQuery(), + conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy(), updateMetadata); - return false; + try { + JdbcQueryTask.QueryResult res = + loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); + + finished = res.isFinished(); + + it = res.getRows().iterator(); + + if (updateMetadata) { + tbls = res.getTbls(); + cols = res.getCols(); + types = res.getTypes(); + } + } + catch (IgniteSQLException e) { + throw e.toJdbcException(); + } + catch (Exception e) { + throw new SQLException("Failed to query Ignite.", e); + } } /** {@inheritDoc} */ @@ -442,6 +477,9 @@ void closeInternal() throws SQLException { @Override public ResultSetMetaData getMetaData() throws SQLException { ensureNotClosed(); + if (tbls == null) + fetchPage(); + return new JdbcResultSetMetadata(tbls, cols, types); } 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 7f466459bab69..f6f9218c14002 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 @@ -59,9 +59,6 @@ public class JdbcStatement implements Statement { /** Rows limit. */ private int maxRows; - /** Current result set. */ - protected ResultSet rs; - /** Query arguments. */ protected ArrayList args; @@ -74,17 +71,14 @@ public class JdbcStatement implements Statement { /** Fields indexes. */ Map fieldsIdxs = new HashMap<>(); - /** Current updated items count. */ - long updateCnt = -1; - /** Batch of statements. */ private List batch; /** Results. */ - private List results; + protected List results; /** Current result set index. */ - private int curRes = 0; + protected int curRes = 0; /** * Creates new statement. @@ -100,47 +94,6 @@ public class JdbcStatement implements Statement { /** {@inheritDoc} */ @SuppressWarnings("deprecation") @Override public ResultSet executeQuery(String sql) throws SQLException { -// ensureNotClosed(); -// -// rs = null; -// -// updateCnt = -1; -// -// if (F.isEmpty(sql)) -// throw new SQLException("SQL query is empty"); -// -// Ignite ignite = conn.ignite(); -// -// UUID nodeId = conn.nodeId(); -// -// UUID uuid = UUID.randomUUID(); -// -// boolean loc = nodeId == null; -// -// 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 = -// loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); -// -// JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), res.getTypes(), -// res.getRows(), res.isFinished()); -// -// rs.setFetchSize(fetchSize); -// -// resSets.add(rs); -// -// return rs; -// } -// catch (IgniteSQLException e) { -// throw e.toJdbcException(); -// } -// catch (Exception e) { -// throw new SQLException("Failed to query Ignite.", e); -// } - execute0(sql, true); return getResultSet(); @@ -151,7 +104,7 @@ public class JdbcStatement implements Statement { * @param isQuery Expected type of statements are contained in the query. * @throws SQLException On error. */ - void executeMultipleStmt(String sql, Boolean isQuery) throws SQLException { + private void executeMultipleStmt(String sql, Boolean isQuery) throws SQLException { ensureNotClosed(); closeResults(); @@ -176,12 +129,10 @@ sql, isQuery, loc, getArgs(), fetchSize, conn.isLocalQuery(), conn.isCollocatedQ results = new ArrayList<>(res.results().size()); for (JdbcQueryMultipleStatementsTask.ResultInfo rsInfo : res.results()) { - if (rsInfo.isQuery()) { - - } - else { - - } + if (rsInfo.isQuery()) + results.add(new JdbcResultSet(true, rsInfo.queryId(), this, null, null, null, null, false)); + else + results.add(new JdbcResultSet(this, rsInfo.updateCount())); } } catch (IgniteSQLException e) { @@ -247,98 +198,20 @@ sql, isQuery, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollo * @param isQuery Expected type of statements are contained in the query. * @throws SQLException On error. */ - private void execute0(String sql, Boolean isQuery) throws SQLException { - executeSingle(sql, isQuery); - -// if (conn.isMultipleStatementsSupported()) -// executeSingle(sql, isQuery); -// else -// executeMultipleStmt(sql, isQuery); + protected void execute0(String sql, Boolean isQuery) throws SQLException { + if (conn.isMultipleStatementsSupported()) + executeMultipleStmt(sql, isQuery); + else + executeSingle(sql, isQuery); } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { -// ensureNotClosed(); -// -// rs = null; -// -// updateCnt = -1; -// -// return Long.valueOf(doUpdate(sql, getArgs())).intValue(); - execute0(sql, false); return getUpdateCount(); } - /** - * Run update query. - * @param sql SQL query. - * @param args Update arguments. - * @return Number of affected items. - * @throws SQLException If failed. - */ - long doUpdate(String sql, Object[] args) throws SQLException { - if (F.isEmpty(sql)) - throw new SQLException("SQL query is empty"); - - Ignite ignite = conn.ignite(); - - UUID nodeId = conn.nodeId(); - - UUID uuid = UUID.randomUUID(); - - boolean loc = nodeId == null; - - if (!conn.isDmlSupported()) - throw new SQLException("Failed to query Ignite: DML operations are supported in versions 1.8.0 and newer"); - - 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 = - loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); - - return updateCnt = updateCounterFromQueryResult(qryRes.getRows()); - } - catch (IgniteSQLException e) { - throw e.toJdbcException(); - } - catch (SQLException e) { - throw e; - } - catch (Exception e) { - throw new SQLException("Failed to query Ignite.", e); - } - } - - /** - * @param rows query result. - * @return update counter, if found. - * @throws SQLException if getting an update counter from result proved to be impossible. - */ - private static long updateCounterFromQueryResult(List> rows) throws SQLException { - if (F.isEmpty(rows)) - return -1; - - if (rows.size() != 1) - throw new SQLException("Expected fetch size of 1 for update operation"); - - List row = rows.get(0); - - if (row.size() != 1) - throw new SQLException("Expected row size of 1 for update operation"); - - Object objRes = row.get(0); - - if (!(objRes instanceof Long)) - throw new SQLException("Unexpected update result type"); - - return (Long)objRes; - } - /** {@inheritDoc} */ @Override public void close() throws SQLException { conn.statements.remove(this); @@ -533,7 +406,7 @@ void closeInternal() throws SQLException { @Override public boolean getMoreResults() throws SQLException { ensureNotClosed(); - return false; + return getMoreResults(CLOSE_CURRENT_RESULT); } /** {@inheritDoc} */ @@ -624,9 +497,8 @@ void closeInternal() throws SQLException { */ protected int[] doBatchUpdate(String command, List batch, List> batchArgs) throws SQLException { - rs = null; - updateCnt = -1; + closeResults(); if ((F.isEmpty(command) || F.isEmpty(batchArgs)) && F.isEmpty(batch)) throw new SQLException("Batch is empty."); @@ -647,7 +519,10 @@ protected int[] doBatchUpdate(String command, List batch, List streamer, PreparedStatement nativeStmt) { @@ -53,8 +56,15 @@ class JdbcStreamedPreparedStatement extends JdbcPreparedStatement { } /** {@inheritDoc} */ - @Override long doUpdate(String sql, Object[] args) throws SQLException { - return conn.ignite().context().query().streamUpdateQuery(conn.cacheName(), conn.schemaName(), - streamer, sql, args); + @Override protected void execute0(String sql, Boolean isQuery) throws SQLException { + assert isQuery != null && !isQuery; + + long updCnt = conn.ignite().context().query().streamUpdateQuery(conn.cacheName(), conn.schemaName(), + streamer, sql, getArgs()); + + JdbcResultSet rs = new JdbcResultSet(this, updCnt); + + results = Collections.singletonList(rs); + curRes = 0; } } From 53ae0620ed54c6a867030e5f8f4e48686718b531 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 14 Sep 2017 18:29:41 +0300 Subject: [PATCH 28/36] IGNITE-6358: minors --- .../ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java | 3 --- .../jdbc2/JdbcQueryMultipleStatementsTask.java | 11 +---------- .../apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java | 7 +------ .../apache/ignite/internal/jdbc2/JdbcResultSet.java | 2 -- .../internal/jdbc2/JdbcStreamedPreparedStatement.java | 2 -- 5 files changed, 2 insertions(+), 23 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java index 162e98f401abb..58c20d569faff 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java @@ -20,9 +20,7 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.ResultSet; -import java.sql.SQLException; import java.sql.Statement; -import java.util.concurrent.Callable; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.configuration.CacheConfiguration; @@ -30,7 +28,6 @@ import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; -import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.jetbrains.annotations.NotNull; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java index df64e1689265b..47d8319ba9fbc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java @@ -19,31 +19,22 @@ import java.io.Serializable; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import java.util.UUID; -import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteJdbcDriver; -import org.apache.ignite.IgniteSystemProperties; import org.apache.ignite.cache.query.FieldsQueryCursor; -import org.apache.ignite.cache.query.QueryCursor; import org.apache.ignite.cache.query.SqlFieldsQuery; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.processors.cache.QueryCursorImpl; -import org.apache.ignite.internal.util.typedef.CAX; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteCallable; import org.apache.ignite.resources.IgniteInstanceResource; /** * Task for SQL queries execution through {@link IgniteJdbcDriver}. + * The query can contains several SQL statements. */ class JdbcQueryMultipleStatementsTask implements IgniteCallable { /** Serial version uid. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java index 9203f572789b4..f470b9a89ca0a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java @@ -20,20 +20,15 @@ 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}. - *

- * 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 JdbcQueryTaskV3 extends JdbcQueryTaskV2 { /** Serial version uid. */ private static final long serialVersionUID = 0L; - /** Lazy query execution flag. */ + /** Update metadata on demand flag. */ private final boolean updateMeta; /** 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 b014803e23e4f..26825a24d2a68 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 @@ -39,13 +39,11 @@ import java.sql.Timestamp; import java.util.ArrayList; import java.util.Calendar; -import java.util.Collection; import java.util.Collections; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.UUID; -import javax.swing.text.html.HTMLDocument; import org.apache.ignite.Ignite; import org.apache.ignite.internal.processors.query.IgniteSQLException; import org.apache.ignite.internal.util.typedef.F; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStreamedPreparedStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStreamedPreparedStatement.java index 51ff419902d49..bd2fa25a40c7c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStreamedPreparedStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStreamedPreparedStatement.java @@ -20,9 +20,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; import java.util.Collections; -import java.util.List; import org.apache.ignite.IgniteDataStreamer; -import org.apache.ignite.internal.IgniteEx; /** * Prepared statement associated with a data streamer. From 253a7b22239d991896a912a1bb172af35b5d93f6 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Fri, 15 Sep 2017 16:53:09 +0300 Subject: [PATCH 29/36] IGNITE-6046: fix review comment --- .../processors/query/h2/IgniteH2Indexing.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java index 8bb75260807b0..73d8715ef0dd1 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/IgniteH2Indexing.java @@ -1303,9 +1303,11 @@ private Iterable> runQueryTwoStep( List meta = cachedQry.meta(); - return Collections.singletonList(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), + List>> res = Collections.singletonList(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), qry.getArgs(), keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, - twoStepQry, meta, cachedQryKey, cachedQry)); + twoStepQry, meta)); + + return res; } List>> res = new ArrayList<>(1); @@ -1401,7 +1403,7 @@ private Iterable> runQueryTwoStep( res.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, - twoStepQry, meta, cachedQryKey, cachedQry)); + twoStepQry, meta)); continue; } @@ -1495,7 +1497,13 @@ private Iterable> runQueryTwoStep( res.add(executeTwoStepsQuery(schemaName, qry.getPageSize(), qry.getPartitions(), args, keepBinary, qry.isLazy(), qry.getTimeout(), cancel, sqlQry, enforceJoinOrder, - twoStepQry, meta, cachedQryKey, cachedQry)); + twoStepQry, meta)); + + if (cachedQry == null && !twoStepQry.explain()) { + cachedQry = new H2TwoStepCachedQuery(meta, twoStepQry.copy()); + + twoStepCache.putIfAbsent(cachedQryKey, cachedQry); + } } return res; @@ -1526,14 +1534,12 @@ private void checkQueryType(SqlFieldsQuery qry, boolean isQry) { * @param enforceJoinOrder Enforce join orded flag. * @param twoStepQry Two-steps query. * @param meta Metadata. - * @param cachedQryKey Cached query key. - * @param cachedQry Cached query. * @return Cursor. */ private FieldsQueryCursor> executeTwoStepsQuery(String schemaName, int pageSize, int partitions[], Object[] args, boolean keepBinary, boolean lazy, int timeout, GridQueryCancel cancel, String sqlQry, boolean enforceJoinOrder, GridCacheTwoStepQuery twoStepQry, - List meta, H2TwoStepCachedQueryKey cachedQryKey, H2TwoStepCachedQuery cachedQry) { + List meta) { if (log.isDebugEnabled()) log.debug("Parsed query: `" + sqlQry + "` into two step query: " + twoStepQry); @@ -1557,12 +1563,6 @@ private FieldsQueryCursor> executeTwoStepsQuery(String schemaName, int p cursor.fieldsMeta(meta); - if (cachedQry == null && !twoStepQry.explain()) { - cachedQry = new H2TwoStepCachedQuery(meta, twoStepQry.copy()); - - twoStepCache.putIfAbsent(cachedQryKey, cachedQry); - } - return cursor; } From 42ec14cd61bbac271b21bebf5126c9a93e28fb81 Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 18 Sep 2017 17:51:49 +0300 Subject: [PATCH 30/36] IGNITE-6046: self review --- .../apache/ignite/internal/jdbc/thin/JdbcThinStatement.java | 3 ++- .../org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java | 3 --- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java index 5e0892293aee8..8e5f05bd9e55d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinStatement.java @@ -167,7 +167,8 @@ else if (res0 instanceof JdbcQueryExecuteMultipleStatementsResult) { else throw new SQLException("Unexpected result [res=" + res0 + ']'); - assert resultSets.size() > 0 : "At least one results set is expected"; } + assert resultSets.size() > 0 : "At least one results set is expected"; + } /** {@inheritDoc} */ @Override public int executeUpdate(String sql) throws SQLException { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java index e9bd5a2bd1adf..a7b6063367c5c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc/thin/JdbcThinTcpIo.java @@ -49,9 +49,6 @@ public class JdbcThinTcpIo { /** Version 2.1.0. */ private static final ClientListenerProtocolVersion VER_2_1_0 = ClientListenerProtocolVersion.create(2, 1, 0); - /** Version 2.1.5. */ - private static final ClientListenerProtocolVersion VER_2_1_5 = ClientListenerProtocolVersion.create(2, 1, 5); - /** Version 2.3.1. */ private static final ClientListenerProtocolVersion VER_2_3_1 = ClientListenerProtocolVersion.create(2, 3, 1); From 6756bf023b37b10b260db438ea4933a1e45d5f5a Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Fri, 29 Sep 2017 13:07:18 +0300 Subject: [PATCH 31/36] IGNITE-6358: minor --- .../apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java | 6 ++++-- .../org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java index 8b0187022f121..e403b89f84f00 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java @@ -285,7 +285,8 @@ public void testExecuteQueryMultipleOnlyDml() throws Exception { int stmtCnt = 10; - StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); + StringBuilder sql = new StringBuilder( + "drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); for (int i = 0; i < stmtCnt; ++i) sql.append("insert into test (ID, NAME) values (" + i + ", 'name_" + i +"'); "); @@ -318,7 +319,8 @@ public void testExecuteQueryMultipleMixed() throws Exception { int stmtCnt = 10; - StringBuilder sql = new StringBuilder("drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); + StringBuilder sql = new StringBuilder( + "drop table if exists test; create table test(ID int primary key, NAME varchar(20)); "); for (int i = 0; i < stmtCnt; ++i) { if (i % 2 == 0) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java index f470b9a89ca0a..1ed0069650bbb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java @@ -22,7 +22,7 @@ import org.apache.ignite.IgniteJdbcDriver; /** - * Task for SQL queries execution through {@link IgniteJdbcDriver}. + * Task for fetch results of multi-statement query. */ class JdbcQueryTaskV3 extends JdbcQueryTaskV2 { /** Serial version uid. */ From c888ff563efdcc95b39b6fa93a6fde68069121aa Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Mon, 2 Oct 2017 15:47:13 +0300 Subject: [PATCH 32/36] IGNITE-6358: add property 'multipleStatements' --- .../ignite/internal/jdbc2/JdbcStatementSelfTest.java | 4 +++- .../main/java/org/apache/ignite/IgniteJdbcDriver.java | 9 ++++++++- .../apache/ignite/internal/jdbc2/JdbcConnection.java | 10 ++++++++-- .../apache/ignite/internal/jdbc2/JdbcStatement.java | 2 +- 4 files changed, 20 insertions(+), 5 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java index e403b89f84f00..cd7a1eedd1f96 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java @@ -45,7 +45,7 @@ public class JdbcStatementSelfTest extends GridCommonAbstractTest { private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** JDBC URL. */ - private static final String BASE_URL = CFG_URL_PREFIX + "cache=default@modules/clients/src/test/config/jdbc-config.xml"; + private static final String BASE_URL = CFG_URL_PREFIX + "cache=default:multipleStatements=true@modules/clients/src/test/config/jdbc-config.xml"; /** SQL query. */ private static final String SQL = "select * from Person where age > 30"; @@ -353,6 +353,8 @@ public void testExecuteQueryMultipleMixed() throws Exception { ResultSet rs = stmt.getResultSet(); + assert rs.getMetaData().getColumnCount() == 2; + int rowsCnt = 0; while(rs.next()) 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 f519589dbfe5a..9d233d578f268 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java @@ -331,6 +331,9 @@ public class IgniteJdbcDriver implements Driver { /** Whether DML streaming will overwrite existing cache entries. */ private static final String PARAM_STREAMING_ALLOW_OVERWRITE = "streamingAllowOverwrite"; + /** Allow queries with multiple statements. */ + private static final String PARAM_MULTIPLE_STMTS = "multipleStatements"; + /** Hostname property name. */ public static final String PROP_HOST = PROP_PREFIX + "host"; @@ -376,6 +379,9 @@ public class IgniteJdbcDriver implements Driver { /** Whether DML streaming will overwrite existing cache entries. */ public static final String PROP_STREAMING_ALLOW_OVERWRITE = PROP_PREFIX + PARAM_STREAMING_ALLOW_OVERWRITE; + /** Allow query with multiple statements. */ + public static final String PROP_MULTIPLE_STMTS = PROP_PREFIX + PARAM_MULTIPLE_STMTS; + /** Cache name property name. */ public static final String PROP_CFG = PROP_PREFIX + "cfg"; @@ -447,7 +453,8 @@ public class IgniteJdbcDriver implements Driver { 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), "") + new JdbcDriverPropertyInfo("Transactions Allowed", info.getProperty(PROP_TX_ALLOWED), ""), + new JdbcDriverPropertyInfo("Queries with multiple statements allowed", info.getProperty(PROP_MULTIPLE_STMTS), "") ); if (info.getProperty(PROP_CFG) != null) 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 274381869a7e5..326bdfb48334c 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 @@ -80,6 +80,7 @@ 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_MULTIPLE_STMTS; import static org.apache.ignite.IgniteJdbcDriver.PROP_NODE_ID; import static org.apache.ignite.IgniteJdbcDriver.PROP_TX_ALLOWED; import static org.apache.ignite.IgniteJdbcDriver.PROP_STREAMING; @@ -164,6 +165,9 @@ public class JdbcConnection implements Connection { /** Allow overwrites for duplicate keys on streamed {@code INSERT}s. */ private final boolean streamAllowOverwrite; + /** Allow multiple query with multiple statements. */ + private final boolean multipleStmts; + /** Statements. */ final Set statements = new HashSet<>(); @@ -204,6 +208,8 @@ public JdbcConnection(String url, Properties props) throws SQLException { // by IgniteDataStreamer.DFLT_PARALLEL_OPS_MULTIPLIER will be used streamNodeParOps = Integer.parseInt(props.getProperty(PROP_STREAMING_PER_NODE_PAR_OPS, "0")); + multipleStmts = Boolean.parseBoolean(props.getProperty(PROP_MULTIPLE_STMTS)); + String nodeIdProp = props.getProperty(PROP_NODE_ID); if (nodeIdProp != null) @@ -843,8 +849,8 @@ boolean isDmlSupported() { /** * @return {@code true} if target node has DML support, {@code false} otherwise. */ - boolean isMultipleStatementsSupported() { - return ignite.version().greaterThanEqual(2, 1, 5); + boolean isMultipleStatementsAllowed() { + return multipleStmts; } /** 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 5f257052c3e72..9f2aeeb854aa4 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 @@ -189,7 +189,7 @@ sql, isQuery, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollo * @throws SQLException On error. */ protected void execute0(String sql, Boolean isQuery) throws SQLException { - if (conn.isMultipleStatementsSupported()) + if (conn.isMultipleStatementsAllowed()) executeMultipleStmt(sql, isQuery); else executeSingle(sql, isQuery); From 0b715d0dbea392b8f3425c7f7331f68378d352a7 Mon Sep 17 00:00:00 2001 From: devozerov Date: Wed, 4 Oct 2017 15:42:00 +0300 Subject: [PATCH 33/36] Cosmetics. --- .../org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java | 5 ++--- .../org/apache/ignite/internal/jdbc2/JdbcResultSet.java | 6 +++--- .../org/apache/ignite/internal/jdbc2/JdbcStatement.java | 2 ++ .../internal/jdbc2/JdbcStreamedPreparedStatement.java | 1 + 4 files changed, 8 insertions(+), 6 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java index 1ed0069650bbb..cb2d45220f7f3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskV3.java @@ -19,7 +19,6 @@ import java.util.UUID; import org.apache.ignite.Ignite; -import org.apache.ignite.IgniteJdbcDriver; /** * Task for fetch results of multi-statement query. @@ -44,7 +43,7 @@ class JdbcQueryTaskV3 extends JdbcQueryTaskV2 { * @param locQry Local query flag. * @param collocatedQry Collocated query flag. * @param distributedJoins Distributed joins flag. - * @param enforceJoinOrder Enforce joins order falg. + * @param enforceJoinOrder Enforce joins order flag. * @param lazy Lazy query execution flag. * @param updateMeta Update metadata on demand. */ @@ -75,7 +74,7 @@ public JdbcQueryTaskV3(Ignite ignite, String cacheName, String schemaName, Strin * @param locQry Local query flag. * @param collocatedQry Collocated query flag. * @param distributedJoins Distributed joins flag. - * @param enforceJoinOrder Enforce joins order falg. + * @param enforceJoinOrder Enforce joins order flag. * @param lazy Lazy query execution flag. * @param updateMeta Update metadata on demand. * @return Appropriate task JdbcQueryTask or JdbcQueryTaskV2. 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 9f2dabf5a5d56..d33d75159ff0f 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 @@ -1604,17 +1604,17 @@ private static long updateCounterFromQueryResult(List> rows) throws SQLE return -1; if (rows.size() != 1) - throw new SQLException("Expected fetch size of 1 for update operation"); + throw new SQLException("Expected fetch size of 1 for update operation."); List row = rows.get(0); if (row.size() != 1) - throw new SQLException("Expected row size of 1 for update operation"); + throw new SQLException("Expected row size of 1 for update operation."); Object objRes = row.get(0); if (!(objRes instanceof Long)) - throw new SQLException("Unexpected update result type"); + throw new SQLException("Unexpected update result type."); return (Long)objRes; } 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 9f2aeeb854aa4..a9ca2afa47bc5 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 @@ -512,6 +512,7 @@ protected int[] doBatchUpdate(String command, List batch, List Date: Wed, 4 Oct 2017 16:58:14 +0300 Subject: [PATCH 34/36] IGNITE-6358: fix review comments --- .../jdbc2/JdbcNoDefaultCacheTest.java | 15 +++-- .../internal/jdbc2/JdbcDatabaseMetadata.java | 2 +- .../JdbcQueryMultipleStatementsTask.java | 3 + .../ignite/internal/jdbc2/JdbcQueryTask.java | 15 +++-- .../ignite/internal/jdbc2/JdbcStatement.java | 55 ------------------- 5 files changed, 25 insertions(+), 65 deletions(-) diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java index 58c20d569faff..e851319c370af 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcNoDefaultCacheTest.java @@ -19,8 +19,9 @@ import java.sql.Connection; import java.sql.DriverManager; -import java.sql.ResultSet; +import java.sql.SQLException; import java.sql.Statement; +import java.util.concurrent.Callable; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; import org.apache.ignite.configuration.CacheConfiguration; @@ -28,6 +29,7 @@ import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; +import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.jetbrains.annotations.NotNull; @@ -129,11 +131,14 @@ public void testNoCacheNameQuery() throws Exception { assertNotNull(stmt); assertFalse(stmt.isClosed()); - stmt.execute("select t._key, t._val from \"cache1\".Integer t"); + Throwable throwable = GridTestUtils.assertThrows(null, new Callable() { + @Override public Void call() throws Exception { + stmt.execute("select t._key, t._val from \"cache1\".Integer t"); + return null; + } + }, SQLException.class, "Failed to query Ignite."); - ResultSet rs = stmt.getResultSet(); - - assert rs.next(); + assertEquals(throwable.getCause().getMessage(), "Ouch! Argument is invalid: Cache name must not be null or empty."); } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java index 34cd0e9dc42ae..6ffcf1b95b1fd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcDatabaseMetadata.java @@ -318,7 +318,7 @@ public class JdbcDatabaseMetadata implements DatabaseMetaData { /** {@inheritDoc} */ @Override public boolean supportsMultipleResultSets() { - return true; + return conn.isMultipleStatementsAllowed(); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java index 47d8319ba9fbc..c76f429f950d1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java @@ -152,6 +152,9 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String JdbcQueryTask.Cursor jdbcCur = new JdbcQueryTask.Cursor(cur, cur.iterator()); JdbcQueryTask.addCursor(qryId, jdbcCur); + + if (!loc) + JdbcQueryTask.scheduleRemoval(qryId); } ResultInfo resInfo = new ResultInfo(cur.isQuery(), qryId, updCnt); 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 f6467b3fcc588..d8c2ad0204af8 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 @@ -210,7 +210,7 @@ public JdbcQueryTask(Ignite ignite, String cacheName, String schemaName, String remove(uuid, cursor); else if (first) { if (!loc) - scheduleRemoval(uuid, RMV_DELAY); + scheduleRemoval(uuid); } else if (!loc && !CURSORS.replace(uuid, cursor, new Cursor(cursor.cursor, cursor.iter))) assert !CURSORS.containsKey(uuid) : "Concurrent cursor modification."; @@ -245,11 +245,18 @@ protected boolean updateMetadata() { * Schedules removal of stored cursor in case of remote query execution. * * @param uuid Cursor UUID. - * @param delay Delay in milliseconds. */ - private void scheduleRemoval(final UUID uuid, long delay) { - assert !loc; + static void scheduleRemoval(final UUID uuid) { + scheduleRemoval(uuid, RMV_DELAY); + } + /** + * Schedules removal of stored cursor in case of remote query execution. + * + * @param uuid Cursor UUID. + * @param delay Delay in milliseconds. + */ + private static void scheduleRemoval(final UUID uuid, long delay) { SCHEDULER.schedule(new CAX() { @Override public void applyx() { while (true) { 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 9f2aeeb854aa4..badbd69d3265e 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 @@ -300,61 +300,6 @@ void closeInternal() throws SQLException { /** {@inheritDoc} */ @Override public boolean execute(String sql) throws SQLException { -// if (!conn.isDmlSupported()) { -// // We attempt to run a query without any checks as long as server does not support DML anyway, -// // so it simply will throw an exception when given a DML statement instead of a query. -// rs = executeQuery(sql); -// -// return true; -// } -// -// ensureNotClosed(); -// -// rs = null; -// -// updateCnt = -1; -// -// if (F.isEmpty(sql)) -// throw new SQLException("SQL query is empty"); -// -// Ignite ignite = conn.ignite(); -// -// UUID nodeId = conn.nodeId(); -// -// UUID uuid = UUID.randomUUID(); -// -// boolean loc = nodeId == null; -// -// 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 = -// loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); -// -// if (res.isQuery()) { -// JdbcResultSet rs = new JdbcResultSet(uuid, this, res.getTbls(), res.getCols(), -// res.getTypes(), res.getRows(), res.isFinished()); -// -// rs.setFetchSize(fetchSize); -// -// resSets.add(rs); -// -// this.rs = rs; -// } -// else -// updateCnt = updateCounterFromQueryResult(res.getRows()); -// -// return res.isQuery(); -// } -// catch (IgniteSQLException e) { -// throw e.toJdbcException(); -// } -// catch (Exception e) { -// throw new SQLException("Failed to query Ignite.", e); -// } - execute0(sql, null); return results.get(0).isQuery(); From 84cb22ec5671132166dda688b34517941b0efbc2 Mon Sep 17 00:00:00 2001 From: devozerov Date: Thu, 5 Oct 2017 11:52:34 +0300 Subject: [PATCH 35/36] Cosmetics. --- .../java/org/apache/ignite/internal/jdbc2/JdbcConnection.java | 4 ++-- .../java/org/apache/ignite/internal/jdbc2/JdbcStatement.java | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) 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 326bdfb48334c..ccc09ece9a4bd 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 @@ -165,7 +165,7 @@ public class JdbcConnection implements Connection { /** Allow overwrites for duplicate keys on streamed {@code INSERT}s. */ private final boolean streamAllowOverwrite; - /** Allow multiple query with multiple statements. */ + /** Allow queries with multiple statements. */ private final boolean multipleStmts; /** Statements. */ @@ -847,7 +847,7 @@ boolean isDmlSupported() { } /** - * @return {@code true} if target node has DML support, {@code false} otherwise. + * @return {@code true} if multiple statements allowed, {@code false} otherwise. */ boolean isMultipleStatementsAllowed() { return multipleStmts; 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 5fdcfdc69f4c5..3165334a456b4 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 @@ -103,7 +103,7 @@ public class JdbcStatement implements Statement { * @param isQuery Expected type of statements are contained in the query. * @throws SQLException On error. */ - private void executeMultipleStmt(String sql, Boolean isQuery) throws SQLException { + private void executeMultipleStatement(String sql, Boolean isQuery) throws SQLException { ensureNotClosed(); closeResults(); @@ -190,7 +190,7 @@ sql, isQuery, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollo */ protected void execute0(String sql, Boolean isQuery) throws SQLException { if (conn.isMultipleStatementsAllowed()) - executeMultipleStmt(sql, isQuery); + executeMultipleStatement(sql, isQuery); else executeSingle(sql, isQuery); } From fe76f25eebd63f8ea46554d9129e47522a9cb4ca Mon Sep 17 00:00:00 2001 From: tledkov-gridgain Date: Thu, 5 Oct 2017 12:25:58 +0300 Subject: [PATCH 36/36] IGNITE-6358: fix review comments --- .../internal/jdbc2/JdbcStatementSelfTest.java | 7 +- .../org/apache/ignite/IgniteJdbcDriver.java | 2 +- .../JdbcQueryMultipleStatementsTask.java | 87 +------------ .../ignite/internal/jdbc2/JdbcQueryTask.java | 105 +-------------- .../internal/jdbc2/JdbcQueryTaskResult.java | 120 ++++++++++++++++++ .../ignite/internal/jdbc2/JdbcResultSet.java | 2 +- .../ignite/internal/jdbc2/JdbcStatement.java | 8 +- .../jdbc2/JdbcStatementResultInfo.java | 73 +++++++++++ 8 files changed, 213 insertions(+), 191 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskResult.java create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatementResultInfo.java diff --git a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java index cd7a1eedd1f96..d3f77e03d2d5b 100644 --- a/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java +++ b/modules/clients/src/test/java/org/apache/ignite/internal/jdbc2/JdbcStatementSelfTest.java @@ -45,7 +45,8 @@ public class JdbcStatementSelfTest extends GridCommonAbstractTest { private static final TcpDiscoveryIpFinder IP_FINDER = new TcpDiscoveryVmIpFinder(true); /** JDBC URL. */ - private static final String BASE_URL = CFG_URL_PREFIX + "cache=default:multipleStatements=true@modules/clients/src/test/config/jdbc-config.xml"; + private static final String BASE_URL = CFG_URL_PREFIX + + "cache=default:multipleStatementsAllowed=true@modules/clients/src/test/config/jdbc-config.xml"; /** SQL query. */ private static final String SQL = "select * from Person where age > 30"; @@ -281,6 +282,8 @@ public void testExecuteQueryMultipleOnlyResultSets() throws Exception { * @throws Exception If failed. */ public void testExecuteQueryMultipleOnlyDml() throws Exception { + assert conn.getMetaData().supportsMultipleResultSets(); + conn.setSchema(null); int stmtCnt = 10; @@ -315,6 +318,8 @@ public void testExecuteQueryMultipleOnlyDml() throws Exception { * @throws Exception If failed. */ public void testExecuteQueryMultipleMixed() throws Exception { + assert conn.getMetaData().supportsMultipleResultSets(); + conn.setSchema(null); int stmtCnt = 10; 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 9d233d578f268..b03e38733f58b 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteJdbcDriver.java @@ -332,7 +332,7 @@ public class IgniteJdbcDriver implements Driver { private static final String PARAM_STREAMING_ALLOW_OVERWRITE = "streamingAllowOverwrite"; /** Allow queries with multiple statements. */ - private static final String PARAM_MULTIPLE_STMTS = "multipleStatements"; + private static final String PARAM_MULTIPLE_STMTS = "multipleStatementsAllowed"; /** Hostname property name. */ public static final String PROP_HOST = PROP_PREFIX + "host"; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java index c76f429f950d1..bf7c24e640ccd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryMultipleStatementsTask.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.jdbc2; -import java.io.Serializable; import java.util.ArrayList; import java.util.List; import java.util.UUID; @@ -36,7 +35,7 @@ * Task for SQL queries execution through {@link IgniteJdbcDriver}. * The query can contains several SQL statements. */ -class JdbcQueryMultipleStatementsTask implements IgniteCallable { +class JdbcQueryMultipleStatementsTask implements IgniteCallable> { /** Serial version uid. */ private static final long serialVersionUID = 0L; @@ -109,7 +108,7 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String } /** {@inheritDoc} */ - @Override public QueryResult call() throws Exception { + @Override public List call() throws Exception { SqlFieldsQuery qry = (isQry != null ? new JdbcSqlFieldsQuery(sql, isQry) : new SqlFieldsQuery(sql)) .setArgs(args); @@ -125,7 +124,7 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String List>> curs = ctx.query().querySqlFieldsNoCache(qry, true, false); - List resultsInfo = new ArrayList<>(curs.size()); + List resultsInfo = new ArrayList<>(curs.size()); for (FieldsQueryCursor> cur0 : curs) { QueryCursorImpl> cur = (QueryCursorImpl>)cur0; @@ -157,88 +156,12 @@ public JdbcQueryMultipleStatementsTask(Ignite ignite, String schemaName, String JdbcQueryTask.scheduleRemoval(qryId); } - ResultInfo resInfo = new ResultInfo(cur.isQuery(), qryId, updCnt); + JdbcStatementResultInfo resInfo = new JdbcStatementResultInfo(cur.isQuery(), qryId, updCnt); resultsInfo.add(resInfo); } - return new QueryResult(resultsInfo); + return resultsInfo; } - /** - * Result of query execution. - */ - static class QueryResult implements Serializable { - /** Serial version uid. */ - private static final long serialVersionUID = 0L; - - /** Uuid. */ - private final List results; - - /** - * @param results Results info list. - */ - public QueryResult(List results) { - this.results = results; - } - - /** - * @return Results info list. - */ - public List results() { - return results; - } - } - - /** - * JDBC statement result information. Keeps statement type (SELECT or UPDATE) and - * queryId or update count (depends on statement type). - */ - public class ResultInfo { - /** Query flag. */ - private boolean isQuery; - - /** Update count. */ - private long updCnt; - - /** Query ID. */ - private UUID qryId; - - /** - * @param isQuery Query flag. - * @param qryId Query ID. - * @param updCnt Update count. - */ - public ResultInfo(boolean isQuery, UUID qryId, long updCnt) { - this.isQuery = isQuery; - this.updCnt = updCnt; - this.qryId = qryId; - } - - /** - * @return Query flag. - */ - public boolean isQuery() { - return isQuery; - } - - /** - * @return Query ID. - */ - public UUID queryId() { - return qryId; - } - - /** - * @return Update count. - */ - public long updateCount() { - return updCnt; - } - - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(ResultInfo.class, this); - } - } } 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 d8c2ad0204af8..ecbfb713451bd 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 @@ -17,7 +17,6 @@ package org.apache.ignite.internal.jdbc2; -import java.io.Serializable; import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; @@ -50,7 +49,7 @@ * This parameter can be configured via {@link IgniteSystemProperties#IGNITE_JDBC_DRIVER_CURSOR_REMOVE_DELAY} * system property. */ -class JdbcQueryTask implements IgniteCallable { +class JdbcQueryTask implements IgniteCallable { /** Serial version uid. */ private static final long serialVersionUID = 0L; @@ -132,7 +131,7 @@ public JdbcQueryTask(Ignite ignite, String cacheName, String schemaName, String } /** {@inheritDoc} */ - @Override public JdbcQueryTask.QueryResult call() throws Exception { + @Override public JdbcQueryTaskResult call() throws Exception { Cursor cursor = CURSORS.get(uuid); List tbls = null; @@ -217,7 +216,7 @@ else if (!loc && !CURSORS.replace(uuid, cursor, new Cursor(cursor.cursor, cursor assert isQry != null : "Query flag must be set prior to returning result"; - return new QueryResult(uuid, finished, isQry, rows, cols, tbls, types); + return new JdbcQueryTaskResult(uuid, finished, isQry, rows, cols, tbls, types); } /** @@ -314,104 +313,6 @@ static void remove(UUID uuid) { c.cursor.close(); } - /** - * Result of query execution. - */ - static class QueryResult implements Serializable { - /** Serial version uid. */ - private static final long serialVersionUID = 0L; - - /** Uuid. */ - private final UUID uuid; - - /** Finished. */ - private final boolean finished; - - /** Result type - query or update. */ - private final boolean isQry; - - /** Rows. */ - private final List> rows; - - /** Tables. */ - private final List tbls; - - /** Columns. */ - private final List cols; - - /** Types. */ - private final List types; - - /** - * @param uuid UUID.. - * @param finished Finished. - * @param isQry Is query flag. - * @param rows Rows. - * @param cols Columns. - * @param tbls Tables. - * @param types Types. - */ - public QueryResult(UUID uuid, boolean finished, boolean isQry, List> rows, List cols, - List tbls, List types) { - this.isQry = isQry; - this.cols = cols; - this.uuid = uuid; - this.finished = finished; - this.rows = rows; - this.tbls = tbls; - this.types = types; - } - - /** - * @return Query result rows. - */ - public List> getRows() { - return rows; - } - - /** - * @return Tables metadata. - */ - public List getTbls() { - return tbls; - } - - /** - * @return Columns metadata. - */ - public List getCols() { - return cols; - } - - /** - * @return Types metadata. - */ - public List getTypes() { - return types; - } - - /** - * @return Query UUID. - */ - public UUID getUuid() { - return uuid; - } - - /** - * @return {@code True} if it is finished query. - */ - public boolean isFinished() { - return finished; - } - - /** - * @return {@code true} if it is result of a query operation, not update; {@code false} otherwise. - */ - public boolean isQuery() { - return isQry; - } - } - /** * Cursor. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskResult.java new file mode 100644 index 0000000000000..607bb3877ad64 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcQueryTaskResult.java @@ -0,0 +1,120 @@ +/* + * 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.io.Serializable; +import java.util.List; +import java.util.UUID; + +/** + * Result of query execution. + */ +class JdbcQueryTaskResult implements Serializable { + /** Serial version uid. */ + private static final long serialVersionUID = 0L; + + /** Uuid. */ + private final UUID uuid; + + /** Finished. */ + private final boolean finished; + + /** Result type - query or update. */ + private final boolean isQry; + + /** Rows. */ + private final List> rows; + + /** Tables. */ + private final List tbls; + + /** Columns. */ + private final List cols; + + /** Types. */ + private final List types; + + /** + * @param uuid UUID.. + * @param finished Finished. + * @param isQry Is query flag. + * @param rows Rows. + * @param cols Columns. + * @param tbls Tables. + * @param types Types. + */ + public JdbcQueryTaskResult(UUID uuid, boolean finished, boolean isQry, List> rows, List cols, + List tbls, List types) { + this.isQry = isQry; + this.cols = cols; + this.uuid = uuid; + this.finished = finished; + this.rows = rows; + this.tbls = tbls; + this.types = types; + } + + /** + * @return Query result rows. + */ + public List> getRows() { + return rows; + } + + /** + * @return Tables metadata. + */ + public List getTbls() { + return tbls; + } + + /** + * @return Columns metadata. + */ + public List getCols() { + return cols; + } + + /** + * @return Types metadata. + */ + public List getTypes() { + return types; + } + + /** + * @return Query UUID. + */ + public UUID getUuid() { + return uuid; + } + + /** + * @return {@code True} if it is finished query. + */ + public boolean isFinished() { + return finished; + } + + /** + * @return {@code true} if it is result of a query operation, not update; {@code false} otherwise. + */ + public boolean isQuery() { + return isQry; + } +} 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 d33d75159ff0f..69d4252d7bcee 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 @@ -208,7 +208,7 @@ private void fetchPage() throws SQLException { conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy(), updateMetadata); try { - JdbcQueryTask.QueryResult res = + JdbcQueryTaskResult res = loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); finished = res.isFinished(); 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 5fdcfdc69f4c5..5ff32deccd27d 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 @@ -122,12 +122,12 @@ sql, isQuery, loc, getArgs(), fetchSize, conn.isLocalQuery(), conn.isCollocatedQ conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { - JdbcQueryMultipleStatementsTask.QueryResult res = + List rsInfos = loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); - results = new ArrayList<>(res.results().size()); + results = new ArrayList<>(rsInfos.size()); - for (JdbcQueryMultipleStatementsTask.ResultInfo rsInfo : res.results()) { + for (JdbcStatementResultInfo rsInfo : rsInfos) { if (rsInfo.isQuery()) results.add(new JdbcResultSet(true, rsInfo.queryId(), this, null, null, null, null, false)); else @@ -166,7 +166,7 @@ sql, isQuery, loc, getArgs(), fetchSize, uuid, conn.isLocalQuery(), conn.isCollo conn.isDistributedJoins(), conn.isEnforceJoinOrder(), conn.isLazy()); try { - JdbcQueryTask.QueryResult qryRes = + JdbcQueryTaskResult qryRes = loc ? qryTask.call() : ignite.compute(ignite.cluster().forNodeId(nodeId)).call(qryTask); JdbcResultSet rs = new JdbcResultSet(qryRes.isQuery(), uuid, this, qryRes.getTbls(), qryRes.getCols(), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatementResultInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatementResultInfo.java new file mode 100644 index 0000000000000..8aa02f1352bd1 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/jdbc2/JdbcStatementResultInfo.java @@ -0,0 +1,73 @@ +/* + * 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.internal.util.typedef.internal.S; + +/** + * JDBC statement result information. Keeps statement type (SELECT or UPDATE) and + * queryId or update count (depends on statement type). + */ +public class JdbcStatementResultInfo { + /** Query flag. */ + private boolean isQuery; + + /** Update count. */ + private long updCnt; + + /** Query ID. */ + private UUID qryId; + + /** + * @param isQuery Query flag. + * @param qryId Query ID. + * @param updCnt Update count. + */ + public JdbcStatementResultInfo(boolean isQuery, UUID qryId, long updCnt) { + this.isQuery = isQuery; + this.updCnt = updCnt; + this.qryId = qryId; + } + + /** + * @return Query flag. + */ + public boolean isQuery() { + return isQuery; + } + + /** + * @return Query ID. + */ + public UUID queryId() { + return qryId; + } + + /** + * @return Update count. + */ + public long updateCount() { + return updCnt; + } + + /** {@inheritDoc} */ + @Override public String toString() { + return S.toString(JdbcStatementResultInfo.class, this); + } +}