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

terrymanu pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/shardingsphere.git


The following commit(s) were added to refs/heads/master by this push:
     new 686eb592276 Validate SQL translator and transaction rule types (#39890)
686eb592276 is described below

commit 686eb5922767833012f4287610d05cbf1c2ecb9c
Author: Liang Zhang <[email protected]>
AuthorDate: Fri Sep 18 21:07:03 2026 +0800

    Validate SQL translator and transaction rule types (#39890)
---
 ...an-sess_ca4aa60b-ba89-4cc1-875d-a5f70aa6617e.md | 73 ----------------------
 kernel/sql-translator/api/pom.xml                  |  5 ++
 .../config/SQLTranslatorRuleConfiguration.java     |  2 +
 .../SQLTranslatorRuleConfigurationTest.java}       | 19 +++---
 .../config/TransactionRuleConfiguration.java       |  2 +
 .../config/TransactionRuleConfigurationTest.java   |  6 +-
 6 files changed, 23 insertions(+), 84 deletions(-)

diff --git a/.zcode/plans/plan-sess_ca4aa60b-ba89-4cc1-875d-a5f70aa6617e.md 
b/.zcode/plans/plan-sess_ca4aa60b-ba89-4cc1-875d-a5f70aa6617e.md
deleted file mode 100644
index a81cf341e1b..00000000000
--- a/.zcode/plans/plan-sess_ca4aa60b-ba89-4cc1-875d-a5f70aa6617e.md
+++ /dev/null
@@ -1,73 +0,0 @@
-# Issue #27152 剩余实现计划:Oracle ALTER TABLE EXCHANGE PARTITION + 测试用例补齐
-
-## 目标(完整关闭 issue #27152 的剩余缺口)
-1. Oracle `ALTER TABLE t EXCHANGE PARTITION p WITH TABLE t2 
[(INCLUDING|EXCLUDING) INDEXES] [(WITH|WITHOUT) VALIDATION]` 语法支持 + 语义建模
-2. 三组 Oracle parser 测试用例:alter-table exchange partition、insert dblink、lock 
table
-
-## 非目标
-- 不改 MySQL/Doris/Hive 的 EXCHANGE PARTITION(保持其现状纯语法覆盖)
-- 不为 INCLUDING/EXCLUDING INDEXES、WITH/WITHOUT 
VALIDATION、updateIndexClauses、parallelClause 建模(仅语法解析)
-- 不做 CASCADE 及多级分区高级子句
-- 不做任何远程 GitHub 写操作(issue 回复/关单/PR 由用户执行,最后提供 commit message 与回复草稿)
-- 不改 binder/rewriter/routing 下游(无消费需求)
-
-## Architecture Gate 报告(语义建模触及共享模型)
-- Owner:`parser/sql/statement/core` 的 `AlterTableStatement`(全方言共享)与 
`segment/ddl/partition/` 目录(现有 4 个分区 segment 全在 core,即便仅单方言消费,放 core 对齐先例)
-- 兼容性:纯增量。新增 segment 类 + `AlterTableStatement` 加 
`@Singular("exchangePartitionDefinition") 
Collection<ExchangePartitionDefinitionSegment>` 字段(该类为 Lombok `@Builder` 
私有构造,public builder API 向后兼容)
-- 
复用:`PartitionSegment`、`SimpleTableSegment`、`AlterDefinitionSegment`、`ExpectedPartition`、`PartitionAssert`、`AbstractExpectedSQLSegment`
-- 其余 10 个 `alterTablePartitioning` 分支的 visitor 行为保持不变(仍不产生 segment)
-
-## 语法设计(对齐 Oracle 官方语法与仓库现有分支模式)
-```antlr
-alterTablePartitioning
-    : ...(现有 11 分支)
-    | exchangePartitionTable
-    ;
-
-exchangePartitionTable
-    : EXCHANGE (partitionExtendedName | subpartitionExtendedName) WITH TABLE 
tableName
-      ((INCLUDING | EXCLUDING) INDEXES)? ((WITH | WITHOUT) VALIDATION)? 
(updateIndexClauses parallelClause?)?
-    ;
-```
-所需关键字(EXCHANGE/INCLUDING/EXCLUDING/VALIDATION/WITHOUT)均已在 `OracleKeyword.g4` 
定义且为非保留字;`partitionExtendedName`、`subpartitionExtendedName`、`updateIndexClauses`、`parallelClause`
 规则已存在。生成代码不入库,Maven 构建时自动重新生成。
-
-## 改动文件清单(13 个)
-生产(4):
-1. 
`parser/sql/engine/dialect/oracle/src/main/antlr4/imports/oracle/DDLStatement.g4`
 — 上述语法(~6 行)
-2. 
`parser/sql/statement/core/.../segment/ddl/partition/ExchangePartitionDefinitionSegment.java`
 — 新建(startIndex/stopIndex/partition(可空)/exchangeTable,实现 
AlterDefinitionSegment,~40 行)
-3. 
`parser/sql/statement/core/.../statement/type/ddl/table/AlterTableStatement.java`
 — +1 字段
-4. `parser/sql/engine/dialect/oracle/.../type/OracleDDLStatementVisitor.java` 
— `visitAlterDefinitionClause` 增加对 `alterTablePartitioning` 的访问(仅 exchange 分支产生 
segment);新增 `visitExchangePartitionTable` 与 
`visitPartitionExtendedName`(`PARTITION name` → PartitionSegment;`PARTITION FOR 
(...)` → partition 为 null;SUBPARTITION 形式同样 partition 为 null)
-
-测试(9):
-5. `test/it/parser/src/main/resources/sql/supported/ddl/alter-table.xml` — +3 
用例:basic、`PARTITION FOR (TO_DATE(...))` + INCLUDING INDEXES WITHOUT 
VALIDATION、EXCLUDING INDEXES WITH VALIDATION
-6. `test/it/parser/src/main/resources/case/ddl/alter-table.xml` — +3 
期望(`<table>` + `<exchange-partition>` 子树:partition + exchange-table)
-7. 
`test/it/parser/.../jaxb/segment/impl/definition/ExpectedExchangePartitionDefinition.java`
 — 新建(照 `ExpectedAddPartitionDefinition` 模式:partition + exchange-table 子节点)
-8. `test/it/parser/.../AlterTableStatementTestCase.java` — +`@XmlElement(name 
= "exchange-partition")`
-9. `test/it/parser/.../asserts/.../AlterTableStatementAssert.java` — +断言方法(复用 
PartitionAssert/TableAssert)
-10. `test/it/parser/src/main/resources/sql/supported/dml/insert.xml` — 
+1:`INSERT INTO remote_table@link SELECT * FROM local_table`(issue 原文)
-11. `test/it/parser/src/main/resources/case/dml/insert.xml` — +1 期望(table 
name=remote_table、stop-index 覆盖 `remote_table@link`,照 
`select_with_table_dblink_oracle`/`insert_with_select_subquery` 先例)
-12. `test/it/parser/src/main/resources/sql/supported/lcl/lock.xml` — +1:`LOCK 
TABLE interval_sales PARTITION FOR (TO_DATE('01-JUN-2007','dd-MON-yyyy')) IN 
SHARE MODE`(issue 原文;Oracle `visitLock` 返回空 tables)
-13. `test/it/parser/src/main/resources/case/tcl/lock.xml` — +1 空 `<lock/>` 
期望(照 `lock_instance_for_backup` 先例)
-
-## 实施步骤
-1. 记录 `git status --short` 基线(现有 3 个未跟踪 `__pycache__` 目录保持不动)
-2. 改 g4 语法 → 编译验证重新生成无冲突
-3. 新建 core segment + AlterTableStatement 字段
-4. Oracle visitor 三处改动
-5. test/it/parser 的 JAXB + assert 扩展
-6. 三组测试用例 XML(start/stop-index 按资源文件原文逐一计数)
-7. 分层验证(见下)
-8. Completion Loop:task-delta 审计、spotless/checkstyle、正确性自审(含 start/stop-index 
复核)
-
-## 验证命令(按 token-efficiency 契约用 log-file wrapper,自底向上)
-1. `./mvnw -pl parser/sql/statement/core -DskipTests -Dspotless.skip=true 
install`
-2. `./mvnw -pl parser/sql/engine/dialect/oracle -DskipITs -Dspotless.skip=true 
test`
-3. `./mvnw -pl parser/sql/engine/dialect/oracle -DskipTests install`(供 IT 
取到含新语法的构件;若 IT 仍拉到旧 SNAPSHOT 则改用 `-am` 并记录理由=reactor freshness)
-4. `./mvnw -pl test/it/parser 
-Dtest=org.apache.shardingsphere.test.it.sql.parser.oracle.InternalOracleParserIT
 -Dsurefire.failIfNoSpecifiedTests=false test`
-5. `./mvnw spotless:apply -Pcheck -T1C` → `./mvnw checkstyle:check -Pcheck 
-T1C`
-
-## 规模与风险
-- 预估新增 ~180 行(生产 ~90 / 测试 ~90),远低于 10,000 行任务上限
-- 风险 1:test/it/parser 取 parser SNAPSHOT 的方式(本地仓库 vs reactor)——步骤 3/4 编码时按实际裁剪
-- 风险 2:`PARTITION FOR` 形式 partition 为 null 的断言——期望节点省略 `<partition>` 子节点即可表达
-- 完成后提供 commit message(`Support ALTER TABLE EXCHANGE PARTITION parsing in 
Oracle (#27152)` 方向)与 issue 回复草稿,Git 提交与远程操作由用户执行
\ No newline at end of file
diff --git a/kernel/sql-translator/api/pom.xml 
b/kernel/sql-translator/api/pom.xml
index fa4400829bf..f7c24b23c46 100644
--- a/kernel/sql-translator/api/pom.xml
+++ b/kernel/sql-translator/api/pom.xml
@@ -37,5 +37,10 @@
             <artifactId>shardingsphere-infra-session</artifactId>
             <version>${project.version}</version>
         </dependency>
+        
+        <dependency>
+            <groupId>jakarta.validation</groupId>
+            <artifactId>jakarta.validation-api</artifactId>
+        </dependency>
     </dependencies>
 </project>
diff --git 
a/kernel/sql-translator/api/src/main/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfiguration.java
 
b/kernel/sql-translator/api/src/main/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfiguration.java
index 11bbe0a79b0..2f0b644f297 100644
--- 
a/kernel/sql-translator/api/src/main/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfiguration.java
+++ 
b/kernel/sql-translator/api/src/main/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfiguration.java
@@ -21,6 +21,7 @@ import lombok.Getter;
 import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.infra.config.rule.scope.GlobalRuleConfiguration;
 
+import javax.validation.constraints.Pattern;
 import java.util.Properties;
 
 /**
@@ -30,6 +31,7 @@ import java.util.Properties;
 @Getter
 public final class SQLTranslatorRuleConfiguration implements 
GlobalRuleConfiguration {
     
+    @Pattern(regexp = ".*\\S.*", flags = Pattern.Flag.DOTALL)
     private final String type;
     
     private final Properties props;
diff --git 
a/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
 
b/kernel/sql-translator/api/src/test/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfigurationTest.java
similarity index 71%
copy from 
kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
copy to 
kernel/sql-translator/api/src/test/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfigurationTest.java
index e122a3b313d..cf326020121 100644
--- 
a/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
+++ 
b/kernel/sql-translator/api/src/test/java/org/apache/shardingsphere/sqltranslator/config/SQLTranslatorRuleConfigurationTest.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.transaction.config;
+package org.apache.shardingsphere.sqltranslator.config;
 
 import 
org.apache.shardingsphere.infra.config.rule.validator.RuleConfigurationValidator;
 import 
org.apache.shardingsphere.infra.exception.kernel.metadata.rule.InvalidRuleConfigurationException;
@@ -29,31 +29,30 @@ import java.util.stream.Stream;
 import static org.junit.jupiter.api.Assertions.assertDoesNotThrow;
 import static org.junit.jupiter.api.Assertions.assertThrows;
 
-class TransactionRuleConfigurationTest {
+class SQLTranslatorRuleConfigurationTest {
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("validRuleConfigurationArguments")
-    void assertValidateValidRuleConfiguration(final String name, final 
TransactionRuleConfiguration ruleConfig) {
+    void assertValidateValidRuleConfiguration(final String name, final 
SQLTranslatorRuleConfiguration ruleConfig) {
         assertDoesNotThrow(() -> 
RuleConfigurationValidator.validate(ruleConfig));
     }
     
     private static Stream<Arguments> validRuleConfigurationArguments() {
         return Stream.of(
-                Arguments.of("Null optional values", new 
TransactionRuleConfiguration("LOCAL", null, null)),
-                Arguments.of("Provider type", new 
TransactionRuleConfiguration("XA", "Atomikos", null)),
-                Arguments.of("Properties", new 
TransactionRuleConfiguration("BASE", null, new Properties())));
+                Arguments.of("Null type and properties", new 
SQLTranslatorRuleConfiguration(null, null, true)),
+                Arguments.of("Type and properties", new 
SQLTranslatorRuleConfiguration("NATIVE", new Properties(), false)));
     }
     
     @ParameterizedTest(name = "{0}")
     @MethodSource("invalidRuleConfigurationArguments")
-    void assertValidateInvalidRuleConfiguration(final String name, final 
TransactionRuleConfiguration ruleConfig) {
+    void assertValidateInvalidRuleConfiguration(final String name, final 
SQLTranslatorRuleConfiguration ruleConfig) {
         assertThrows(InvalidRuleConfigurationException.class, () -> 
RuleConfigurationValidator.validate(ruleConfig));
     }
     
     private static Stream<Arguments> invalidRuleConfigurationArguments() {
         return Stream.of(
-                Arguments.of("Null default type", new 
TransactionRuleConfiguration(null, null, null)),
-                Arguments.of("Empty default type", new 
TransactionRuleConfiguration("", null, null)),
-                Arguments.of("Blank default type", new 
TransactionRuleConfiguration(" ", null, null)));
+                Arguments.of("Empty type", new 
SQLTranslatorRuleConfiguration("", null, true)),
+                Arguments.of("Blank type", new 
SQLTranslatorRuleConfiguration(" ", null, true)),
+                Arguments.of("Multiline blank type", new 
SQLTranslatorRuleConfiguration("\n\t", null, true)));
     }
 }
diff --git 
a/kernel/transaction/api/src/main/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfiguration.java
 
b/kernel/transaction/api/src/main/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfiguration.java
index ff2abadf91f..310227b6bce 100644
--- 
a/kernel/transaction/api/src/main/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfiguration.java
+++ 
b/kernel/transaction/api/src/main/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfiguration.java
@@ -23,6 +23,7 @@ import lombok.RequiredArgsConstructor;
 import 
org.apache.shardingsphere.infra.config.rule.scope.GlobalRuleConfiguration;
 
 import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Pattern;
 import java.util.Properties;
 
 /**
@@ -34,6 +35,7 @@ import java.util.Properties;
 public final class TransactionRuleConfiguration implements 
GlobalRuleConfiguration {
     
     @NotBlank
+    @Pattern(regexp = "LOCAL|XA|BASE", flags = Pattern.Flag.CASE_INSENSITIVE)
     private final String defaultType;
     
     private final String providerType;
diff --git 
a/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
 
b/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
index e122a3b313d..19bafd592b1 100644
--- 
a/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
+++ 
b/kernel/transaction/api/src/test/java/org/apache/shardingsphere/transaction/config/TransactionRuleConfigurationTest.java
@@ -40,6 +40,8 @@ class TransactionRuleConfigurationTest {
     private static Stream<Arguments> validRuleConfigurationArguments() {
         return Stream.of(
                 Arguments.of("Null optional values", new 
TransactionRuleConfiguration("LOCAL", null, null)),
+                Arguments.of("Lowercase default type", new 
TransactionRuleConfiguration("local", null, null)),
+                Arguments.of("Mixed case default type", new 
TransactionRuleConfiguration("Base", null, null)),
                 Arguments.of("Provider type", new 
TransactionRuleConfiguration("XA", "Atomikos", null)),
                 Arguments.of("Properties", new 
TransactionRuleConfiguration("BASE", null, new Properties())));
     }
@@ -54,6 +56,8 @@ class TransactionRuleConfigurationTest {
         return Stream.of(
                 Arguments.of("Null default type", new 
TransactionRuleConfiguration(null, null, null)),
                 Arguments.of("Empty default type", new 
TransactionRuleConfiguration("", null, null)),
-                Arguments.of("Blank default type", new 
TransactionRuleConfiguration(" ", null, null)));
+                Arguments.of("Blank default type", new 
TransactionRuleConfiguration(" ", null, null)),
+                Arguments.of("Unsupported default type", new 
TransactionRuleConfiguration("FOO", null, null)),
+                Arguments.of("Padded default type", new 
TransactionRuleConfiguration(" XA ", null, null)));
     }
 }

Reply via email to