This is an automated email from the ASF dual-hosted git repository. amashenkov pushed a commit to branch ignite-22303 in repository https://gitbox.apache.org/repos/asf/ignite-3.git
commit 3a86330bac8197d8ee46f0ae1fa86eb986c2fb91 Author: amashenkov <[email protected]> AuthorDate: Mon Jul 1 16:28:45 2024 +0300 Add test --- .../internal/sql/engine/SqlQueryProcessor.java | 1 + .../sql/engine/exec/ExecutionServiceImpl.java | 2 + .../internal/sql/engine/exec/QueryRetryTest.java | 82 ++++++++++++++++++++++ .../sql/engine/framework/ImplicitTxContext.java | 4 +- .../sql/engine/framework/NoOpTransaction.java | 13 +++- 5 files changed, 100 insertions(+), 2 deletions(-) diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java index a7b3cae271..b74dd87fde 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/SqlQueryProcessor.java @@ -68,6 +68,7 @@ import org.apache.ignite.internal.sql.SqlCommon; import org.apache.ignite.internal.sql.configuration.distributed.SqlDistributedConfiguration; import org.apache.ignite.internal.sql.configuration.local.SqlLocalConfiguration; import org.apache.ignite.internal.sql.engine.exec.AsyncDataCursor; +import org.apache.ignite.internal.sql.engine.exec.ConcurrentSchemaModificationException; import org.apache.ignite.internal.sql.engine.exec.ExchangeServiceImpl; import org.apache.ignite.internal.sql.engine.exec.ExecutableTableRegistryImpl; import org.apache.ignite.internal.sql.engine.exec.ExecutionDependencyResolverImpl; diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java index c314582b68..82e1f1b34c 100644 --- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java +++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/ExecutionServiceImpl.java @@ -320,6 +320,8 @@ public class ExecutionServiceImpl<RowT> implements ExecutionService, TopologyEve QueryTransactionWrapper txWrapper = txContext.getOrStartImplicit(plan.type() != SqlQueryType.DML); + assert sqlSchemaManager.schema(plan.catalogVersion()) == sqlSchemaManager.schema(txWrapper.unwrap().startTimestamp().longValue()); + AsyncCursor<InternalSqlRow> dataCursor = queryManager.execute(txWrapper.unwrap(), plan); PrefetchCallback prefetchCallback = operationContext.prefetchCallback(); diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryRetryTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryRetryTest.java new file mode 100644 index 0000000000..0bc9c73230 --- /dev/null +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/QueryRetryTest.java @@ -0,0 +1,82 @@ +/* + * 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.sql.engine.exec; + +import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows; + +import java.util.List; +import org.apache.ignite.internal.hlc.HybridClockImpl; +import org.apache.ignite.internal.sql.engine.framework.DataProvider; +import org.apache.ignite.internal.sql.engine.framework.ImplicitTxContext; +import org.apache.ignite.internal.sql.engine.framework.TestBuilders; +import org.apache.ignite.internal.sql.engine.framework.TestCluster; +import org.apache.ignite.internal.sql.engine.framework.TestNode; +import org.apache.ignite.internal.sql.engine.prepare.QueryPlan; +import org.apache.ignite.internal.testframework.BaseIgniteAbstractTest; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +public class QueryRetryTest extends BaseIgniteAbstractTest { + private TestCluster cluster; + + @BeforeEach + public void init() { + cluster = TestBuilders.cluster() + .nodes("N1") + .dataProvider("N1", "TEST_TBL", TestBuilders.tableScan(DataProvider.fromCollection(List.of()))) + .build(); + + cluster.start(); + } + + @AfterEach + public void tearDown() throws Exception { + cluster.stop(); + } + + @Test + void testQuery() { + TestNode node = cluster.node("N1"); + + node.initSchema("CREATE TABLE test_tbl (ID INT PRIMARY KEY, VAL INT, VAL2 INT)"); + + QueryPlan plan = node.prepare("SELECT * FROM test_tbl"); + + node.initSchema("ALTER TABLE test_tbl DROP COLUMN VAL2"); + ImplicitTxContext.INSTANCE.updateObservableTime(new HybridClockImpl().now()); + + assertThrows(ConcurrentSchemaModificationException.class, () -> node.executePlan(plan), null); + } + + + @Test + void testLookupQuery() throws Exception { + TestNode node = cluster.node("N1"); + + node.initSchema("CREATE TABLE test_tbl (ID INT PRIMARY KEY, VAL INT, VAL2 INT)"); + + QueryPlan plan = node.prepare("SELECT * FROM test_tbl WHERE id = 1"); + + node.initSchema("ALTER TABLE test_tbl DROP COLUMN VAL2"); + ImplicitTxContext.INSTANCE.updateObservableTime(new HybridClockImpl().now()); + + assertThrows(ConcurrentSchemaModificationException.class, () -> node.executePlan(plan).requestNextAsync(10).get(), null); + } + +} \ No newline at end of file diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/ImplicitTxContext.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/ImplicitTxContext.java index b22b24fa03..27bd07d10b 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/ImplicitTxContext.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/ImplicitTxContext.java @@ -48,7 +48,9 @@ public class ImplicitTxContext implements QueryTransactionContext { @Override public QueryTransactionWrapper getOrStartImplicit(boolean readOnly) { - return new QueryTransactionWrapperImpl(new NoOpTransaction("dummy"), true, TX_INFLIGHTS); + HybridTimestamp ts = observableTimeTracker.get(); + + return new QueryTransactionWrapperImpl(new NoOpTransaction("dummy", true, ts), true, TX_INFLIGHTS); } @Override diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/NoOpTransaction.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/NoOpTransaction.java index 4ad153c175..aaf3493e0f 100644 --- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/NoOpTransaction.java +++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/framework/NoOpTransaction.java @@ -37,7 +37,7 @@ public final class NoOpTransaction implements InternalTransaction { private final UUID id = UUID.randomUUID(); - private final HybridTimestamp hybridTimestamp = new HybridTimestamp(1, 1); + private final HybridTimestamp hybridTimestamp; private final IgniteBiTuple<ClusterNode, Long> tuple; @@ -75,8 +75,19 @@ public final class NoOpTransaction implements InternalTransaction { * @param readOnly Read-only or not. */ private NoOpTransaction(String name, boolean readOnly) { + this(name, readOnly, new HybridTimestamp(1, 1)); + } + + /** + * Constructs a transaction. + * + * @param name Name of the node. + * @param readOnly Read-only or not. + */ + NoOpTransaction(String name, boolean readOnly, HybridTimestamp timestamp) { var networkAddress = NetworkAddress.from(new InetSocketAddress("localhost", 1234)); this.tuple = new IgniteBiTuple<>(new ClusterNodeImpl(name, name, networkAddress), 1L); + this.hybridTimestamp = timestamp; this.readOnly = readOnly; }
