This is an automated email from the ASF dual-hosted git repository.

amashenkov 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 1cc2eb0b024 IGNITE-26446 Allow batching for compatible DDL operations 
only (#6835)
1cc2eb0b024 is described below

commit 1cc2eb0b0245c953112cf6f2c2037542c6d75cb8
Author: Andrew V. Mashenkov <[email protected]>
AuthorDate: Mon Nov 3 19:24:47 2025 +0300

    IGNITE-26446 Allow batching for compatible DDL operations only (#6835)
---
 .../sql/engine/exec/fsm/DdlBatchAware.java         | 37 +++++++++
 .../sql/engine/exec/fsm/DdlBatchGroup.java         | 32 ++++++++
 .../sql/engine/exec/fsm/DdlBatchingHelper.java     | 66 +++++++++++++++
 .../sql/engine/exec/fsm/MultiStatementHandler.java |  4 +
 .../sql/engine/sql/IgniteSqlAlterColumn.java       |  2 +
 .../engine/sql/IgniteSqlAlterTableAddColumn.java   |  2 +
 .../engine/sql/IgniteSqlAlterTableDropColumn.java  |  2 +
 .../sql/IgniteSqlAlterTableSetProperties.java      |  2 +
 .../sql/engine/sql/IgniteSqlAlterZoneRenameTo.java |  2 +
 .../sql/engine/sql/IgniteSqlAlterZoneSet.java      |  2 +
 .../engine/sql/IgniteSqlAlterZoneSetDefault.java   |  2 +
 .../sql/engine/sql/IgniteSqlCreateIndex.java       |  3 +
 .../sql/engine/sql/IgniteSqlCreateSchema.java      |  5 +-
 .../sql/engine/sql/IgniteSqlCreateTable.java       |  3 +
 .../sql/engine/sql/IgniteSqlCreateZone.java        |  3 +
 .../sql/engine/sql/IgniteSqlDropIndex.java         |  3 +
 .../sql/engine/sql/IgniteSqlDropSchema.java        |  5 +-
 .../sql/engine/sql/IgniteSqlDropTable.java         |  3 +
 .../internal/sql/engine/sql/IgniteSqlDropZone.java |  3 +
 .../internal/sql/engine/sql/ParsedResult.java      | 15 +++-
 .../internal/sql/engine/sql/ParserServiceImpl.java | 33 ++++++--
 .../internal/sql/engine/exec/DdlBatchingTest.java  | 96 +++++++++++++++++++++-
 .../sql/engine/exec/fsm/DdlBatchingHelperTest.java | 53 ++++++++++++
 .../sql/engine/sql/ParserServiceImplTest.java      | 31 +++++--
 24 files changed, 389 insertions(+), 20 deletions(-)

diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchAware.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchAware.java
new file mode 100644
index 00000000000..31a7cc2da13
--- /dev/null
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchAware.java
@@ -0,0 +1,37 @@
+/*
+ * 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.fsm;
+
+import static java.lang.annotation.ElementType.TYPE;
+import static java.lang.annotation.RetentionPolicy.RUNTIME;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.Target;
+
+/**
+ * Annotation that defines how multi-statement handler executes DDL statement.
+ *
+ * <p>DDL statements of the same {@link DdlBatchGroup} can be executed in 
together within the same batch except {@link DdlBatchGroup#OTHER}.
+ * Statements marked as {@link DdlBatchGroup#OTHER} can be executed only 
separately, this is the default behavior.
+ */
+@Target({TYPE})
+@Retention(RUNTIME)
+public @interface DdlBatchAware {
+    /** Returns DDL batch group. */
+    DdlBatchGroup group() default DdlBatchGroup.OTHER;
+}
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchGroup.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchGroup.java
new file mode 100644
index 00000000000..9dd5b09a555
--- /dev/null
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchGroup.java
@@ -0,0 +1,32 @@
+/*
+ * 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.fsm;
+
+/**
+ * Groups that is used for DDL operations batching.
+ *
+ * @see DdlBatchAware
+ */
+public enum DdlBatchGroup {
+    /** Group for CREATE operations. */
+    CREATE,
+    /** Group for DROP operations. */
+    DROP,
+    /** Group for other DDL operations. */
+    OTHER;
+}
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelper.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelper.java
new file mode 100644
index 00000000000..b78358c0cf8
--- /dev/null
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelper.java
@@ -0,0 +1,66 @@
+/*
+ * 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.fsm;
+
+import org.apache.calcite.sql.SqlNode;
+import org.apache.ignite.internal.sql.engine.sql.ParsedResult;
+import org.jetbrains.annotations.Nullable;
+
+/**
+ *  Provide helper methods for batched DDL commands.
+ */
+public class DdlBatchingHelper {
+    /**
+     * Returns {@code true} if that statement is compatible with this 
statement.
+     * Node: the operation is not commutative.
+     */
+    static boolean isCompatible(ParsedResult thisStatement, ParsedResult 
thatStatement) {
+        @Nullable DdlBatchGroup batchGroup = thisStatement.ddlBatchGroup();
+        @Nullable DdlBatchGroup statementGroup = thatStatement.ddlBatchGroup();
+
+        if (batchGroup == null || statementGroup == null) {
+            // Actually, we should never get here, but If we missed smth, it 
is always safe to fallback to non-batched execution.
+            assert false : "DDL statement should be batch aware.";
+
+            return false;
+        }
+
+        return isCompatible(batchGroup, statementGroup);
+    }
+
+    /**
+     * Returns {@code true} if that group is compatible with this group
+     * Node: the operation is not commutative.
+     */
+    static boolean isCompatible(DdlBatchGroup thisGroup, DdlBatchGroup 
thatGroup) {
+        return (thisGroup != DdlBatchGroup.OTHER // OTHER group doesn't 
support batching.
+                && thisGroup == thatGroup) // Groups matched.
+                || thisGroup == DdlBatchGroup.DROP;
+    }
+
+    /** Returns command kind or {@code null} if command is not {@link 
DdlBatchAware batch aware}. */
+    public static @Nullable DdlBatchGroup extractDdlBatchGroup(SqlNode node) {
+        DdlBatchAware batchAwareAnnotation = 
node.getClass().getDeclaredAnnotation(DdlBatchAware.class);
+
+        return batchAwareAnnotation == null ? null : 
batchAwareAnnotation.group();
+    }
+
+    private DdlBatchingHelper() {
+        // No-op.
+    }
+}
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/MultiStatementHandler.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/MultiStatementHandler.java
index 31f8a2a5925..33558d59bfa 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/MultiStatementHandler.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/exec/fsm/MultiStatementHandler.java
@@ -177,6 +177,10 @@ class MultiStatementHandler {
                         break;
                     }
 
+                    if 
(!DdlBatchingHelper.isCompatible(scriptStatement.parsedResult, 
statement.parsedResult)) {
+                        break;
+                    }
+
                     scriptStatement = statement;
 
                     statements.poll();
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterColumn.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterColumn.java
index 346111e97a0..d727e228622 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterColumn.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterColumn.java
@@ -27,11 +27,13 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Parse tree for {@code ALTER TABLE ... ALTER COLUMN} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterColumn extends IgniteAbstractSqlAlterTable {
 
     /** ALTER TABLE .. ALTER COLUMN operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
index 92b5502b73d..0ed6e3e479b 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableAddColumn.java
@@ -28,11 +28,13 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER TABLE ... ADD COLUMN} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterTableAddColumn extends IgniteAbstractSqlAlterTable {
 
     /** ALTER TABLE ... ADD COLUMN operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
index 293c6432537..1a5da146a51 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableDropColumn.java
@@ -28,11 +28,13 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER TABLE ... DROP COLUMN} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterTableDropColumn extends IgniteAbstractSqlAlterTable 
{
 
     /** ALTER TABLE operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableSetProperties.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableSetProperties.java
index 3a91eb95c97..49ae5321c24 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableSetProperties.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterTableSetProperties.java
@@ -28,11 +28,13 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER TABLE ... SET} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterTableSetProperties extends 
IgniteAbstractSqlAlterTable {
 
     /** ALTER TABLE ... SET operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneRenameTo.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneRenameTo.java
index fa8fb621bc6..a56bb509cf3 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneRenameTo.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneRenameTo.java
@@ -27,11 +27,13 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER ZONE RENAME TO} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterZoneRenameTo extends IgniteAbstractSqlAlterZone {
 
     /** ALTER ZONE RENAME TO operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSet.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSet.java
index 85e11e85c94..8c164fb4020 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSet.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSet.java
@@ -28,11 +28,13 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER ZONE SET} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterZoneSet extends IgniteAbstractSqlAlterZone {
 
     /** ALTER ZONE SET operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSetDefault.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSetDefault.java
index 28990eab659..971ca8cd37b 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSetDefault.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlAlterZoneSetDefault.java
@@ -26,11 +26,13 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code ALTER ZONE SET DEFAULT} statement.
  */
+@DdlBatchAware
 public class IgniteSqlAlterZoneSetDefault extends IgniteAbstractSqlAlterZone {
 
     /** ALTER ZONE SET DEFAULT operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateIndex.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateIndex.java
index b99e01a4147..40db137c60a 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateIndex.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateIndex.java
@@ -29,11 +29,14 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code CREATE INDEX} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.CREATE)
 public class IgniteSqlCreateIndex extends SqlCreate {
 
     /** CREATE INDEX operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateSchema.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateSchema.java
index 1de9c2508a4..02130b02b84 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateSchema.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateSchema.java
@@ -28,11 +28,14 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Parse tree for {@code CREATE SCHEMA} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.CREATE)
 public class IgniteSqlCreateSchema extends SqlCreate {
 
     /** CREATE SCHEMA operator. */
@@ -40,7 +43,7 @@ public class IgniteSqlCreateSchema extends SqlCreate {
 
         /** Constructor. */
         protected Operator(boolean existFlag) {
-            super("CREATE SCHEMA", SqlKind.OTHER_DDL, existFlag);
+            super("CREATE SCHEMA", SqlKind.CREATE_SCHEMA, existFlag);
         }
 
         /** {@inheritDoc} */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateTable.java
index 587ffa6c6a4..8acb2a948d4 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateTable.java
@@ -29,11 +29,14 @@ import org.apache.calcite.sql.SqlNodeList;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Parse tree for {@code CREATE TABLE} statement with Ignite specific features.
  */
+@DdlBatchAware(group = DdlBatchGroup.CREATE)
 public class IgniteSqlCreateTable extends SqlCreate {
 
     /** CREATE TABLE operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateZone.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateZone.java
index 0aae15d5ab0..f09e1267114 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateZone.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlCreateZone.java
@@ -34,11 +34,14 @@ import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.SqlWriter.FrameTypeEnum;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.jetbrains.annotations.Nullable;
 
 /**
  * Parse tree for {@code CREATE ZONE} statement with Ignite specific features.
  */
+@DdlBatchAware(group = DdlBatchGroup.CREATE)
 public class IgniteSqlCreateZone extends SqlCreate {
     private static final String STORAGE_PROFILES_OPTION_NAME = 
"STORAGE_PROFILES";
     private static final Pattern STORAGE_PROFILES_SPLIT_PATTERN = 
Pattern.compile("\\s*,\\s*");
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropIndex.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropIndex.java
index 2bbfe94ff80..b885df42558 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropIndex.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropIndex.java
@@ -28,11 +28,14 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code DROP INDEX} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.DROP)
 public class IgniteSqlDropIndex extends SqlDrop {
 
     /** DROP INDEX operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropSchema.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropSchema.java
index b94dcbf315c..2c7ce35216c 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropSchema.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropSchema.java
@@ -28,11 +28,14 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code DROP SCHEMA} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.DROP)
 public class IgniteSqlDropSchema extends SqlDrop {
 
     /** DROP SCHEMA operator. */
@@ -41,7 +44,7 @@ public class IgniteSqlDropSchema extends SqlDrop {
 
         /** Constructor. */
         protected Operator(boolean existFlag, IgniteSqlDropSchemaBehavior 
dropBehavior) {
-            super("DROP SCHEMA", SqlKind.OTHER_DDL, existFlag);
+            super("DROP SCHEMA", SqlKind.DROP_SCHEMA, existFlag);
 
             this.dropBehavior = dropBehavior;
         }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropTable.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropTable.java
index cfc3f3e9b9e..d266e7750e4 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropTable.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropTable.java
@@ -27,11 +27,14 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code DROP TABLE} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.DROP)
 public class IgniteSqlDropTable extends SqlDrop {
 
     /** DROP TABLE operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropZone.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropZone.java
index a515acaa781..e583cf9191e 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropZone.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/IgniteSqlDropZone.java
@@ -28,11 +28,14 @@ import org.apache.calcite.sql.SqlNode;
 import org.apache.calcite.sql.SqlWriter;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.util.ImmutableNullableList;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchAware;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
 import org.checkerframework.checker.nullness.qual.Nullable;
 
 /**
  * Parse tree for {@code DROP ZONE} statement.
  */
+@DdlBatchAware(group = DdlBatchGroup.DROP)
 public class IgniteSqlDropZone extends SqlDrop {
 
     /** DROP ZONE operator. */
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParsedResult.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParsedResult.java
index 27b3a79192a..cafc62e01ec 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParsedResult.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParsedResult.java
@@ -19,6 +19,8 @@ package org.apache.ignite.internal.sql.engine.sql;
 
 import org.apache.calcite.sql.SqlNode;
 import org.apache.ignite.internal.sql.engine.SqlQueryType;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * Result of the parse.
@@ -43,6 +45,17 @@ public interface ParsedResult {
     /** Returns the count of the dynamic params (specified by question marks 
in the query text) used in the query. */
     int dynamicParamsCount();
 
-    /** Returns the syntax tree of the query according to the grammar rules. */
+    /**
+     * Returns the syntax tree of the query according to the grammar rules for 
planning purposes.
+     *
+     * <p>Note: Each call should return new tree instance.
+     */
     SqlNode parsedTree();
+
+    /**
+     * Returns {@link DdlBatchGroup} for batching purposes or {@code null} if 
not applicable.
+     */
+    default @Nullable DdlBatchGroup ddlBatchGroup() {
+        return null;
+    }
 }
diff --git 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImpl.java
 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImpl.java
index 94b808ac8b1..95130b3cca9 100644
--- 
a/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImpl.java
+++ 
b/modules/sql-engine/src/main/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImpl.java
@@ -29,7 +29,10 @@ import org.apache.calcite.sql.dialect.AnsiSqlDialect;
 import org.apache.calcite.sql.parser.SqlParserPos;
 import org.apache.calcite.sql.pretty.SqlPrettyWriter;
 import org.apache.ignite.internal.sql.engine.SqlQueryType;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchGroup;
+import org.apache.ignite.internal.sql.engine.exec.fsm.DdlBatchingHelper;
 import org.apache.ignite.internal.sql.engine.util.Commons;
+import org.jetbrains.annotations.Nullable;
 
 /**
  * An implementation of {@link ParserService} that, apart of parsing, 
introduces cache of parsed results.
@@ -85,13 +88,15 @@ public class ParserServiceImpl implements ParserService {
                     originalQuery,
                     normalizedQuery,
                     result.dynamicParamsCount(),
-                    () -> {
-                        if (queryType != SqlQueryType.TX_CONTROL && 
!used.compareAndSet(false, true)) {
-                            throw new IllegalStateException("Parsed result of 
script is not reusable.");
-                        }
-
-                        return parsedTree;
-                    }
+                    DdlBatchingHelper.extractDdlBatchGroup(parsedTree),
+                    queryType == SqlQueryType.TX_CONTROL ? () -> parsedTree
+                            : () -> {
+                                if (!used.compareAndSet(false, true)) {
+                                    throw new IllegalStateException("Parsed 
result of script is not reusable.");
+                                }
+
+                                return parsedTree;
+                            }
             ));
         }
 
@@ -141,6 +146,7 @@ public class ParserServiceImpl implements ParserService {
                 originalQuery,
                 normalizedQuery,
                 dynamicParamsCount,
+                DdlBatchingHelper.extractDdlBatchGroup(parsedTree),
                 () -> {
                     // Descendants of SqlNode class are mutable, thus we must 
use every
                     // syntax node only once to avoid problem. But we already 
parsed the
@@ -164,12 +170,14 @@ public class ParserServiceImpl implements ParserService {
         private final String normalizedQuery;
         private final int dynamicParamCount;
         private final Supplier<SqlNode> parsedTreeSupplier;
+        private final @Nullable DdlBatchGroup ddlBatchGroup;
 
         private ParsedResultImpl(
                 SqlQueryType queryType,
                 String originalQuery,
                 String normalizedQuery,
                 int dynamicParamCount,
+                @Nullable DdlBatchGroup ddlBatchGroup,
                 Supplier<SqlNode> parsedTreeSupplier
         ) {
             this.queryType = queryType;
@@ -177,6 +185,11 @@ public class ParserServiceImpl implements ParserService {
             this.normalizedQuery = normalizedQuery;
             this.dynamicParamCount = dynamicParamCount;
             this.parsedTreeSupplier = parsedTreeSupplier;
+            this.ddlBatchGroup = ddlBatchGroup;
+
+            // Here we ensure that DDL batch group is set for DDL queries.
+            // For the case the one missed adding DDL operation to the 
Multi-statement test.
+            assert queryType != SqlQueryType.DDL || ddlBatchGroup != null : 
"DDL query without batch group";
         }
 
         /** {@inheritDoc} */
@@ -203,6 +216,12 @@ public class ParserServiceImpl implements ParserService {
             return dynamicParamCount;
         }
 
+        /** {@inheritDoc} */
+        @Override
+        public @Nullable DdlBatchGroup ddlBatchGroup() {
+            return ddlBatchGroup;
+        }
+
         /** {@inheritDoc} */
         @Override
         public SqlNode parsedTree() {
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/DdlBatchingTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/DdlBatchingTest.java
index a479a86fa06..9c3e2917509 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/DdlBatchingTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/DdlBatchingTest.java
@@ -92,7 +92,7 @@ public class DdlBatchingTest extends BaseIgniteAbstractTest {
     @Test
     void schemaAndTableCreatedInTheSameBatch() {
         AsyncSqlCursor<InternalSqlRow> cursor = gatewayNode.executeQuery(
-                "CREATE SCHEMA my_schema;" 
+                "CREATE SCHEMA my_schema;"
                         + "CREATE TABLE my_schema.t1 (id INT PRIMARY KEY, 
val_1 INT, val_2 INT);"
                         + "CREATE INDEX t1_ind_1 ON my_schema.t1 (val_1);"
         );
@@ -196,13 +196,101 @@ public class DdlBatchingTest extends 
BaseIgniteAbstractTest {
         assertIndexExists("t1_ind_2");
     }
 
+    @Test
+    void batchIsSplitByAlter() {
+        AsyncSqlCursor<InternalSqlRow> cursor = gatewayNode.executeQuery(
+                "CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, val_2 INT);"
+                        + "ALTER TABLE t1 ADD COLUMN val_3 INT;"
+                        + "ALTER TABLE t1 DROP COLUMN val_2;"
+                        + "CREATE TABLE t2 (id INT PRIMARY KEY, val_1 INT, 
val_2 INT);"
+        );
+
+        // CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, val_2 INT)
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // ALTER TABLE t ADD COLUMN val_3 INT;
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // ALTER TABLE t DROP COLUMN val_2 INT;
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // CREATE TABLE t2 (id INT PRIMARY KEY, val_1 INT, val_2 INT)
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(false));
+
+        // ALTER splits the batch
+        assertEquals(4, executeCallCounter.get());
+
+        assertTableExists("t1");
+        assertTableExists("t2");
+    }
+
+    @Test
+    void batchIsSplitByDrop() {
+        AsyncSqlCursor<InternalSqlRow> cursor = gatewayNode.executeQuery(
+                "CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, val_2 INT);"
+                        + "CREATE TABLE t2 (id INT PRIMARY KEY, val_1 INT, 
val_2 INT);"
+                        + "CREATE INDEX t1_ind_1 ON t1 (val_1);"
+                        + "DROP TABLE t1;"
+                        + "DROP TABLE t2;"
+                        + "CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, 
val_2 INT);"
+        );
+
+        // CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, val_2 INT)
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // CREATE TABLE t2 (id INT PRIMARY KEY, val_1 INT, val_2 INT)
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // CREATE INDEX t1_ind_1 ON t1 (val_1)
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // DROP TABLE t1
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // DROP TABLE t2
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(true));
+        assertThat(cursor.nextResult(), willSucceedFast());
+
+        // CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, val_2 INT)
+        cursor = cursor.nextResult().join();
+        assertDdlResult(cursor, true);
+        assertThat(cursor.hasNextResult(), is(false));
+
+        assertEquals(2, executeCallCounter.get());
+        assertTableExists("t1");
+        assertIndexNotExists("t1_ind_1");
+    }
+
     @Test
     void batchIsSplitByOtherStatements() {
         AsyncSqlCursor<InternalSqlRow> cursor = gatewayNode.executeQuery(
                 "INSERT INTO blackhole SELECT x FROM system_range(1, 10);"
                         + "CREATE TABLE t1 (id INT PRIMARY KEY, val_1 INT, 
val_2 INT);"
                         + "CREATE INDEX t1_ind_1 ON t1 (val_1);"
-                        + "CREATE INDEX t1_ind_2 ON t1 (val_2);" 
+                        + "CREATE INDEX t1_ind_2 ON t1 (val_2);"
                         + "INSERT INTO blackhole SELECT x FROM system_range(1, 
10);"
                         + "CREATE TABLE t2 (id INT PRIMARY KEY, val_1 INT, 
val_2 INT);"
                         + "CREATE INDEX t2_ind_1 ON t2 (val_1);"
@@ -367,10 +455,10 @@ public class DdlBatchingTest extends 
BaseIgniteAbstractTest {
     }
 
     /**
-     * This case makes sure that exception thrown is matched the order of 
execution, and not the order 
+     * This case makes sure that exception thrown is matched the order of 
execution, and not the order
      * exceptions appear.
      *
-     * <p>To be more specific, first seen exception relates to absent PK 
definition in 3rd statement, but 
+     * <p>To be more specific, first seen exception relates to absent PK 
definition in 3rd statement, but
      * during execution the exception that should be thrown is the one 
denoting that table with given name
      * already exists (2nd statement).
      */
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelperTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelperTest.java
new file mode 100644
index 00000000000..ae28eb3cd36
--- /dev/null
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/exec/fsm/DdlBatchingHelperTest.java
@@ -0,0 +1,53 @@
+/*
+ * 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.fsm;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import java.util.EnumSet;
+import org.junit.jupiter.api.Test;
+
+/**
+ * DdlBatchingHelper self-test.
+ */
+public class DdlBatchingHelperTest {
+    @Test
+    void testDdlBatchingHelper() {
+        EnumSet<DdlBatchGroup> allExceptOther = 
EnumSet.complementOf(EnumSet.of(DdlBatchGroup.OTHER));
+
+        assert !allExceptOther.isEmpty();
+
+        // Any group is compatible with itself (except OTHER).
+        for (DdlBatchGroup group : allExceptOther) {
+            assertTrue(DdlBatchingHelper.isCompatible(group, group), 
group.toString());
+        }
+
+        // DROP can be followed by any other group (incl. OTHER).
+        for (DdlBatchGroup group : DdlBatchGroup.values()) {
+            assertTrue(DdlBatchingHelper.isCompatible(DdlBatchGroup.DROP, 
group), group.toString());
+        }
+
+        // Other incompatible cases.
+        for (DdlBatchGroup batchGroup : 
EnumSet.complementOf(EnumSet.of(DdlBatchGroup.DROP))) {
+            for (DdlBatchGroup group : 
EnumSet.complementOf(EnumSet.of(batchGroup))) {
+                assertFalse(DdlBatchingHelper.isCompatible(batchGroup, group), 
batchGroup + " vs " + group);
+            }
+        }
+    }
+}
diff --git 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImplTest.java
 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImplTest.java
index d372ea8987a..21997a3159f 100644
--- 
a/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImplTest.java
+++ 
b/modules/sql-engine/src/test/java/org/apache/ignite/internal/sql/engine/sql/ParserServiceImplTest.java
@@ -21,13 +21,18 @@ import static 
org.apache.ignite.internal.sql.engine.util.SqlTestUtils.assertThro
 import static 
org.apache.ignite.internal.testframework.IgniteTestUtils.assertThrowsWithCause;
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.containsString;
+import static org.hamcrest.Matchers.empty;
 import static org.hamcrest.Matchers.equalTo;
 import static org.hamcrest.Matchers.hasSize;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.notNullValue;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
 import static org.junit.jupiter.api.Assertions.assertNotSame;
 
+import java.util.Arrays;
+import java.util.EnumSet;
 import java.util.List;
+import java.util.stream.Collectors;
 import org.apache.calcite.sql.SqlNode;
 import org.apache.ignite.internal.lang.IgniteStringBuilder;
 import org.apache.ignite.internal.sql.engine.SqlQueryType;
@@ -46,7 +51,9 @@ public class ParserServiceImplTest {
         DML("INSERT INTO my_table VALUES (1, 1)", SqlQueryType.DML),
         DDL("CREATE TABLE my_table (id INT PRIMARY KEY, avl INT)", 
SqlQueryType.DDL),
         EXPLAIN_QUERY("EXPLAIN PLAN FOR SELECT * FROM my_table", 
SqlQueryType.EXPLAIN),
-        EXPLAIN_DML("EXPLAIN PLAN FOR INSERT INTO my_table VALUES (1, 1)", 
SqlQueryType.EXPLAIN);
+        EXPLAIN_DML("EXPLAIN PLAN FOR INSERT INTO my_table VALUES (1, 1)", 
SqlQueryType.EXPLAIN),
+        TX_CONTROL("COMMIT", SqlQueryType.TX_CONTROL),
+        KILL("KILL QUERY 'abc'", SqlQueryType.KILL);
 
         private final String text;
         private final SqlQueryType type;
@@ -57,6 +64,14 @@ public class ParserServiceImplTest {
         }
     }
 
+    @Test
+    void ensureAllStatementsAreCovered() {
+        List<SqlQueryType> statementTypes = 
Arrays.stream(Statement.values()).map(s -> s.type).collect(Collectors.toList());
+        EnumSet<SqlQueryType> missedTypes = 
EnumSet.complementOf(EnumSet.copyOf(statementTypes));
+
+        assertThat(missedTypes, empty());
+    }
+
     @ParameterizedTest
     @EnumSource(Statement.class)
     void serviceReturnsResultOfExpectedType(Statement statement) {
@@ -134,11 +149,15 @@ public class ParserServiceImplTest {
 
             SqlNode parsedTree = result.parsedTree();
 
-            assertThrowsWithCause(
-                    result::parsedTree,
-                    IllegalStateException.class,
-                    "Parsed result of script is not reusable"
-            );
+            if (statements.get(i).type == SqlQueryType.TX_CONTROL) {
+                assertNotNull(result.parsedTree());
+            } else {
+                assertThrowsWithCause(
+                        result::parsedTree,
+                        IllegalStateException.class,
+                        "Parsed result of script is not reusable"
+                );
+            }
 
             assertThat(parsedTree, notNullValue());
             assertThat(parsedTree.toString(), 
equalTo(singleStatementResult.parsedTree().toString()));


Reply via email to