You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by mp...@apache.org on 2025/05/14 09:32:33 UTC
(ignite-3) branch main updated: IGNITE-24391 Introduce the new QUORUM_SIZE parameter into CREATE ZONE and ALTER ZONE commands (#5795)
This is an automated email from the ASF dual-hosted git repository.
mpochatkin pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/ignite-3.git
The following commit(s) were added to refs/heads/main by this push:
new 43cb97d50b2 IGNITE-24391 Introduce the new QUORUM_SIZE parameter into CREATE ZONE and ALTER ZONE commands (#5795)
43cb97d50b2 is described below
commit 43cb97d50b24da68a523c074ec266f58b527eed7
Author: Vadim Pakhnushev <86...@users.noreply.github.com>
AuthorDate: Wed May 14 12:32:28 2025 +0300
IGNITE-24391 Introduce the new QUORUM_SIZE parameter into CREATE ZONE and ALTER ZONE commands (#5795)
---
.../systemviews/ZonesSystemViewProvider.java | 1 +
.../commands/AbstractCommandValidationTest.java | 6 +
.../commands/CreateZoneCommandValidationTest.java | 25 ++
.../ignite/internal/table/ItReplicasTest.java | 41 +--
.../engine/systemviews/ItZonesSystemViewTest.java | 61 ++++-
modules/sql-engine/src/main/codegen/config.fmpp | 2 +
.../src/main/codegen/includes/parserImpls.ftl | 6 +
.../prepare/ddl/DdlSqlToCommandConverter.java | 5 +
.../sql/engine/prepare/ddl/ZoneOptionEnum.java | 3 +
.../DistributionZoneSqlToCommandConverterTest.java | 280 +++++++++++----------
.../sql/DistributionZoneSqlDdlParserTest.java | 6 +
11 files changed, 260 insertions(+), 176 deletions(-)
diff --git a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
index 00899cdcd28..7c352d0e030 100644
--- a/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
+++ b/modules/catalog/src/main/java/org/apache/ignite/internal/catalog/systemviews/ZonesSystemViewProvider.java
@@ -67,6 +67,7 @@ public final class ZonesSystemViewProvider implements CatalogSystemViewProvider
.addColumn("REPLICAS", INT32, wrapper -> wrapper.zone.replicas())
.addColumn("CONSISTENCY_MODE", STRING, wrapper -> wrapper.zone.consistencyMode().name())
// End of legacy columns list. New columns must be added below this line.
+ .addColumn("ZONE_QUORUM_SIZE", INT32, wrapper -> wrapper.zone.quorumSize())
.dataProvider(SubscriptionUtils.fromIterable(() -> {
Catalog catalog = catalogSupplier.get();
CatalogZoneDescriptor defaultZone = catalog.defaultZone();
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AbstractCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AbstractCommandValidationTest.java
index eb7dc9b46b2..dd159143e7b 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AbstractCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/AbstractCommandValidationTest.java
@@ -95,6 +95,12 @@ abstract class AbstractCommandValidationTest extends BaseIgniteAbstractTest {
return Stream.of(null, Set.of()).map(Arguments::of);
}
+ /**
+ * Test cases for the create/alter zone parameter validation. The order is: number of replicas, default quorum size, default consensus
+ * group size, minimum quorum size, maximum quorum size.
+ *
+ * @return Stream of arguments for parameterized test.
+ */
static Stream<Arguments> quorumTable() {
return Stream.of(
Arguments.of(null, 1, 1, 1, 1), // default replicas count is 1
diff --git a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateZoneCommandValidationTest.java b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateZoneCommandValidationTest.java
index e434826cdef..545aa17604d 100644
--- a/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateZoneCommandValidationTest.java
+++ b/modules/catalog/src/test/java/org/apache/ignite/internal/catalog/commands/CreateZoneCommandValidationTest.java
@@ -17,12 +17,14 @@
package org.apache.ignite.internal.catalog.commands;
+import static java.lang.Math.round;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_FILTER;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_PARTITION_COUNT;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_REPLICA_COUNT;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.IMMEDIATE_TIMER_VALUE;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.INFINITE_TIMER_VALUE;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.MAX_PARTITION_COUNT;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.defaultQuorumSize;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
@@ -152,6 +154,29 @@ public class CreateZoneCommandValidationTest extends AbstractCommandValidationTe
}
}
+ @Test
+ void extremeQuorumSize() {
+ int replicas = Integer.MAX_VALUE; // REPLICAS = ALL
+ int maxQuorumSize = (int) (round(replicas / 2.0));
+ int defaultQuorumSize = defaultQuorumSize(replicas);
+ int defaultConsensusGroupSize = defaultQuorumSize * 2 - 1;
+
+ String errorMessageFragmentMaxQuorum = "Specified quorum size doesn't fit into the specified replicas count";
+
+ assertThrows(
+ CatalogValidationException.class,
+ () -> getZoneDescriptor(createZoneBuilder().replicas(replicas).quorumSize(maxQuorumSize + 1)),
+ errorMessageFragmentMaxQuorum
+ );
+
+ CatalogZoneDescriptor zoneDescriptor = getZoneDescriptor(createZoneBuilder().replicas(replicas));
+ assertThat(zoneDescriptor.quorumSize(), is(defaultQuorumSize));
+ assertThat(zoneDescriptor.consensusGroupSize(), is(defaultConsensusGroupSize));
+
+ zoneDescriptor = getZoneDescriptor(createZoneBuilder().replicas(replicas).quorumSize(maxQuorumSize - 1));
+ assertThat(zoneDescriptor.quorumSize(), is(maxQuorumSize - 1));
+ }
+
@Test
void zoneAutoAdjust() {
assertThrows(
diff --git a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItReplicasTest.java b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItReplicasTest.java
index b9d8ddfa7de..11ac2e86ebd 100644
--- a/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItReplicasTest.java
+++ b/modules/runner/src/integrationTest/java/org/apache/ignite/internal/table/ItReplicasTest.java
@@ -22,7 +22,6 @@ import static java.util.Objects.requireNonNull;
import static java.util.Optional.ofNullable;
import static org.apache.ignite.internal.TestWrappers.unwrapIgniteImpl;
import static org.apache.ignite.internal.TestWrappers.unwrapTableManager;
-import static org.apache.ignite.internal.distributionzones.rebalance.RebalanceUtil.pendingPartAssignmentsQueueKey;
import static org.apache.ignite.internal.lang.IgniteStringFormatter.format;
import static org.apache.ignite.internal.lang.IgniteSystemProperties.enabledColocation;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.bypassingThreadAssertions;
@@ -38,10 +37,7 @@ import org.apache.ignite.Ignite;
import org.apache.ignite.internal.ClusterPerTestIntegrationTest;
import org.apache.ignite.internal.app.IgniteImpl;
import org.apache.ignite.internal.distributionzones.rebalance.RebalanceUtil;
-import org.apache.ignite.internal.lang.ByteArray;
import org.apache.ignite.internal.partitiondistribution.Assignment;
-import org.apache.ignite.internal.partitiondistribution.Assignments;
-import org.apache.ignite.internal.partitiondistribution.AssignmentsQueue;
import org.apache.ignite.internal.raft.PeersAndLearners;
import org.apache.ignite.internal.raft.service.RaftGroupService;
import org.apache.ignite.internal.replicator.ReplicaManager;
@@ -57,27 +53,26 @@ import org.junit.jupiter.api.Test;
class ItReplicasTest extends ClusterPerTestIntegrationTest {
- @Disabled("https://issues.apache.org/jira/browse/IGNITE-24391")
+ @Disabled("https://issues.apache.org/jira/browse/IGNITE-24072")
@Test
void testStartNewNodeAsLearner() {
- cluster.doInSession(0, session -> {
- session.execute(null, "CREATE ZONE TEST_ZONE WITH PARTITIONS=1, REPLICAS=ALL, STORAGE_PROFILES='default'");
- session.execute(null, "CREATE TABLE TEST (id INT PRIMARY KEY, name INT) ZONE TEST_ZONE");
- session.execute(null, "INSERT INTO TEST VALUES (0, 0)");
- });
+ executeSql("CREATE ZONE TEST_ZONE (PARTITIONS 1, REPLICAS ALL, QUORUM SIZE 2) STORAGE PROFILES ['default']");
+ executeSql("CREATE TABLE TEST (id INT PRIMARY KEY, name INT) ZONE TEST_ZONE");
+ executeSql("INSERT INTO TEST VALUES (0, 0)");
await().untilAsserted(() -> {
assertTrue(cluster.runningNodes().map(resolvePartition("TEST")).allMatch(notNull()),
"all nodes should contain table partition replica");
});
Set<Assignment> assignmentsBefore = getStableAssignments(cluster.node(0), "TEST");
- Ignite newNode = cluster.startNode((int) cluster.runningNodes().count());
+ cluster.startNode((int) cluster.runningNodes().count());
- // TODO change learners using alter zone https://issues.apache.org/jira/browse/IGNITE-24391
- Set<Assignment> newAssignment = Set.of(Assignment.forLearner(newNode.name()));
- Set<Assignment> assignmentsAfterExpected = RebalanceUtil.union(assignmentsBefore, newAssignment);
+ // Node 1 is downgraded from peer to learner
+ String learnerName = node(1).name();
- putPendingAssignments(cluster.aliveNode(), "TEST", assignmentsAfterExpected);
+ Set<Assignment> assignmentsAfterExpected = new HashSet<>(assignmentsBefore);
+ assignmentsAfterExpected.removeIf(assignment -> assignment.consistentId().equals(learnerName));
+ assignmentsAfterExpected.add(Assignment.forLearner(learnerName));
await().atMost(Duration.ofSeconds(30)).untilAsserted(() -> {
assertTrue(cluster.runningNodes()
@@ -109,18 +104,6 @@ class ItReplicasTest extends ClusterPerTestIntegrationTest {
.orElse(Set.of());
}
- private static void putPendingAssignments(Ignite node, String tableName, Set<Assignment> assignments) {
- IgniteImpl ignite = unwrapIgniteImpl(node);
-
- TablePartitionId partitionId = new TablePartitionId(requireNonNull(getTableId(node, tableName)), 0);
- ByteArray pendingKey = pendingPartAssignmentsQueueKey(partitionId);
-
- long timestamp = ignite.catalogManager().catalog(ignite.catalogManager().latestCatalogVersion()).time();
- byte[] pendingVal = AssignmentsQueue.toBytes(Assignments.of(assignments, timestamp));
-
- ignite.metaStorageManager().put(pendingKey, pendingVal).join();
- }
-
private static int getTableOrZoneId(Ignite node, String tableName) {
// TODO https://issues.apache.org/jira/browse/IGNITE-22522 tableOrZoneId -> zoneId, remove.
IgniteImpl ignite = unwrapIgniteImpl(node);
@@ -167,8 +150,8 @@ class ItReplicasTest extends ClusterPerTestIntegrationTest {
private static Predicate<RaftGroupService> equalsPeersAndLearners(Set<Assignment> assignments) {
return client -> {
PeersAndLearners expected = PeersAndLearners.fromAssignments(assignments);
- return expected.peers().equals(new HashSet<>(requireNonNull(client.peers())))
- && expected.learners().equals(new HashSet<>(requireNonNull(client.learners())));
+ PeersAndLearners actual = PeersAndLearners.fromPeers(requireNonNull(client.peers()), requireNonNull(client.learners()));
+ return expected.equals(actual);
};
}
diff --git a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/systemviews/ItZonesSystemViewTest.java b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/systemviews/ItZonesSystemViewTest.java
index 1beae275910..ba2512ed9e7 100644
--- a/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/systemviews/ItZonesSystemViewTest.java
+++ b/modules/sql-engine/src/integrationTest/java/org/apache/ignite/internal/sql/engine/systemviews/ItZonesSystemViewTest.java
@@ -24,6 +24,7 @@ import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_F
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_PARTITION_COUNT;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_REPLICA_COUNT;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_VARLEN_LENGTH;
+import static org.apache.ignite.internal.catalog.commands.CatalogUtils.DEFAULT_ZONE_QUORUM_SIZE;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.INFINITE_TIMER_VALUE;
import static org.apache.ignite.internal.catalog.commands.CatalogUtils.defaultZoneDefaultAutoAdjustScaleUpTimeoutSeconds;
import static org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrows;
@@ -54,11 +55,13 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
catalogManager.catalog(catalogManager.activeCatalogVersion(node.clock().nowLong()))
);
- assertQuery("SELECT ZONE_NAME, ZONE_PARTITIONS, ZONE_REPLICAS, DATA_NODES_AUTO_ADJUST_SCALE_UP, DATA_NODES_AUTO_ADJUST_SCALE_DOWN, "
- + "DATA_NODES_FILTER, IS_DEFAULT_ZONE, ZONE_CONSISTENCY_MODE FROM SYSTEM.ZONES").returns(
+ assertQuery("SELECT ZONE_NAME, ZONE_PARTITIONS, ZONE_REPLICAS, ZONE_QUORUM_SIZE, DATA_NODES_AUTO_ADJUST_SCALE_UP,"
+ + " DATA_NODES_AUTO_ADJUST_SCALE_DOWN, DATA_NODES_FILTER, IS_DEFAULT_ZONE, ZONE_CONSISTENCY_MODE FROM SYSTEM.ZONES")
+ .returns(
catalog.defaultZone().name(),
DEFAULT_PARTITION_COUNT,
DEFAULT_REPLICA_COUNT,
+ DEFAULT_ZONE_QUORUM_SIZE,
defaultZoneDefaultAutoAdjustScaleUpTimeoutSeconds(),
INFINITE_TIMER_VALUE,
DEFAULT_FILTER,
@@ -69,11 +72,12 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
@Test
public void systemViewCustomZone() {
- sql(createZoneSql(ZONE_NAME, 1, 2, 3, 4, DEFAULT_FILTER));
+ sql(createZoneSql(ZONE_NAME, 1, 5, 2, 3, 4, DEFAULT_FILTER));
assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -87,11 +91,12 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
@Test
public void systemViewAlterCustomZone() {
- sql(createZoneSql(ZONE_NAME, 1, 2, 3, 4, DEFAULT_FILTER));
+ sql(createZoneSql(ZONE_NAME, 1, 5, 2, 3, 4, DEFAULT_FILTER));
assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -106,6 +111,21 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
ZONE_NAME,
1,
100,
+ 2,
+ 3,
+ 4,
+ DEFAULT_FILTER,
+ false,
+ DEFAULT_CONSISTENCY_MODE.name()
+ ).check();
+
+ sql("ALTER ZONE " + ZONE_NAME + " SET (QUORUM SIZE 20)");
+
+ assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
+ ZONE_NAME,
+ 1,
+ 100,
+ 20,
3,
4,
DEFAULT_FILTER,
@@ -118,11 +138,12 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
@Test
public void systemViewRenameCustomZone() {
- sql(createZoneSql(ZONE_NAME, 1, 2, 3, 4, DEFAULT_FILTER));
+ sql(createZoneSql(ZONE_NAME, 1, 5, 2, 3, 4, DEFAULT_FILTER));
assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -136,6 +157,7 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
assertQuery(selectFromZonesSystemView(ALTER_ZONE_NAME)).returns(
ALTER_ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -153,7 +175,7 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
public void systemViewDropCustomZone() {
assertQuery("SELECT COUNT(*) FROM SYSTEM.ZONES").returns(1L).check();
- sql(createZoneSql(ZONE_NAME, 1, 2, 3, 4, DEFAULT_FILTER));
+ sql(createZoneSql(ZONE_NAME, 1, 5, 2, 3, 4, DEFAULT_FILTER));
assertQuery("SELECT COUNT(*) FROM SYSTEM.ZONES").returns(2L).check();
@@ -170,6 +192,7 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
ZONE_NAME,
1,
2,
+ 2,
3,
4,
DEFAULT_FILTER,
@@ -183,6 +206,7 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
ZONE_NAME,
1,
100,
+ 2,
3,
4,
DEFAULT_FILTER,
@@ -195,11 +219,12 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
@Test
public void systemViewAlterConsistencyMode() {
- sql(createZoneSql(ZONE_NAME, 1, 2, 3, 4, DEFAULT_FILTER));
+ sql(createZoneSql(ZONE_NAME, 1, 5, 2, 3, 4, DEFAULT_FILTER));
assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -216,6 +241,7 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
assertQuery(selectFromZonesSystemView(ZONE_NAME)).returns(
ZONE_NAME,
1,
+ 5,
2,
3,
4,
@@ -247,7 +273,8 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
new MetadataMatcher().name("PARTITIONS").type(ColumnType.INT32).nullable(true),
new MetadataMatcher().name("REPLICAS").type(ColumnType.INT32).nullable(true),
new MetadataMatcher().name("CONSISTENCY_MODE").type(ColumnType.STRING).precision(DEFAULT_VARLEN_LENGTH)
- .nullable(true)
+ .nullable(true),
+ new MetadataMatcher().name("ZONE_QUORUM_SIZE").type(ColumnType.INT32).nullable(true)
)
.check();
}
@@ -265,16 +292,25 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
.check();
}
- private static String createZoneSql(String zoneName, int partitions, int replicas, int scaleUp, int scaleDown, String filter) {
+ private static String createZoneSql(
+ String zoneName,
+ int partitions,
+ int replicas,
+ int quorumSize,
+ int scaleUp,
+ int scaleDown,
+ String filter
+ ) {
String sqlFormat = "CREATE ZONE %s ("
+ "PARTITIONS %d, "
+ "REPLICAS %d, "
+ + "QUORUM SIZE %d, "
+ "AUTO SCALE UP %d, "
+ "AUTO SCALE DOWN %d,"
+ "NODES FILTER '%s') "
+ "STORAGE PROFILES ['%s']";
- return String.format(sqlFormat, zoneName, partitions, replicas, scaleUp, scaleDown, filter, DEFAULT_STORAGE_PROFILE);
+ return String.format(sqlFormat, zoneName, partitions, replicas, quorumSize, scaleUp, scaleDown, filter, DEFAULT_STORAGE_PROFILE);
}
private static String createZoneSql(
@@ -309,8 +345,9 @@ public class ItZonesSystemViewTest extends AbstractSystemViewTest {
}
private static String selectFromZonesSystemView(String zoneName) {
- String sqlFormat = "SELECT ZONE_NAME, PARTITIONS, REPLICAS, DATA_NODES_AUTO_ADJUST_SCALE_UP, DATA_NODES_AUTO_ADJUST_SCALE_DOWN, "
- + "DATA_NODES_FILTER, IS_DEFAULT_ZONE, CONSISTENCY_MODE FROM SYSTEM.ZONES WHERE ZONE_NAME = '%s'";
+ String sqlFormat = "SELECT ZONE_NAME, ZONE_PARTITIONS, ZONE_REPLICAS, ZONE_QUORUM_SIZE, "
+ + "DATA_NODES_AUTO_ADJUST_SCALE_UP, DATA_NODES_AUTO_ADJUST_SCALE_DOWN, DATA_NODES_FILTER, IS_DEFAULT_ZONE, "
+ + "CONSISTENCY_MODE FROM SYSTEM.ZONES WHERE ZONE_NAME = '%s'";
return String.format(sqlFormat, zoneName);
}
diff --git a/modules/sql-engine/src/main/codegen/config.fmpp b/modules/sql-engine/src/main/codegen/config.fmpp
index 42ba9ccb02c..f48c99d46f1 100644
--- a/modules/sql-engine/src/main/codegen/config.fmpp
+++ b/modules/sql-engine/src/main/codegen/config.fmpp
@@ -72,6 +72,7 @@ data: {
"DOWN"
"PARTITIONS"
"REPLICAS"
+ "QUORUM"
"DISTRIBUTION"
"ALGORITHM"
"NODES"
@@ -103,6 +104,7 @@ data: {
"DOWN"
"PARTITIONS"
"REPLICAS"
+ "QUORUM"
"DISTRIBUTION"
"ALGORITHM"
"NODES"
diff --git a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
index 61cf553345a..b89bb20ecb1 100644
--- a/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
+++ b/modules/sql-engine/src/main/codegen/includes/parserImpls.ftl
@@ -658,6 +658,12 @@ void ZoneElement(List<SqlNode> zoneOptions) :
}
)
|
+ <QUORUM> { pos = getPos(); } <SIZE> option = UnsignedIntegerLiteral()
+ {
+ key = new SqlIdentifier(ZoneOptionEnum.QUORUM_SIZE.name(), pos);
+ zoneOptions.add(new IgniteSqlZoneOption(key, option, s.end(this)));
+ }
+ |
<DISTRIBUTION> { pos = getPos(); } <ALGORITHM> option = NonEmptyCharacterStringLiteral()
{
key = new SqlIdentifier(ZoneOptionEnum.DISTRIBUTION_ALGORITHM.name(), pos);
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
index cce60463dce..eb8de7660c4 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DdlSqlToCommandConverter.java
@@ -29,6 +29,7 @@ import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.D
import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.DATA_NODES_FILTER;
import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.DISTRIBUTION_ALGORITHM;
import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.PARTITIONS;
+import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.QUORUM_SIZE;
import static org.apache.ignite.internal.sql.engine.prepare.ddl.ZoneOptionEnum.REPLICAS;
import static org.apache.ignite.internal.sql.engine.util.IgniteMath.convertToByteExact;
import static org.apache.ignite.internal.sql.engine.util.IgniteMath.convertToIntExact;
@@ -174,6 +175,8 @@ public class DdlSqlToCommandConverter {
// CREATE ZONE options.
zoneOptionInfos = new EnumMap<>(Map.of(
PARTITIONS, new DdlOptionInfo<>(Integer.class, this::checkPositiveNumber, CreateZoneCommandBuilder::partitions),
+ // We can't properly validate quorum size since it depends on the replicas number.
+ QUORUM_SIZE, new DdlOptionInfo<>(Integer.class, this::checkPositiveNumber, CreateZoneCommandBuilder::quorumSize),
// TODO https://issues.apache.org/jira/browse/IGNITE-22162 appropriate setter method should be used.
DISTRIBUTION_ALGORITHM, new DdlOptionInfo<>(String.class, null, (builder, params) -> {}),
DATA_NODES_FILTER, new DdlOptionInfo<>(String.class, null, CreateZoneCommandBuilder::filter),
@@ -192,6 +195,8 @@ public class DdlSqlToCommandConverter {
// ALTER ZONE options.
alterZoneOptionInfos = new EnumMap<>(Map.of(
PARTITIONS, new DdlOptionInfo<>(Integer.class, this::checkPositiveNumber, AlterZoneCommandBuilder::partitions),
+ // We can't properly validate quorum size since it depends on the replicas number.
+ QUORUM_SIZE, new DdlOptionInfo<>(Integer.class, this::checkPositiveNumber, AlterZoneCommandBuilder::quorumSize),
DATA_NODES_FILTER, new DdlOptionInfo<>(String.class, null, AlterZoneCommandBuilder::filter),
DATA_NODES_AUTO_ADJUST,
new DdlOptionInfo<>(Integer.class, this::checkPositiveNumber, AlterZoneCommandBuilder::dataNodesAutoAdjust),
diff --git a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ZoneOptionEnum.java b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ZoneOptionEnum.java
index 9326ca4105b..d79de9391ae 100644
--- a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ZoneOptionEnum.java
+++ b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/prepare/ddl/ZoneOptionEnum.java
@@ -28,6 +28,9 @@ public enum ZoneOptionEnum {
/** Number of replicas. */
REPLICAS("REPLICAS"),
+ /** Quorum size. */
+ QUORUM_SIZE("QUORUM SIZE"),
+
/** Partition distribution algorithm name. */
DISTRIBUTION_ALGORITHM("DISTRIBUTION ALGORITHM"),
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DistributionZoneSqlToCommandConverterTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DistributionZoneSqlToCommandConverterTest.java
index fde1083b0f3..5fb83f9a700 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DistributionZoneSqlToCommandConverterTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/prepare/ddl/DistributionZoneSqlToCommandConverterTest.java
@@ -34,6 +34,7 @@ import org.apache.calcite.sql.SqlDdl;
import org.apache.calcite.sql.SqlNode;
import org.apache.calcite.sql.parser.SqlParseException;
import org.apache.ignite.internal.catalog.CatalogCommand;
+import org.apache.ignite.internal.catalog.CatalogValidationException;
import org.apache.ignite.internal.catalog.commands.AlterZoneCommand;
import org.apache.ignite.internal.catalog.commands.AlterZoneSetDefaultCommand;
import org.apache.ignite.internal.catalog.commands.DropZoneCommand;
@@ -65,9 +66,11 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
private static final List<ZoneOptionEnum> NUMERIC_OPTIONS = List.of(
ZoneOptionEnum.PARTITIONS,
ZoneOptionEnum.REPLICAS,
+ ZoneOptionEnum.QUORUM_SIZE,
ZoneOptionEnum.DATA_NODES_AUTO_ADJUST,
ZoneOptionEnum.DATA_NODES_AUTO_ADJUST_SCALE_UP,
- ZoneOptionEnum.DATA_NODES_AUTO_ADJUST_SCALE_DOWN);
+ ZoneOptionEnum.DATA_NODES_AUTO_ADJUST_SCALE_DOWN
+ );
private static final List<ZoneOptionEnum> STRING_OPTIONS = List.of(
ZoneOptionEnum.DISTRIBUTION_ALGORITHM,
@@ -83,14 +86,10 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "with syntax = {0}")
@ValueSource(booleans = {true, false})
public void testCreateZone(boolean withPresent) throws SqlParseException {
- SqlNode node = parse(withPresent
+ CatalogCommand cmd = convert(withPresent
? "CREATE ZONE test WITH STORAGE_PROFILES='" + DEFAULT_STORAGE_PROFILE + "'"
: "CREATE ZONE test STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "']");
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
-
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
assertThat(desc.name(), equalTo("TEST"));
@@ -107,11 +106,7 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
: "CREATE ZONE test (CONSISTENCY MODE '" + ConsistencyMode.STRONG_CONSISTENCY.name() + "') "
+ "STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "'] ";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert(sql);
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
@@ -127,11 +122,7 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
: "CREATE ZONE test (CONSISTENCY MODE '" + ConsistencyMode.HIGH_AVAILABILITY + "') "
+ "STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "'] ";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert(sql);
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
@@ -140,20 +131,16 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "with syntax = {0}")
@ValueSource(booleans = {true, false})
- public void testCreateZoneWithConsistencyModeInvalid(boolean withPresent) throws SqlParseException {
+ public void testCreateZoneWithConsistencyModeInvalid(boolean withPresent) {
String sql = withPresent
? "CREATE ZONE test WITH STORAGE_PROFILES='" + DEFAULT_STORAGE_PROFILE + "',"
+ " CONSISTENCY_MODE='MY_CUSTOM_MODE'"
: "CREATE ZONE test (CONSISTENCY MODE 'MY_CUSTOM_MODE') "
+ "STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "'] ";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
assertThrows(
SqlException.class,
- () -> converter.convert((SqlDdl) node, createContext()),
+ () -> convert(sql),
"Failed to parse consistency mode: MY_CUSTOM_MODE. Valid values are: [STRONG_CONSISTENCY, HIGH_AVAILABILITY]"
);
}
@@ -177,28 +164,27 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
String sql = withPresent
? "CREATE ZONE test with "
+ "partitions=2, "
- + "replicas=3, "
+ + "replicas=5, "
+ + "quorum_size=2, " // non-default value
+ "distribution_algorithm='rendezvous', "
+ "data_nodes_filter='$[?(@.region == \"US\")]', "
+ "data_nodes_auto_adjust=300, "
+ "storage_profiles='lru_rocks , segmented_aipersist ' "
: "CREATE ZONE test "
+ "(partitions 2, "
- + "replicas 3, "
+ + "replicas 5, "
+ + "quorum size 2, " // non-default value
+ "distribution algorithm 'rendezvous', "
+ "nodes filter '$[?(@.region == \"US\")]', "
+ "auto adjust 300) "
+ "storage profiles ['lru_rocks', 'segmented_aipersist '] ";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert(sql);
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
assertThat(desc.partitions(), equalTo(2));
- assertThat(desc.replicas(), equalTo(3));
+ assertThat(desc.replicas(), equalTo(5));
+ assertThat(desc.quorumSize(), equalTo(2));
// TODO https://issues.apache.org/jira/browse/IGNITE-22162
// assertThat(desc.distributionAlgorithm(), equalTo("rendezvous"));
assertThat(desc.filter(), equalTo("$[?(@.region == \"US\")]"));
@@ -222,11 +208,7 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
+ "auto scale down 200) "
+ "storage profiles ['lru_rocks']";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert(sql);
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
assertThat(desc.dataNodesAutoAdjustScaleUp(), equalTo(100));
@@ -262,20 +244,82 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
? "CREATE ZONE test WITH STORAGE_PROFILES='" + DEFAULT_STORAGE_PROFILE + "', REPLICAS=ALL"
: "CREATE ZONE test (REPLICAS ALL) STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "']";
- SqlNode node = parse(sql);
+ CatalogCommand cmd = convert(sql);
- assertThat(node, instanceOf(SqlDdl.class));
+ CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ assertThat(desc.replicas(), equalTo(DistributionAlgorithm.ALL_REPLICAS));
+ }
+
+ private static List<Arguments> defaultQuorum() {
+ return List.of(
+ Arguments.of(1, 1),
+ Arguments.of(2, 2),
+ Arguments.of(5, 3),
+ Arguments.of(10, 3)
+ );
+ }
+
+ @ParameterizedTest(name = "replicas = {0}, expectedQuorum = {1}")
+ @MethodSource("defaultQuorum")
+ public void testCreateZoneWithQuorumDefault(int replicas, int expectedQuorum) throws SqlParseException {
+ String sql = "CREATE ZONE test WITH REPLICAS=" + replicas + ", STORAGE_PROFILES='" + DEFAULT_STORAGE_PROFILE + "'";
+
+ CatalogCommand cmd = convert(sql);
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
- assertThat(desc.replicas(), equalTo(DistributionAlgorithm.ALL_REPLICAS));
+ assertThat(desc.quorumSize(), equalTo(expectedQuorum));
+ }
+
+ private static List<Arguments> correctQuorumSize() {
+ return List.of(
+ Arguments.of(1, 1),
+ Arguments.of(2, 2),
+ Arguments.of(5, 2),
+ Arguments.of(10, 5)
+ );
+ }
+
+ @ParameterizedTest(name = "(replicas = {0}, quorum size = {1})")
+ @MethodSource("correctQuorumSize")
+ public void testCreateZoneWithQuorum(int replicas, int quorum) throws SqlParseException {
+ String sql = "CREATE ZONE test (REPLICAS " + replicas + ", QUORUM SIZE " + quorum
+ + ") STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "']";
+
+ CatalogCommand cmd = convert(sql);
+
+ CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, NewZoneEntry.class).descriptor();
+
+ assertThat(desc.quorumSize(), equalTo(quorum));
+ }
+
+ private static List<Arguments> invalidQuorumSize() {
+ return List.of(
+ Arguments.of(1, 2),
+ Arguments.of(2, 3),
+ Arguments.of(5, 4),
+ Arguments.of(10, 1)
+ );
+ }
+
+ @ParameterizedTest(name = "(replicas {0}, quorum size {1})")
+ @MethodSource("invalidQuorumSize")
+ public void testCreateZoneWithInvalidQuorum(int replicas, int quorum) {
+ String sql = "CREATE ZONE test (REPLICAS " + replicas + ", QUORUM SIZE " + quorum
+ + ") STORAGE PROFILES ['" + DEFAULT_STORAGE_PROFILE + "']";
+
+ // We can't properly validate quorum size in the parser, so the exception is thrown from the catalog command validation instead.
+ assertThrows(
+ CatalogValidationException.class,
+ () -> convert(sql),
+ "Specified quorum size doesn't fit into the specified replicas count"
+ );
}
@ParameterizedTest(name = "with syntax = {0}")
@ValueSource(booleans = {true, false})
- public void testCreateZoneWithoutStorageProfileOptionShouldThrowError(boolean withPresent) throws SqlParseException {
+ public void testCreateZoneWithoutStorageProfileOptionShouldThrowError(boolean withPresent) {
assertThrowsWithPos("CREATE ZONE test", "<EOF>", 16);
if (withPresent) {
@@ -287,23 +331,17 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "with syntax = {0}")
@ValueSource(booleans = {true, false})
- public void testCreateZoneWithDuplicateOptions(boolean withPresent) throws SqlParseException {
+ public void testCreateZoneWithDuplicateOptions(boolean withPresent) {
String sql = withPresent
? "CREATE ZONE test with partitions=2, replicas=0, PARTITIONS=1, STORAGE_PROFILES='profile'"
: "CREATE ZONE test (partitions 2, replicas 0, PARTITIONS 1) STORAGE PROFILES ['profile']";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- expectDuplicateOptionError((SqlDdl) node, "PARTITIONS");
+ expectDuplicateOptionError(sql, "PARTITIONS");
}
@Test
public void testRenameZoneCommand() throws SqlParseException {
- SqlNode node = parse("ALTER ZONE test RENAME TO test2");
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert("ALTER ZONE test RENAME TO test2");
assertThat(cmd, instanceOf(RenameZoneCommand.class));
@@ -317,9 +355,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@Test
public void testRenameZoneIfExistCommand() throws SqlParseException {
- SqlNode node = parse("ALTER ZONE IF EXISTS test RENAME TO test2");
+ CatalogCommand cmd = convert("ALTER ZONE IF EXISTS test RENAME TO test2");
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(RenameZoneCommand.class));
RenameZoneCommand zoneCmd = (RenameZoneCommand) cmd;
@@ -335,9 +372,11 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "obsolete = {0}")
@ValueSource(booleans = {true, false})
public void testAlterZoneCommand(boolean obsolete) throws SqlParseException {
- SqlNode node = parse(obsolete ? "ALTER ZONE test SET replicas=3" : "ALTER ZONE test SET (replicas 3)");
+ CatalogCommand cmd = convert(obsolete
+ ? "ALTER ZONE test SET replicas=5, quorum_size=3"
+ : "ALTER ZONE test SET (replicas 5, quorum size 3)"
+ );
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneCommand.class));
CatalogZoneDescriptor zoneMock = mock(CatalogZoneDescriptor.class);
@@ -350,16 +389,15 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
CatalogZoneDescriptor desc = invokeAndGetFirstEntry(cmd, AlterZoneEntry.class).descriptor();
assertThat(desc.name(), equalTo("TEST"));
- assertThat(desc.replicas(), is(3));
+ assertThat(desc.replicas(), is(5));
+ assertThat(desc.quorumSize(), is(3));
assertThat(((AlterZoneCommand) cmd).ifExists(), is(false));
}
@ParameterizedTest(name = "obsolete = {0}")
@ValueSource(booleans = {true, false})
public void testAlterZoneIfExistsCommand(boolean obsolete) throws SqlParseException {
- SqlNode node = parse(obsolete ? "ALTER ZONE IF EXISTS test SET replicas=3" : "ALTER ZONE IF EXISTS test SET (replicas 3)");
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert(obsolete ? "ALTER ZONE IF EXISTS test SET replicas=3" : "ALTER ZONE IF EXISTS test SET (replicas 3)");
assertThat(cmd, instanceOf(AlterZoneCommand.class));
assertThat(((AlterZoneCommand) cmd).ifExists(), is(true));
@@ -372,17 +410,18 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
{
String sql = obsolete
? "ALTER ZONE test SET "
- + "replicas=3, "
+ + "replicas=5, "
+ + "quorum_size=3, "
+ "data_nodes_filter='$[?(@.region == \"US\")]', "
+ "data_nodes_auto_adjust=300"
: "ALTER ZONE test SET "
- + "(replicas 3, "
+ + "(replicas 5, "
+ + "quorum size 3, "
+ "nodes filter '$[?(@.region == \"US\")]', "
+ "auto adjust 300)";
- SqlNode node = parse(sql);
+ CatalogCommand cmd = convert(sql);
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneCommand.class));
CatalogZoneDescriptor zoneMock = mock(CatalogZoneDescriptor.class);
@@ -395,7 +434,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
assertThat(desc.name(), equalTo("TEST"));
- assertThat(desc.replicas(), equalTo(3));
+ assertThat(desc.replicas(), equalTo(5));
+ assertThat(desc.quorumSize(), equalTo(3));
assertThat(desc.filter(), equalTo("$[?(@.region == \"US\")]"));
assertThat(desc.dataNodesAutoAdjust(), equalTo(300));
}
@@ -410,9 +450,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
+ "(auto scale up 100, "
+ "auto scale down 200)";
- SqlNode node = parse(sql);
+ CatalogCommand cmd = convert(sql);
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneCommand.class));
CatalogZoneDescriptor zoneMock = mock(CatalogZoneDescriptor.class);
@@ -433,9 +472,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "obsolete = {0}")
@ValueSource(booleans = {true, false})
public void testAlterZoneReplicasAll(boolean obsolete) throws SqlParseException {
- SqlNode node = parse(obsolete ? "ALTER ZONE test SET replicas=ALL" : "ALTER ZONE test SET (replicas ALL)");
+ CatalogCommand cmd = convert(obsolete ? "ALTER ZONE test SET replicas=ALL" : "ALTER ZONE test SET (replicas ALL)");
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneCommand.class));
CatalogZoneDescriptor zoneMock = mock(CatalogZoneDescriptor.class);
@@ -451,9 +489,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@Test
public void testAlterZoneSetDefault() throws SqlParseException {
- SqlNode node = parse("ALTER ZONE test SET DEFAULT");
+ CatalogCommand cmd = convert("ALTER ZONE test SET DEFAULT");
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneSetDefaultCommand.class));
CatalogZoneDescriptor zoneMock = mock(CatalogZoneDescriptor.class);
@@ -468,9 +505,8 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@Test
public void testAlterZoneSetDefaultIfExists() throws SqlParseException {
- SqlNode node = parse("ALTER ZONE IF EXISTS test SET DEFAULT");
+ CatalogCommand cmd = convert("ALTER ZONE IF EXISTS test SET DEFAULT");
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
assertThat(cmd, instanceOf(AlterZoneSetDefaultCommand.class));
assertThat(((AlterZoneSetDefaultCommand) cmd).ifExists(), is(true));
@@ -478,7 +514,7 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "obsolete = {0}, option = {1}")
@MethodSource("numericOptions")
- public void testAlterZoneCommandWithInvalidOptions(boolean obsolete, ZoneOptionEnum option) throws SqlParseException {
+ public void testAlterZoneCommandWithInvalidOptions(boolean obsolete, ZoneOptionEnum option) {
String sql = obsolete
? "ALTER ZONE test SET replicas=2, data_nodes_auto_adjust=-100"
: "ALTER ZONE test SET ({} -100)";
@@ -499,20 +535,13 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
String sql = obsolete
? "ALTER ZONE test SET replicas=2, data_nodes_auto_adjust=300, DATA_NODES_AUTO_ADJUST=400"
: "ALTER ZONE test SET (replicas 2, auto adjust 300, AUTO ADJUST 400)";
- SqlNode node = parse(sql);
-
- assertThat(node, instanceOf(SqlDdl.class));
- expectDuplicateOptionError((SqlDdl) node, ZoneOptionEnum.DATA_NODES_AUTO_ADJUST.sqlName);
+ expectDuplicateOptionError(sql, ZoneOptionEnum.DATA_NODES_AUTO_ADJUST.sqlName);
}
@Test
public void testDropZone() throws SqlParseException {
- SqlNode node = parse("DROP ZONE test");
-
- assertThat(node, instanceOf(SqlDdl.class));
-
- CatalogCommand cmd = converter.convert((SqlDdl) node, createContext());
+ CatalogCommand cmd = convert("DROP ZONE test");
assertThat(cmd, instanceOf(DropZoneCommand.class));
@@ -526,31 +555,28 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "with syntax = {0}, option = {1}")
@MethodSource("numericOptions")
- public void createZoneWithInvalidNumericOptionValue(boolean withPresent, ZoneOptionEnum option) throws Exception {
+ public void createZoneWithInvalidNumericOptionValue(boolean withPresent, ZoneOptionEnum option) {
String sql = withPresent ? "create zone test_zone with {}={}, storage_profiles='p'" : "create zone test_zone ({} {})";
if (withPresent) {
- SqlDdl node = (SqlDdl) parse(format(sql, option, "'bar'"));
- expectInvalidOptionType(node, option.name());
+ expectInvalidOptionType(format(sql, option, "'bar'"), option.name());
} else {
String sqlName = option.sqlName;
String prefix = "create zone test_zone (";
- assertThrowsWithPos(format(sql, sqlName, "'bar'"), "\\'bar\\'", prefix.length() + sqlName.length() + 1 /* start pos*/
- + 1 /* first symbol after bracket*/);
+ int errorPos = prefix.length() + sqlName.length() + 1 /* start pos*/ + 1 /* first symbol after bracket*/;
- assertThrowsWithPos(format(sql, sqlName, "-1"), "-", prefix.length() + sqlName.length() + 1 /* start pos*/
- + 1 /* first symbol after bracket*/);
+ assertThrowsWithPos(format(sql, sqlName, "'bar'"), "\\'bar\\'", errorPos);
+ assertThrowsWithPos(format(sql, sqlName, "-1"), "-", errorPos);
}
}
@ParameterizedTest(name = "with syntax = {0}")
@ValueSource(booleans = {true, false})
- public void createZoneWithUnexpectedOption(boolean withPresent) throws SqlParseException {
+ public void createZoneWithUnexpectedOption(boolean withPresent) {
String sql = withPresent ? "create zone test_zone with ABC=1, storage_profiles='p'" : "create zone test_zone (ABC 1)";
if (withPresent) {
- SqlDdl node = (SqlDdl) parse(sql);
- expectUnexpectedOption(node, "ABC");
+ expectUnexpectedOption(sql, "ABC");
} else {
assertThrowsWithPos(sql, "ABC", 24);
}
@@ -558,10 +584,10 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest(name = "with syntax = {0}, option = {1}")
@MethodSource("stringOptions")
- public void createZoneWithInvalidStringOptionValue(boolean withPresent, ZoneOptionEnum option) throws Exception {
+ public void createZoneWithInvalidStringOptionValue(boolean withPresent, ZoneOptionEnum option) {
if (withPresent) {
- SqlDdl node = (SqlDdl) parse(format("create zone test_zone with {}={}, storage_profiles='p'", option.name(), "1"));
- expectInvalidOptionType(node, option.name());
+ String sql = format("create zone test_zone with {}={}, storage_profiles='p'", option.name(), "1");
+ expectInvalidOptionType(sql, option.name());
} else {
String sql = "create zone test_zone ({} {})";
@@ -585,20 +611,22 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
@ParameterizedTest
@MethodSource("pureNumericOptions")
- public void alterZoneWithInvalidNumericOptionValue(ZoneOptionEnum optionParam) throws Exception {
- SqlDdl node = (SqlDdl) parse(format("alter zone test_zone set {}={}", optionParam.name(), "'bar'"));
- expectInvalidOptionType(node, optionParam.name());
+ public void alterZoneWithInvalidNumericOptionValue(ZoneOptionEnum optionParam) {
+ String sql = format("alter zone test_zone set {}={}", optionParam.name(), "'bar'");
+ expectInvalidOptionType(sql, optionParam.name());
}
@Test
- public void alterZoneWithUnexpectedOption() throws SqlParseException {
- SqlDdl node = (SqlDdl) parse("alter zone test_zone set ABC=1");
- expectUnexpectedOption(node, "ABC");
+ public void alterZoneWithUnexpectedOption() {
+ expectUnexpectedOption("alter zone test_zone set ABC=1", "ABC");
}
- private void convert(String query) throws SqlParseException {
- SqlDdl node = (SqlDdl) parse(query);
- converter.convert(node, createContext());
+ private CatalogCommand convert(String query) throws SqlParseException {
+ SqlNode node = parse(query);
+
+ assertThat(node, instanceOf(SqlDdl.class));
+
+ return converter.convert((SqlDdl) node, createContext());
}
private void assertThrowsWithPos(String query, String encountered, int pos) {
@@ -625,50 +653,32 @@ public class DistributionZoneSqlToCommandConverterTest extends AbstractDdlSqlToC
);
}
- private void expectOptionValidationError(String sql, String invalidOption) throws SqlParseException {
- SqlDdl node = (SqlDdl) parse(sql);
- assertThrowsWithCode(
- SqlException.class,
- Sql.STMT_VALIDATION_ERR,
- () -> converter.convert(node, createContext()),
- "Zone option validation failed [option=" + invalidOption
- );
+ private void expectOptionValidationError(String sql, String invalidOption) {
+ expectStatementValidationError(sql, "Zone option validation failed [option=" + invalidOption);
}
- private void emptyProfilesValidationError(String sql) throws SqlParseException {
- SqlDdl node = (SqlDdl) parse(sql);
- assertThrowsWithCode(
- SqlException.class,
- Sql.STMT_VALIDATION_ERR,
- () -> converter.convert(node, createContext()),
- "STORAGE PROFILES can not be empty"
- );
+ private void emptyProfilesValidationError(String sql) {
+ expectStatementValidationError(sql, "STORAGE PROFILES can not be empty");
}
- private void expectInvalidOptionType(SqlDdl node, String invalidOption) {
- assertThrowsWithCode(
- SqlException.class,
- Sql.STMT_VALIDATION_ERR,
- () -> converter.convert(node, createContext()),
- "Invalid zone option type [option=" + invalidOption
- );
+ private void expectInvalidOptionType(String sql, String invalidOption) {
+ expectStatementValidationError(sql, "Invalid zone option type [option=" + invalidOption);
}
- private void expectUnexpectedOption(SqlDdl node, String invalidOption) {
- assertThrowsWithCode(
- SqlException.class,
- Sql.STMT_VALIDATION_ERR,
- () -> converter.convert(node, createContext()),
- "Unexpected zone option [option=" + invalidOption
- );
+ private void expectUnexpectedOption(String sql, String invalidOption) {
+ expectStatementValidationError(sql, "Unexpected zone option [option=" + invalidOption);
+ }
+
+ private void expectDuplicateOptionError(String sql, String option) {
+ expectStatementValidationError(sql, "Duplicate zone option has been specified [option=" + option);
}
- private void expectDuplicateOptionError(SqlDdl node, String option) {
+ private void expectStatementValidationError(String sql, String errorMessageFragment) {
assertThrowsWithCode(
SqlException.class,
Sql.STMT_VALIDATION_ERR,
- () -> converter.convert(node, createContext()),
- "Duplicate zone option has been specified [option=" + option
+ () -> convert(sql),
+ errorMessageFragment
);
}
}
diff --git a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
index 630f9d0903e..f18b08e8823 100644
--- a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
+++ b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/DistributionZoneSqlDdlParserTest.java
@@ -92,6 +92,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
IgniteSqlCreateZone createZone = parseCreateZone(
"create zone test_zone "
+ "(replicas 2, "
+ + "quorum size 2, "
+ "partitions 3, "
+ "nodes filter '(\"US\" || \"EU\") && \"SSD\"', "
+ "distribution algorithm 'test_Distribution', "
@@ -107,6 +108,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
List<SqlNode> optList = createZone.createOptionList().getList();
assertThatZoneOptionPresent(optList, ZoneOptionEnum.REPLICAS, 2);
+ assertThatZoneOptionPresent(optList, ZoneOptionEnum.QUORUM_SIZE, 2);
assertThatZoneOptionPresent(optList, ZoneOptionEnum.PARTITIONS, 3);
assertThatZoneOptionPresent(optList, ZoneOptionEnum.DISTRIBUTION_ALGORITHM, "test_Distribution");
assertThatZoneOptionPresent(optList, ZoneOptionEnum.DATA_NODES_FILTER, "(\"US\" || \"EU\") && \"SSD\"");
@@ -117,6 +119,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
expectUnparsed(createZone, "CREATE ZONE \"TEST_ZONE\" ("
+ "REPLICAS 2, "
+ + "QUORUM SIZE 2, "
+ "PARTITIONS 3, "
+ "NODES FILTER '(\"US\" || \"EU\") && \"SSD\"', "
+ "DISTRIBUTION ALGORITHM 'test_Distribution', "
@@ -332,6 +335,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
IgniteSqlAlterZoneSet alterZoneSet = parseAlterZone(
"alter zone a.test_zone set ("
+ "REPLICAS 2, "
+ + "QUORUM SIZE 2, "
+ "NODES FILTER '(\"US\" || \"EU\") && \"SSD\"', "
+ "AUTO ADJUST 1, "
+ "AUTO SCALE UP 2, "
@@ -345,6 +349,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
List<SqlNode> optList = alterZoneSet.alterOptionsList().getList();
assertThatZoneOptionPresent(optList, ZoneOptionEnum.REPLICAS, 2);
+ assertThatZoneOptionPresent(optList, ZoneOptionEnum.QUORUM_SIZE, 2);
assertThatZoneOptionPresent(optList, ZoneOptionEnum.DATA_NODES_FILTER, "(\"US\" || \"EU\") && \"SSD\"");
assertThatZoneOptionPresent(optList, ZoneOptionEnum.DATA_NODES_AUTO_ADJUST, 1);
assertThatZoneOptionPresent(optList, ZoneOptionEnum.DATA_NODES_AUTO_ADJUST_SCALE_UP, 2);
@@ -352,6 +357,7 @@ public class DistributionZoneSqlDdlParserTest extends AbstractParserTest {
String expectedStmt = "ALTER ZONE \"A\".\"TEST_ZONE\" SET "
+ "(REPLICAS 2, "
+ + "QUORUM SIZE 2, "
+ "NODES FILTER '(\"US\" || \"EU\") && \"SSD\"', "
+ "AUTO ADJUST 1, "
+ "AUTO SCALE UP 2, "