You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by zh...@apache.org on 2026/08/04 14:17:06 UTC

(shardingsphere) branch master updated: Refactor MCP SQL analysis to use structured parser metadata (#39334)

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 708c375dcdc Refactor MCP SQL analysis to use structured parser metadata (#39334)
708c375dcdc is described below

commit 708c375dcdc1db7a39e51c0b5f5ff1663bc3c37b
Author: Liang Zhang <zh...@apache.org>
AuthorDate: Tue Aug 4 22:16:58 2026 +0800

    Refactor MCP SQL analysis to use structured parser metadata (#39334)
    
    * Refactor MCP SQL analysis to use structured parser metadata
    
    * Refactor MCP SQL analysis to use structured parser metadata
    
    * Refactor MCP SQL analysis to use structured parser metadata
---
 .../execute/ExplainSQLCandidateValidator.java      |  40 +-
 .../tool/handler/execute/MCPStatementAnalyzer.java |  78 +---
 .../execute/SQLStatementObjectExtractor.java       | 121 ++----
 .../execute/SQLStatementSafetyValidator.java       | 211 +++-------
 .../tool/handler/execute/SQLStatementScanner.java  | 224 +++++-----
 .../tool/handler/execute/SQLStatementToken.java    |  71 ----
 .../handler/execute/SQLStatementTreeWalker.java    | 452 +++++++++++++++++++++
 .../handler/execute/MCPSQLExecutionFacadeTest.java |   4 +-
 .../handler/execute/MCPStatementAnalyzerTest.java  |  34 +-
 .../visitor/statement/MySQLStatementVisitor.java   |  89 +++-
 .../statement/type/MySQLDCLStatementVisitor.java   |  29 +-
 .../statement/type/MySQLDDLStatementVisitor.java   |   1 +
 .../type/OpenGaussDCLStatementVisitor.java         | 213 +++++++++-
 .../visitor/statement/OracleStatementVisitor.java  |  13 +
 .../statement/type/OracleDDLStatementVisitor.java  |  32 +-
 .../statement/type/OracleDMLStatementVisitor.java  |   4 +-
 .../type/PostgreSQLDCLStatementVisitor.java        | 211 +++++++++-
 .../statement/type/PrestoDDLStatementVisitor.java  |   6 +
 .../src/main/antlr4/imports/sqlserver/BaseRule.g4  |   7 +-
 .../statement/SQLServerStatementVisitor.java       |  31 +-
 .../dcl/PrivilegeObjectSegment.java}               |  29 +-
 .../core/statement/type/dcl/GrantStatement.java    |   5 +
 .../core/statement/type/dcl/RevokeStatement.java   |   5 +
 .../parser/src/main/resources/case/dal/explain.xml |   2 +-
 .../src/main/resources/case/ddl/create-table.xml   | 157 +++++++
 .../src/main/resources/case/ddl/create-view.xml    |  10 +-
 .../main/resources/case/dml/select-expression.xml  | 225 +++++++++-
 .../src/main/resources/case/dml/select-into.xml    |   5 +
 .../src/main/resources/case/dml/select-join.xml    | 121 +++++-
 .../parser/src/main/resources/case/dml/select.xml  |  69 +++-
 .../parser/src/main/resources/case/dml/table.xml   |  12 +-
 31 files changed, 1916 insertions(+), 595 deletions(-)

diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExplainSQLCandidateValidator.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExplainSQLCandidateValidator.java
index 145561b45eb..f664daa43f6 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExplainSQLCandidateValidator.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/ExplainSQLCandidateValidator.java
@@ -24,7 +24,6 @@ import org.apache.shardingsphere.mcp.api.exception.MCPInvalidRequestException;
 import org.apache.shardingsphere.mcp.support.database.capability.MCPDatabaseCapability;
 import org.apache.shardingsphere.mcp.support.database.capability.SupportedMCPStatement;
 
-import java.util.List;
 import java.util.Set;
 
 @RequiredArgsConstructor(access = AccessLevel.PACKAGE)
@@ -47,24 +46,18 @@ final class ExplainSQLCandidateValidator {
         String actualExplainSql = scanner.sql();
         ShardingSpherePreconditions.checkState(!scanner.containsExecutableComment(),
                 () -> new MCPInvalidRequestException("Executable comments are not supported by the MCP explain query tool."));
-        List<SQLStatementToken> tokens = scanner.tokens();
-        checkExplainCandidate(scanner, tokens, explainedStatement.getNormalizedSql(), actualExplainSql);
-        return new ClassificationResult(SupportedMCPStatement.EXPLAIN, "EXPLAIN", actualExplainSql, "", explainedStatement.getReferencedObjects(), false);
-    }
-    
-    private void checkExplainCandidate(final SQLStatementScanner scanner, final List<SQLStatementToken> tokens, final String sql, final String explainSql) {
-        ShardingSpherePreconditions.checkState(!tokens.isEmpty() && scanner.isKeyword(tokens.get(0), "EXPLAIN"),
+        ShardingSpherePreconditions.checkState(scanner.startsWithKeyword("EXPLAIN"),
                 () -> new MCPInvalidRequestException("explain_sql must start with EXPLAIN."));
-        String explainPrefix = extractExplainPrefix(explainSql, sql);
-        List<SQLStatementToken> explainPrefixTokens = scanner.scan(explainPrefix).tokens();
-        ShardingSpherePreconditions.checkState(!scanner.containsKeywordSequence(explainPrefixTokens, "EXPLAIN", "PLAN", "FOR"),
+        SQLStatementScanner prefixScanner = scanner.scan(extractExplainPrefix(actualExplainSql, explainedStatement.getNormalizedSql()));
+        ShardingSpherePreconditions.checkState(!prefixScanner.containsKeywordSequence("EXPLAIN", "PLAN", "FOR"),
                 () -> new MCPInvalidRequestException("EXPLAIN PLAN FOR workflows are not supported by the MCP explain query tool."));
-        ShardingSpherePreconditions.checkState(!containsKeyword(scanner, explainPrefixTokens, "ANALYZE", "ANALYSE"),
+        ShardingSpherePreconditions.checkState(!prefixScanner.containsKeyword("ANALYZE", "ANALYSE"),
                 () -> new MCPInvalidRequestException("EXPLAIN ANALYZE is not supported by the MCP explain query tool."));
-        ShardingSpherePreconditions.checkState(!containsKeyword(scanner, explainPrefixTokens, "INTO"),
+        ShardingSpherePreconditions.checkState(!prefixScanner.containsKeyword("INTO"),
                 () -> new MCPInvalidRequestException("EXPLAIN output redirection is not supported by the MCP explain query tool."));
-        ShardingSpherePreconditions.checkState(!containsStatementStartKeyword(explainPrefixTokens),
+        ShardingSpherePreconditions.checkState(!prefixScanner.containsKeywordAfterFirst(STATEMENT_START_KEYWORDS),
                 () -> new MCPInvalidRequestException("explain_sql must not wrap the original sql argument in another statement."));
+        return new ClassificationResult(SupportedMCPStatement.EXPLAIN, "EXPLAIN", actualExplainSql, "", explainedStatement.getReferencedObjects(), false);
     }
     
     private String extractExplainPrefix(final String explainSql, final String sql) {
@@ -72,23 +65,4 @@ final class ExplainSQLCandidateValidator {
                 () -> new MCPInvalidRequestException("explain_sql must include the original sql argument without rewriting it."));
         return explainSql.substring(0, explainSql.length() - sql.length());
     }
-    
-    private boolean containsStatementStartKeyword(final List<SQLStatementToken> tokens) {
-        for (SQLStatementToken each : tokens.subList(1, tokens.size())) {
-            if (!each.quotedIdentifier() && STATEMENT_START_KEYWORDS.contains(each.upperText())) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
-    private boolean containsKeyword(final SQLStatementScanner scanner, final List<SQLStatementToken> tokens, final String... keywords) {
-        for (SQLStatementToken each : tokens) {
-            if (scanner.isKeyword(each, keywords)) {
-                return true;
-            }
-        }
-        return false;
-    }
-    
 }
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzer.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzer.java
index 133cfdb8b25..65b5b6d72fa 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzer.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzer.java
@@ -38,18 +38,16 @@ import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatemen
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.RevokeStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.DDLStatement;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.CreateTableStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DeleteStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.MergeStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.tcl.TCLStatement;
 
 import java.util.Collection;
-import java.util.List;
 import java.util.Locale;
 import java.util.Map;
-import java.util.Optional;
 import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
 
@@ -70,76 +68,34 @@ final class MCPStatementAnalyzer {
         String actualSql = scanner.sql();
         String leadingSql = scanner.leadingSql();
         String upperLeadingSql = leadingSql.toUpperCase(Locale.ENGLISH);
-        SQLStatementSafetyValidator safetyValidator = new SQLStatementSafetyValidator(scanner);
-        safetyValidator.checkLeadingStatement(upperLeadingSql);
+        SQLStatementSafetyValidator safetyValidator = new SQLStatementSafetyValidator();
+        safetyValidator.checkLeadingStatement(upperLeadingSql, scanner.containsExecutableComment());
         if (isSavepointStatement(upperLeadingSql)) {
             return analyzeSavepointStatement(actualSql, leadingSql, upperLeadingSql);
         }
         if (isTransactionControlStatement(upperLeadingSql)) {
-            return new ClassificationResult(SupportedMCPStatement.TRANSACTION_CONTROL, extractTransactionStatementType(upperLeadingSql), actualSql, "", Set.of(), false);
+            return createTCLResult(SupportedMCPStatement.TRANSACTION_CONTROL, extractTransactionStatementType(upperLeadingSql), actualSql, "");
         }
         SQLStatement sqlStatement = parse(actualSql, databaseType);
         safetyValidator.checkParsedStatement(sqlStatement);
+        if (sqlStatement instanceof TCLStatement) {
+            throw new MCPUnsupportedSQLStatementException();
+        }
         boolean ruleDistSQL = isRuleDistSQL(sqlStatement);
         String leadingKeyword = scanner.extractLeadingKeyword();
         SupportedMCPStatement statementClass = resolveStatementClass(sqlStatement, leadingKeyword, ruleDistSQL);
         String statementType = resolveStatementType(sqlStatement, statementClass, leadingKeyword);
-        return new ClassificationResult(statementClass, statementType, actualSql, "", extractReferencedObjects(sqlStatement, databaseType, scanner), ruleDistSQL);
-    }
-    
-    private Collection<SQLStatementObjectName> extractReferencedObjects(final SQLStatement sqlStatement, final String databaseType, final SQLStatementScanner scanner) {
-        SQLStatementObjectExtractor extractor = new SQLStatementObjectExtractor(scanner);
-        Collection<SQLStatementObjectName> result = extractor.extract(sqlStatement);
-        findCreateTableQuery(sqlStatement, scanner).ifPresent(query -> {
-            SQLStatementScanner queryScanner = scanner.scan(query);
-            result.addAll(new SQLStatementObjectExtractor(queryScanner).extract(parse(queryScanner.sql(), databaseType)));
-        });
-        return result;
-    }
-    
-    private Optional<String> findCreateTableQuery(final SQLStatement sqlStatement, final SQLStatementScanner scanner) {
-        if (!(sqlStatement instanceof CreateTableStatement)) {
-            return Optional.empty();
-        }
-        CreateTableStatement createTableStatement = (CreateTableStatement) sqlStatement;
-        if (createTableStatement.getSelectStatement().isPresent()) {
-            return Optional.empty();
-        }
-        List<SQLStatementToken> tokens = scanner.tokens();
-        int tableStopIndex = createTableStatement.getTable().getStopIndex();
-        int parenthesisDepth = 0;
-        for (int index = 0; index < tokens.size(); index++) {
-            SQLStatementToken token = tokens.get(index);
-            if (token.startIndex() <= tableStopIndex) {
-                continue;
-            }
-            if (0 == parenthesisDepth) {
-                int queryStartIndex = scanner.isKeyword(token, "AS") ? index + 1 : index;
-                if (isCreateTableQueryStart(tokens, queryStartIndex, scanner)) {
-                    return Optional.of(scanner.sql().substring(tokens.get(queryStartIndex).startIndex()));
-                }
-            }
-            if ("(".equals(token.text())) {
-                parenthesisDepth++;
-            } else if (")".equals(token.text())) {
-                parenthesisDepth--;
-            }
-        }
-        return Optional.empty();
-    }
-    
-    private boolean isCreateTableQueryStart(final List<SQLStatementToken> tokens, final int startIndex, final SQLStatementScanner scanner) {
-        int queryKeywordIndex = startIndex;
-        while (queryKeywordIndex < tokens.size() && "(".equals(tokens.get(queryKeywordIndex).text())) {
-            queryKeywordIndex++;
-        }
-        return queryKeywordIndex < tokens.size() && scanner.isKeyword(tokens.get(queryKeywordIndex), "SELECT", "WITH", "TABLE", "VALUES");
+        return new ClassificationResult(statementClass, statementType, actualSql, "", new SQLStatementObjectExtractor().extract(sqlStatement), ruleDistSQL);
     }
     
     private ClassificationResult analyzeSavepointStatement(final String actualSql, final String leadingSql, final String upperLeadingSql) {
         String savepointName = extractSavepointName(leadingSql);
         ShardingSpherePreconditions.checkState(!savepointName.isEmpty(), () -> new MCPInvalidRequestException("Savepoint name is required."));
-        return new ClassificationResult(SupportedMCPStatement.SAVEPOINT, extractTransactionStatementType(upperLeadingSql), actualSql, savepointName, Set.of(), false);
+        return createTCLResult(SupportedMCPStatement.SAVEPOINT, extractTransactionStatementType(upperLeadingSql), actualSql, savepointName);
+    }
+    
+    private ClassificationResult createTCLResult(final SupportedMCPStatement statementClass, final String statementType, final String sql, final String savepointName) {
+        return new ClassificationResult(statementClass, statementType, sql, savepointName, Set.of(), false);
     }
     
     private SQLStatement parse(final String sql, final String databaseType) {
@@ -219,16 +175,16 @@ final class MCPStatementAnalyzer {
         return false;
     }
     
-    private boolean isTransactionControlStatement(final String upperSql) {
-        return "BEGIN".equals(upperSql) || "START TRANSACTION".equals(upperSql) || "COMMIT".equals(upperSql) || "ROLLBACK".equals(upperSql);
-    }
-    
     private boolean isSavepointStatement(final String upperSql) {
         return "SAVEPOINT".equals(upperSql) || upperSql.startsWith("SAVEPOINT ")
                 || "ROLLBACK TO".equals(upperSql) || upperSql.startsWith("ROLLBACK TO ")
                 || "RELEASE SAVEPOINT".equals(upperSql) || upperSql.startsWith("RELEASE SAVEPOINT ");
     }
     
+    private boolean isTransactionControlStatement(final String upperSql) {
+        return "BEGIN".equals(upperSql) || "START TRANSACTION".equals(upperSql) || "COMMIT".equals(upperSql) || "ROLLBACK".equals(upperSql);
+    }
+    
     private String extractTransactionStatementType(final String upperSql) {
         if (upperSql.startsWith("START TRANSACTION")) {
             return "START TRANSACTION";
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementObjectExtractor.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementObjectExtractor.java
index 00ac78de634..5ff7ff0539e 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementObjectExtractor.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementObjectExtractor.java
@@ -17,12 +17,11 @@
 
 package org.apache.shardingsphere.mcp.core.tool.handler.execute;
 
-import lombok.AccessLevel;
-import lombok.RequiredArgsConstructor;
-import org.apache.shardingsphere.database.connector.core.metadata.database.enums.QuoteCharacter;
 import org.apache.shardingsphere.mcp.core.protocol.exception.MCPUnsupportedSQLStatementException;
 import org.apache.shardingsphere.sql.parser.statement.core.extractor.TableExtractor;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.index.IndexSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.DeleteMultiTableSegment;
@@ -59,19 +58,14 @@ import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.Iden
 
 import java.util.Collection;
 import java.util.HashSet;
-import java.util.LinkedList;
 import java.util.LinkedHashSet;
-import java.util.List;
 import java.util.Locale;
 import java.util.Optional;
 import java.util.Set;
 
-@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 final class SQLStatementObjectExtractor {
     
-    private static final Set<String> DCL_OBJECT_TYPE_KEYWORDS = Set.of("TABLE", "VIEW", "INDEX", "SEQUENCE", "DATABASE", "SCHEMA", "FUNCTION", "PROCEDURE");
-    
-    private final SQLStatementScanner scanner;
+    private static final Set<String> NAMESPACE_PRIVILEGE_OBJECT_TYPES = Set.of("DATABASE", "SCHEMA");
     
     Collection<SQLStatementObjectName> extract(final SQLStatement sqlStatement) {
         Collection<SQLStatementObjectName> result = new LinkedHashSet<>();
@@ -83,72 +77,39 @@ final class SQLStatementObjectExtractor {
         extractMergeTables(sqlStatement, result);
         extractCommonTableExpressionTables(sqlStatement, result);
         removeCommonTableExpressionAliases(sqlStatement, result);
-        List<SQLStatementToken> tokens = scanner.tokens();
-        extractDCLTarget(sqlStatement, tokens, result);
-        extractQualifiedFunctions(tokens, result);
+        extractDCLTargets(sqlStatement, result);
+        extractQualifiedFunctions(sqlStatement, result);
         return result;
     }
     
-    private void extractDCLTarget(final SQLStatement sqlStatement, final List<SQLStatementToken> tokens, final Collection<SQLStatementObjectName> result) {
-        if (!(sqlStatement instanceof GrantStatement) && !(sqlStatement instanceof RevokeStatement)) {
+    private void extractDCLTargets(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
+        Collection<PrivilegeObjectSegment> privilegeObjects;
+        if (sqlStatement instanceof GrantStatement) {
+            privilegeObjects = ((GrantStatement) sqlStatement).getPrivilegeObjects();
+        } else if (sqlStatement instanceof RevokeStatement) {
+            privilegeObjects = ((RevokeStatement) sqlStatement).getPrivilegeObjects();
+        } else {
             return;
         }
-        for (int index = 0; index < tokens.size(); index++) {
-            if (scanner.isKeyword(tokens.get(index), "ON")) {
-                int objectTypeIndex = index + 1;
-                int objectStartIndex = skipDCLObjectType(tokens, index + 1);
-                addObjectName(tokens, objectStartIndex, findObjectNameEnd(tokens, objectStartIndex), isNamespaceObjectType(tokens, objectTypeIndex), result);
-                return;
+        for (PrivilegeObjectSegment each : privilegeObjects) {
+            if (!each.getIdentifiers().isEmpty()) {
+                result.add(NAMESPACE_PRIVILEGE_OBJECT_TYPES.contains(each.getObjectType())
+                        ? SQLStatementObjectName.fromNamespace(each.getIdentifiers())
+                        : SQLStatementObjectName.from(each.getIdentifiers()));
             }
         }
     }
     
-    private boolean isNamespaceObjectType(final List<SQLStatementToken> tokens, final int index) {
-        return index < tokens.size() && (scanner.isKeyword(tokens.get(index), "DATABASE") || scanner.isKeyword(tokens.get(index), "SCHEMA"));
-    }
-    
-    private int skipDCLObjectType(final List<SQLStatementToken> tokens, final int startIndex) {
-        return startIndex < tokens.size() && DCL_OBJECT_TYPE_KEYWORDS.contains(tokens.get(startIndex).upperText()) ? startIndex + 1 : startIndex;
-    }
-    
-    private void extractQualifiedFunctions(final List<SQLStatementToken> tokens, final Collection<SQLStatementObjectName> result) {
-        int index = 0;
-        while (index < tokens.size()) {
-            int objectNameEnd = findObjectNameEnd(tokens, index);
-            if (objectNameEnd - index > 1 && objectNameEnd < tokens.size() && "(".equals(tokens.get(objectNameEnd).text())) {
-                addObjectName(tokens, index, objectNameEnd, false, result);
-                index = objectNameEnd + 1;
-            } else {
-                index++;
+    private void extractQualifiedFunctions(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
+        new SQLStatementTreeWalker(each -> {
+        }, expression -> {
+            if (expression instanceof FunctionSegment) {
+                FunctionSegment function = (FunctionSegment) expression;
+                if (null != function.getOwner()) {
+                    result.add(SQLStatementObjectName.from(Optional.of(function.getOwner()), new IdentifierValue(function.getFunctionName())));
+                }
             }
-        }
-    }
-    
-    private int findObjectNameEnd(final List<SQLStatementToken> tokens, final int startIndex) {
-        if (startIndex >= tokens.size() || !isObjectNameToken(tokens.get(startIndex))) {
-            return startIndex;
-        }
-        int result = startIndex + 1;
-        while (result + 1 < tokens.size() && ".".equals(tokens.get(result).text()) && isObjectNameToken(tokens.get(result + 1))) {
-            result += 2;
-        }
-        return result;
-    }
-    
-    private boolean isObjectNameToken(final SQLStatementToken token) {
-        return token.identifier() || "*".equals(token.text());
-    }
-    
-    private void addObjectName(final List<SQLStatementToken> tokens, final int startIndex, final int stopIndex, final boolean namespaceTarget,
-                               final Collection<SQLStatementObjectName> result) {
-        if (startIndex >= stopIndex) {
-            return;
-        }
-        List<IdentifierValue> identifiers = new LinkedList<>();
-        for (int index = startIndex; index < stopIndex; index += 2) {
-            identifiers.add(new IdentifierValue(tokens.get(index).text()));
-        }
-        result.add(namespaceTarget ? SQLStatementObjectName.fromNamespace(identifiers) : SQLStatementObjectName.from(identifiers));
+        }).walk(sqlStatement);
     }
     
     private void extractDirectTargets(final SQLStatement sqlStatement, final Collection<SQLStatementObjectName> result) {
@@ -271,6 +232,13 @@ final class SQLStatementObjectExtractor {
                 collectCommonTableExpressionAliases(each.getSubquery().getSelect(), result);
             }
         });
+        if (sqlStatement instanceof CreateTableStatement) {
+            ((CreateTableStatement) sqlStatement).getSelectStatement().ifPresent(each -> collectCommonTableExpressionAliases(each, result));
+        } else if (sqlStatement instanceof CreateViewStatement) {
+            collectCommonTableExpressionAliases(((CreateViewStatement) sqlStatement).getSelect(), result);
+        } else if (sqlStatement instanceof AlterViewStatement) {
+            ((AlterViewStatement) sqlStatement).getSelect().ifPresent(each -> collectCommonTableExpressionAliases(each, result));
+        }
     }
     
     private Optional<WithSegment> findWithSegment(final SQLStatement sqlStatement) {
@@ -321,28 +289,7 @@ final class SQLStatementObjectExtractor {
         if (null == table) {
             return;
         }
-        IdentifierValue identifier = table.getTableName().getIdentifier();
-        if (table.getOwner().isEmpty() && addFlattenedQualifiedTable(identifier, result)) {
-            return;
-        }
-        result.add(SQLStatementObjectName.from(table.getOwner(), identifier));
-    }
-    
-    private boolean addFlattenedQualifiedTable(final IdentifierValue identifier, final Collection<SQLStatementObjectName> result) {
-        if (!identifier.getValue().contains(".")) {
-            return false;
-        }
-        QuoteCharacter quoteCharacter = identifier.getQuoteCharacter();
-        String identifierText = QuoteCharacter.NONE == quoteCharacter || quoteCharacter.isWrapped(identifier.getValue())
-                ? identifier.getValue()
-                : identifier.getValueWithQuoteCharacters();
-        List<SQLStatementToken> tokens = scanner.scan(identifierText).tokens();
-        int objectNameEnd = findObjectNameEnd(tokens, 0);
-        if (3 > objectNameEnd || objectNameEnd != tokens.size()) {
-            return false;
-        }
-        addObjectName(tokens, 0, objectNameEnd, false, result);
-        return true;
+        result.add(SQLStatementObjectName.from(table.getOwner(), table.getTableName().getIdentifier()));
     }
     
     private void addIndex(final IndexSegment index, final Collection<SQLStatementObjectName> result) {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementSafetyValidator.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementSafetyValidator.java
index 9dbbda19d73..91b9aca29e5 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementSafetyValidator.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementSafetyValidator.java
@@ -17,37 +17,40 @@
 
 package org.apache.shardingsphere.mcp.core.tool.handler.execute;
 
-import lombok.AccessLevel;
-import lombok.RequiredArgsConstructor;
 import org.apache.shardingsphere.mcp.core.protocol.exception.MCPBannedSQLStatementException;
 import org.apache.shardingsphere.mcp.core.protocol.exception.MCPLockingReadStatementException;
-import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.complex.CommonTableExpressionSegment;
-import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.CommentSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DeleteStatement;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.MergeStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dal.SetStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.role.AlterRoleStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.role.CreateRoleStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.role.DropRoleStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.AlterUserStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.CreateUserStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.DropUserStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.CallStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement;
 
 import java.util.List;
-import java.util.Optional;
+import java.util.Locale;
 
-@RequiredArgsConstructor(access = AccessLevel.PACKAGE)
 final class SQLStatementSafetyValidator {
     
-    private static final List<String> SIDE_EFFECTING_FUNCTION_NAMES = List.of("NEXTVAL", "SETVAL", "GET_LOCK", "RELEASE_LOCK", "RELEASE_ALL_LOCKS", "PG_ADVISORY_LOCK",
-            "PG_ADVISORY_XACT_LOCK", "PG_TRY_ADVISORY_LOCK", "PG_TRY_ADVISORY_XACT_LOCK", "PG_ADVISORY_UNLOCK", "PG_ADVISORY_UNLOCK_ALL", "SET_CONFIG",
-            "PG_REPLICATION_SLOT_ADVANCE", "PG_LOGICAL_SLOT_GET_CHANGES", "PG_LOGICAL_SLOT_GET_BINARY_CHANGES", "PG_LOGICAL_EMIT_MESSAGE", "PG_SWITCH_WAL", "PG_RELOAD_CONF",
-            "PG_CANCEL_BACKEND", "PG_TERMINATE_BACKEND");
+    private static final List<String> SIDE_EFFECTING_FUNCTION_NAMES = List.of("NEXTVAL", "NEXT VALUE FOR", "SETVAL", "GET_LOCK", "RELEASE_LOCK", "RELEASE_ALL_LOCKS",
+            "PG_ADVISORY_LOCK", "PG_ADVISORY_XACT_LOCK", "PG_TRY_ADVISORY_LOCK", "PG_TRY_ADVISORY_XACT_LOCK", "PG_ADVISORY_UNLOCK", "PG_ADVISORY_UNLOCK_ALL",
+            "SET_CONFIG", "PG_REPLICATION_SLOT_ADVANCE", "PG_LOGICAL_SLOT_GET_CHANGES", "PG_LOGICAL_SLOT_GET_BINARY_CHANGES", "PG_LOGICAL_EMIT_MESSAGE", "PG_SWITCH_WAL",
+            "PG_RELOAD_CONF", "PG_CANCEL_BACKEND", "PG_TERMINATE_BACKEND");
     
-    private static final List<String> METADATA_LOOKUP_FUNCTION_NAMES = List.of("TO_REGCLASS", "TO_REGTYPE", "TO_REGPROC", "TO_REGPROCEDURE", "TO_REGOPER", "TO_REGOPERATOR",
-            "TO_REGNAMESPACE", "TO_REGROLE", "OBJECT_ID");
+    private static final List<String> METADATA_LOOKUP_FUNCTION_NAMES = List.of("TO_REGCLASS", "TO_REGTYPE", "TO_REGPROC", "TO_REGPROCEDURE", "TO_REGOPER",
+            "TO_REGOPERATOR", "TO_REGNAMESPACE", "TO_REGROLE", "OBJECT_ID");
     
-    private final SQLStatementScanner scanner;
-    
-    void checkLeadingStatement(final String upperSql) {
-        if (isBannedCommand(upperSql)) {
+    void checkLeadingStatement(final String upperSql, final boolean executableComment) {
+        if (executableComment || upperSql.startsWith("USE ") || upperSql.startsWith("SET ") || upperSql.startsWith("COPY ") || upperSql.startsWith("LOAD ")
+                || upperSql.startsWith("CALL ") || isAlterSystemStatement(upperSql)) {
             throw new MCPBannedSQLStatementException();
         }
         if (isMetadataIntrospectionStatement(upperSql)) {
@@ -56,161 +59,69 @@ final class SQLStatementSafetyValidator {
     }
     
     void checkParsedStatement(final SQLStatement sqlStatement) {
-        if (sqlStatement instanceof SelectStatement || findWithSegment(sqlStatement).isPresent()) {
-            checkLockingRead(scanner.tokens());
-        }
-        checkParsedStatementTree(sqlStatement);
+        new SQLStatementTreeWalker(this::checkStatement, this::checkExpression).walk(sqlStatement);
     }
     
-    private void checkParsedStatementTree(final SQLStatement sqlStatement) {
-        if (sqlStatement instanceof SelectStatement) {
-            SelectStatement selectStatement = (SelectStatement) sqlStatement;
-            if (selectStatement.getInto().isPresent() || selectStatement.getOutfile().isPresent()) {
-                throw new MCPBannedSQLStatementException();
-            }
-            if (selectStatement.getLock().isPresent()) {
-                throw new MCPLockingReadStatementException();
-            }
-        }
-        findWithSegment(sqlStatement).ifPresent(with -> {
-            for (CommonTableExpressionSegment each : with.getCommonTableExpressions()) {
-                checkParsedStatementTree(each.getSubquery().getSelect());
-            }
-        });
+    private boolean isBannedStatementType(final SQLStatement sqlStatement) {
+        return sqlStatement instanceof SetStatement || sqlStatement instanceof CallStatement
+                || sqlStatement instanceof CreateUserStatement || sqlStatement instanceof AlterUserStatement || sqlStatement instanceof DropUserStatement
+                || sqlStatement instanceof CreateRoleStatement || sqlStatement instanceof AlterRoleStatement || sqlStatement instanceof DropRoleStatement;
     }
     
-    private Optional<WithSegment> findWithSegment(final SQLStatement sqlStatement) {
-        if (sqlStatement instanceof SelectStatement) {
-            return ((SelectStatement) sqlStatement).getWith();
-        }
-        if (sqlStatement instanceof InsertStatement) {
-            return ((InsertStatement) sqlStatement).getWith();
-        }
-        if (sqlStatement instanceof UpdateStatement) {
-            return ((UpdateStatement) sqlStatement).getWith();
-        }
-        if (sqlStatement instanceof DeleteStatement) {
-            return ((DeleteStatement) sqlStatement).getWith();
-        }
-        return sqlStatement instanceof MergeStatement ? ((MergeStatement) sqlStatement).getWith() : Optional.empty();
-    }
-    
-    private boolean isBannedCommand(final String upperSql) {
-        return upperSql.startsWith("USE ")
-                || upperSql.startsWith("SET ")
-                || upperSql.startsWith("COPY ")
-                || upperSql.startsWith("LOAD ")
-                || upperSql.startsWith("CALL ")
-                || scanner.containsExecutableComment()
-                || scanner.containsUserVariableAssignment()
-                || containsBannedDialectPattern(scanner.tokens());
-    }
-    
-    private boolean isMetadataIntrospectionStatement(final String upperSql) {
-        return "SHOW".equals(upperSql)
-                || upperSql.startsWith("SHOW ")
-                || "DESCRIBE".equals(upperSql)
-                || upperSql.startsWith("DESCRIBE ")
-                || "DESC".equals(upperSql)
-                || upperSql.startsWith("DESC ");
-    }
-    
-    private boolean containsBannedDialectPattern(final List<SQLStatementToken> tokens) {
-        return containsSelectIntoFile(tokens)
-                || scanner.containsKeywordSequence(tokens, "ALTER", "SYSTEM")
-                || containsUserOrRoleManagement(tokens)
-                || containsSideEffectingQueryPattern(tokens)
-                || containsMetadataLookupFunction(tokens);
-    }
-    
-    private boolean containsSelectIntoFile(final List<SQLStatementToken> tokens) {
-        for (int index = 0; index + 1 < tokens.size(); index++) {
-            if (!scanner.isKeyword(tokens.get(index), "INTO")) {
-                continue;
-            }
-            if (scanner.isKeyword(tokens.get(index + 1), "OUTFILE") || scanner.isKeyword(tokens.get(index + 1), "DUMPFILE")) {
+    private boolean containsExecutableComment(final SQLStatement sqlStatement) {
+        for (CommentSegment each : sqlStatement.getComments()) {
+            String text = each.getText().trim();
+            if (text.startsWith("/*!") || text.toUpperCase(Locale.ENGLISH).startsWith("/*M!")) {
                 return true;
             }
         }
         return false;
     }
     
-    private boolean containsUserOrRoleManagement(final List<SQLStatementToken> tokens) {
-        return scanner.containsKeywordSequence(tokens, "CREATE", "USER")
-                || scanner.containsKeywordSequence(tokens, "ALTER", "USER")
-                || scanner.containsKeywordSequence(tokens, "DROP", "USER")
-                || scanner.containsKeywordSequence(tokens, "CREATE", "ROLE")
-                || scanner.containsKeywordSequence(tokens, "ALTER", "ROLE")
-                || scanner.containsKeywordSequence(tokens, "DROP", "ROLE");
-    }
-    
-    private boolean containsSideEffectingQueryPattern(final List<SQLStatementToken> tokens) {
-        return scanner.containsKeywordSequence(tokens, "NEXT", "VALUE", "FOR")
-                || containsSequenceNextvalPseudocolumn(tokens)
-                || containsSideEffectingFunction(tokens)
-                || containsLastInsertIdMutation(tokens);
-    }
-    
-    private boolean containsSideEffectingFunction(final List<SQLStatementToken> tokens) {
-        for (int index = 0; index + 1 < tokens.size(); index++) {
-            if ("(".equals(tokens.get(index + 1).text()) && SIDE_EFFECTING_FUNCTION_NAMES.contains(tokens.get(index).upperText())) {
-                return true;
-            }
+    private void checkStatement(final SQLStatement sqlStatement) {
+        if (isBannedStatementType(sqlStatement) || containsExecutableComment(sqlStatement)) {
+            throw new MCPBannedSQLStatementException();
         }
-        return false;
-    }
-    
-    private boolean containsMetadataLookupFunction(final List<SQLStatementToken> tokens) {
-        for (int index = 0; index + 1 < tokens.size(); index++) {
-            if ("(".equals(tokens.get(index + 1).text()) && METADATA_LOOKUP_FUNCTION_NAMES.contains(tokens.get(index).upperText())) {
-                return true;
+        if (sqlStatement instanceof SelectStatement) {
+            SelectStatement select = (SelectStatement) sqlStatement;
+            if (select.getInto().isPresent() || select.getOutfile().isPresent()) {
+                throw new MCPBannedSQLStatementException();
             }
-        }
-        return false;
-    }
-    
-    private boolean containsLastInsertIdMutation(final List<SQLStatementToken> tokens) {
-        for (int index = 0; index + 2 < tokens.size(); index++) {
-            if (scanner.isKeyword(tokens.get(index), "LAST_INSERT_ID") && "(".equals(tokens.get(index + 1).text()) && !")".equals(tokens.get(index + 2).text())) {
-                return true;
+            if (select.getLock().isPresent()) {
+                throw new MCPLockingReadStatementException();
             }
         }
-        return false;
     }
     
-    private boolean containsSequenceNextvalPseudocolumn(final List<SQLStatementToken> tokens) {
-        for (int index = 2; index < tokens.size(); index++) {
-            if (scanner.isKeyword(tokens.get(index), "NEXTVAL") && ".".equals(tokens.get(index - 1).text()) && tokens.get(index - 2).identifier()) {
-                return true;
+    private void checkExpression(final ExpressionSegment expression) {
+        if (expression instanceof FunctionSegment) {
+            checkFunction((FunctionSegment) expression);
+        } else if (expression instanceof BinaryOperationExpression && ":=".equals(((BinaryOperationExpression) expression).getOperator())) {
+            throw new MCPBannedSQLStatementException();
+        } else if (expression instanceof ColumnSegment) {
+            ColumnSegment column = (ColumnSegment) expression;
+            if (column.getOwner().isPresent() && "NEXTVAL".equalsIgnoreCase(column.getIdentifier().getValue())) {
+                throw new MCPBannedSQLStatementException();
             }
         }
-        return false;
     }
     
-    private void checkLockingRead(final List<SQLStatementToken> tokens) {
-        for (int index = 0; index < tokens.size(); index++) {
-            if (containsLockingReadForClause(tokens, index) || containsLockInShareModeClause(tokens, index)) {
-                throw new MCPLockingReadStatementException();
-            }
+    private void checkFunction(final FunctionSegment function) {
+        String functionName = function.getFunctionName().toUpperCase(Locale.ENGLISH);
+        if (SIDE_EFFECTING_FUNCTION_NAMES.contains(functionName) || METADATA_LOOKUP_FUNCTION_NAMES.contains(functionName)
+                || "LAST_INSERT_ID".equals(functionName) && !function.getParameters().isEmpty()) {
+            throw new MCPBannedSQLStatementException();
         }
     }
     
-    private boolean containsLockingReadForClause(final List<SQLStatementToken> tokens, final int index) {
-        if (!scanner.isKeyword(tokens.get(index), "FOR") || index + 1 >= tokens.size()) {
-            return false;
-        }
-        return scanner.isKeyword(tokens.get(index + 1), "UPDATE", "SHARE")
-                || index + 2 < tokens.size() && scanner.isKeyword(tokens.get(index + 1), "KEY") && scanner.isKeyword(tokens.get(index + 2), "SHARE")
-                || index + 3 < tokens.size() && scanner.isKeyword(tokens.get(index + 1), "NO") && scanner.isKeyword(tokens.get(index + 2), "KEY")
-                        && scanner.isKeyword(tokens.get(index + 3), "UPDATE");
+    private boolean isMetadataIntrospectionStatement(final String upperSql) {
+        return "SHOW".equals(upperSql) || upperSql.startsWith("SHOW ") || "DESCRIBE".equals(upperSql) || upperSql.startsWith("DESCRIBE ")
+                || "DESC".equals(upperSql) || upperSql.startsWith("DESC ");
     }
     
-    private boolean containsLockInShareModeClause(final List<SQLStatementToken> tokens, final int index) {
-        return index + 3 < tokens.size()
-                && scanner.isKeyword(tokens.get(index), "LOCK")
-                && scanner.isKeyword(tokens.get(index + 1), "IN")
-                && scanner.isKeyword(tokens.get(index + 2), "SHARE")
-                && scanner.isKeyword(tokens.get(index + 3), "MODE");
+    private boolean isAlterSystemStatement(final String upperSql) {
+        String[] words = upperSql.split("\\s+", 3);
+        return 2 <= words.length && "ALTER".equals(words[0]) && "SYSTEM".equals(words[1]);
     }
     
     private String extractStatementType(final String upperSql) {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementScanner.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementScanner.java
index cfe11f2be2f..04779b4efaa 100644
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementScanner.java
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementScanner.java
@@ -37,6 +37,7 @@ import org.apache.shardingsphere.sql.parser.spi.DialectSQLParserFacade;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Locale;
+import java.util.Set;
 
 final class SQLStatementScanner {
     
@@ -50,13 +51,9 @@ final class SQLStatementScanner {
     
     private final String sql;
     
-    private final boolean lineCommentsHandledByLexer;
-    
-    private final List<Token> rawTokens;
-    
     private final List<Token> visibleTokens;
     
-    private final List<SQLStatementToken> tokens;
+    private final boolean executableComment;
     
     SQLStatementScanner(final String databaseTypeName, final String sql) {
         this(getParserFacade(databaseTypeName), sql);
@@ -72,14 +69,13 @@ final class SQLStatementScanner {
         String trimmedSQL = sql.trim();
         ShardingSpherePreconditions.checkState(!trimmedSQL.isEmpty(), () -> new MCPInvalidRequestException("sql cannot be empty."));
         List<Token> allTokens = getTokens(trimmedSQL);
-        lineCommentsHandledByLexer = areLineCommentsHandledByLexer(allTokens);
-        List<Token> allVisibleTokens = getVisibleTokens(trimmedSQL, allTokens);
+        boolean lineCommentsHandledByLexer = areLineCommentsHandledByLexer(allTokens);
+        List<Token> allVisibleTokens = getVisibleTokens(trimmedSQL, allTokens, lineCommentsHandledByLexer);
         int statementEndIndex = findStatementEndIndex(allVisibleTokens, trimmedSQL.length());
         this.sql = trimmedSQL.substring(0, statementEndIndex).trim();
         ShardingSpherePreconditions.checkState(!this.sql.isEmpty(), () -> new MCPInvalidRequestException("sql cannot be empty."));
-        rawTokens = getTokensBefore(allTokens, this.sql.length());
         visibleTokens = getTokensBefore(allVisibleTokens, this.sql.length());
-        tokens = createStatementTokens(visibleTokens);
+        executableComment = containsExecutableComment(this.sql, getTokensBefore(allTokens, this.sql.length()), lineCommentsHandledByLexer);
     }
     
     private static DialectSQLParserFacade getParserFacade(final String databaseTypeName) {
@@ -88,38 +84,14 @@ final class SQLStatementScanner {
                 () -> new MCPUnsupportedException(String.format("SQL parser is not available for database type `%s`.", databaseTypeName)));
     }
     
-    private int findStatementEndIndex(final List<Token> tokens, final int sqlLength) {
-        for (int index = 0; index < tokens.size(); index++) {
-            Token each = tokens.get(index);
-            if (!";".equals(each.getText())) {
-                continue;
-            }
-            if (index + 1 < tokens.size()) {
-                throw new MCPMultipleSQLStatementsException();
-            }
-            return each.getStartIndex();
-        }
-        return sqlLength;
-    }
-    
-    private List<Token> getTokensBefore(final List<Token> tokens, final int stopIndex) {
-        List<Token> result = new ArrayList<>();
-        for (Token each : tokens) {
-            if (each.getStartIndex() < stopIndex) {
-                result.add(each);
-            }
-        }
-        return result;
+    String sql() {
+        return sql;
     }
     
     SQLStatementScanner scan(final String sql) {
         return new SQLStatementScanner(lexerClass, parserClass, sql);
     }
     
-    String sql() {
-        return sql;
-    }
-    
     String leadingSql() {
         return sql.substring(visibleTokens.isEmpty() ? sql.length() : visibleTokens.get(0).getStartIndex()).trim();
     }
@@ -136,27 +108,53 @@ final class SQLStatementScanner {
         return sql.substring(startIndex, stopIndex).toUpperCase(Locale.ENGLISH);
     }
     
-    List<SQLStatementToken> tokens() {
-        return tokens;
+    boolean containsExecutableComment() {
+        return executableComment;
     }
     
-    private List<SQLStatementToken> createStatementTokens(final List<Token> tokens) {
-        List<SQLStatementToken> result = new ArrayList<>();
-        for (Token each : tokens) {
-            if (BEGIN_DOLLAR_STRING_CONSTANT.equals(getTokenName(each))) {
+    private boolean containsExecutableComment(final String sql, final List<Token> tokens, final boolean lineCommentsHandledByLexer) {
+        int nextIndex = 0;
+        int skippedCommentEnd = -1;
+        for (int index = 0; index < tokens.size(); index++) {
+            Token each = tokens.get(index);
+            if (each.getStartIndex() <= skippedCommentEnd) {
+                continue;
+            }
+            if (each.getStartIndex() > nextIndex && containsExecutableCommentMarker(sql.substring(nextIndex, each.getStartIndex()))) {
+                return true;
+            }
+            if (Token.DEFAULT_CHANNEL != each.getChannel() && startsWithExecutableCommentMarker(each.getText())) {
+                return true;
+            }
+            int blockCommentEnd = findBlockCommentEnd(sql, tokens, index);
+            if (-1 != blockCommentEnd) {
+                if (startsWithExecutableCommentMarker(sql.substring(each.getStartIndex()))) {
+                    return true;
+                }
+                skippedCommentEnd = blockCommentEnd;
+                nextIndex = blockCommentEnd + 1;
                 continue;
             }
-            if (".*".equals(each.getText())) {
-                result.add(new SQLStatementToken(".", each.getStartIndex()));
-                result.add(new SQLStatementToken("*", each.getStartIndex() + 1));
-            } else {
-                result.add(new SQLStatementToken(each.getText(), each.getStartIndex()));
+            int lineCommentEnd = findLineCommentEnd(sql, tokens, index, lineCommentsHandledByLexer);
+            if (-1 != lineCommentEnd) {
+                skippedCommentEnd = lineCommentEnd;
+                nextIndex = lineCommentEnd + 1;
+                continue;
             }
+            nextIndex = Math.max(nextIndex, each.getStopIndex() + 1);
         }
-        return result;
+        return nextIndex < sql.length() && containsExecutableCommentMarker(sql.substring(nextIndex));
+    }
+    
+    boolean startsWithKeyword(final String keyword) {
+        return !visibleTokens.isEmpty() && isKeyword(visibleTokens.get(0), keyword);
     }
     
-    boolean isKeyword(final SQLStatementToken token, final String... keywords) {
+    private boolean isKeyword(final Token token, final String keyword) {
+        return !isQuotedIdentifier(token.getText()) && token.getText().equalsIgnoreCase(keyword);
+    }
+    
+    private boolean isKeyword(final Token token, final String... keywords) {
         for (String each : keywords) {
             if (isKeyword(token, each)) {
                 return true;
@@ -165,60 +163,49 @@ final class SQLStatementScanner {
         return false;
     }
     
-    boolean isKeyword(final SQLStatementToken token, final String keyword) {
-        return !token.quotedIdentifier() && token.upperText().equals(keyword);
+    boolean containsKeyword(final String... keywords) {
+        for (Token each : visibleTokens) {
+            if (isKeyword(each, keywords)) {
+                return true;
+            }
+        }
+        return false;
     }
     
-    boolean containsKeywordSequence(final List<SQLStatementToken> tokens, final String... keywords) {
-        for (int index = 0; index + keywords.length <= tokens.size(); index++) {
-            if (containsKeywordSequence(tokens, index, keywords)) {
+    boolean containsKeywordSequence(final String... keywords) {
+        for (int index = 0; index + keywords.length <= visibleTokens.size(); index++) {
+            if (containsKeywordSequence(index, keywords)) {
                 return true;
             }
         }
         return false;
     }
     
-    private boolean containsKeywordSequence(final List<SQLStatementToken> tokens, final int startIndex, final String... keywords) {
+    private boolean containsKeywordSequence(final int startIndex, final String... keywords) {
         for (int index = 0; index < keywords.length; index++) {
-            if (!isKeyword(tokens.get(startIndex + index), keywords[index])) {
+            if (!isKeyword(visibleTokens.get(startIndex + index), keywords[index])) {
                 return false;
             }
         }
         return true;
     }
     
-    boolean containsExecutableComment() {
-        int nextIndex = 0;
-        int skippedCommentEnd = -1;
-        for (int index = 0; index < rawTokens.size(); index++) {
-            Token each = rawTokens.get(index);
-            if (each.getStartIndex() <= skippedCommentEnd) {
-                continue;
-            }
-            if (each.getStartIndex() > nextIndex && containsExecutableCommentMarker(sql.substring(nextIndex, each.getStartIndex()))) {
+    boolean containsKeywordAfterFirst(final Set<String> keywords) {
+        for (Token each : visibleTokens.subList(1, visibleTokens.size())) {
+            if (!isQuotedIdentifier(each.getText()) && keywords.contains(each.getText().toUpperCase(Locale.ENGLISH))) {
                 return true;
             }
-            if (Token.DEFAULT_CHANNEL != each.getChannel() && startsWithExecutableCommentMarker(each.getText())) {
-                return true;
-            }
-            int blockCommentEnd = findBlockCommentEnd(sql, rawTokens, index);
-            if (-1 != blockCommentEnd) {
-                if (startsWithExecutableCommentMarker(sql, each.getStartIndex())) {
-                    return true;
-                }
-                skippedCommentEnd = blockCommentEnd;
-                nextIndex = blockCommentEnd + 1;
-                continue;
-            }
-            int lineCommentEnd = findLineCommentEnd(sql, rawTokens, index);
-            if (-1 != lineCommentEnd) {
-                skippedCommentEnd = lineCommentEnd;
-                nextIndex = lineCommentEnd + 1;
-                continue;
-            }
-            nextIndex = Math.max(nextIndex, each.getStopIndex() + 1);
         }
-        return nextIndex < sql.length() && containsExecutableCommentMarker(sql.substring(nextIndex));
+        return false;
+    }
+    
+    private boolean isQuotedIdentifier(final String text) {
+        if (2 > text.length()) {
+            return false;
+        }
+        char firstChar = text.charAt(0);
+        char lastChar = text.charAt(text.length() - 1);
+        return '"' == firstChar && '"' == lastChar || '`' == firstChar && '`' == lastChar || '[' == firstChar && ']' == lastChar;
     }
     
     private boolean containsExecutableCommentMarker(final String text) {
@@ -233,7 +220,7 @@ final class SQLStatementScanner {
                 currentIndex++;
                 continue;
             }
-            if (startsWithExecutableCommentMarker(text, currentIndex)) {
+            if (startsWithExecutableCommentMarker(text.substring(currentIndex))) {
                 return true;
             }
             int commentEndIndex = text.indexOf("*/", currentIndex + 2);
@@ -242,58 +229,31 @@ final class SQLStatementScanner {
         return false;
     }
     
-    private boolean startsWithExecutableCommentMarker(final String text) {
-        return text.startsWith("/*!") || text.toUpperCase(Locale.ENGLISH).startsWith("/*M!");
-    }
-    
-    private boolean startsWithExecutableCommentMarker(final String sql, final int startIndex) {
-        return sql.startsWith("/*!", startIndex) || sql.regionMatches(true, startIndex, "/*M!", 0, 4);
-    }
-    
-    boolean containsUserVariableAssignment() {
-        for (int index = 0; index < visibleTokens.size(); index++) {
-            Token variable = visibleTokens.get(index);
-            if (variable.getText().startsWith("@") && containsUserVariableAssignment(index)) {
-                return true;
+    private int findStatementEndIndex(final List<Token> tokens, final int sqlLength) {
+        for (int index = 0; index < tokens.size(); index++) {
+            Token each = tokens.get(index);
+            if (!";".equals(each.getText())) {
+                continue;
             }
-        }
-        return false;
-    }
-    
-    private boolean containsUserVariableAssignment(final int variableIndex) {
-        Token variable = visibleTokens.get(variableIndex);
-        int assignmentIndex = variableIndex + 1;
-        if ("@".equals(variable.getText())) {
-            if (assignmentIndex >= visibleTokens.size() || visibleTokens.get(assignmentIndex).getStartIndex() != variable.getStopIndex() + 1) {
-                return false;
+            if (index + 1 < tokens.size()) {
+                throw new MCPMultipleSQLStatementsException();
             }
-            variable = visibleTokens.get(assignmentIndex++);
-        }
-        if (1 >= variable.getText().length() && !isVariableName(variable.getText())) {
-            return false;
-        }
-        return assignmentIndex < visibleTokens.size() && ":=".equals(visibleTokens.get(assignmentIndex).getText())
-                && isWhitespace(variable.getStopIndex() + 1, visibleTokens.get(assignmentIndex).getStartIndex());
-    }
-    
-    private boolean isVariableName(final String text) {
-        if (text.isEmpty()) {
-            return false;
+            return each.getStartIndex();
         }
-        char firstChar = text.charAt(0);
-        return Character.isLetterOrDigit(firstChar) || '_' == firstChar || '$' == firstChar || '\'' == firstChar || '"' == firstChar || '`' == firstChar;
+        return sqlLength;
     }
     
-    private boolean isWhitespace(final int startIndex, final int stopIndex) {
-        for (int index = startIndex; index < stopIndex; index++) {
-            if (!Character.isWhitespace(sql.charAt(index))) {
-                return false;
+    private List<Token> getTokensBefore(final List<Token> tokens, final int stopIndex) {
+        List<Token> result = new ArrayList<>();
+        for (Token each : tokens) {
+            if (each.getStartIndex() < stopIndex) {
+                result.add(each);
             }
         }
-        return true;
+        return result;
     }
     
-    private List<Token> getVisibleTokens(final String sql, final List<Token> tokens) {
+    private List<Token> getVisibleTokens(final String sql, final List<Token> tokens, final boolean lineCommentsHandledByLexer) {
         List<Token> result = new ArrayList<>();
         boolean executableComment = false;
         boolean dollarQuotedString = false;
@@ -326,7 +286,7 @@ final class SQLStatementScanner {
                 skippedCommentEnd = blockCommentEnd;
                 continue;
             }
-            int lineCommentEnd = findLineCommentEnd(sql, tokens, index);
+            int lineCommentEnd = findLineCommentEnd(sql, tokens, index, lineCommentsHandledByLexer);
             if (-1 != lineCommentEnd) {
                 skippedCommentEnd = lineCommentEnd;
                 continue;
@@ -355,7 +315,7 @@ final class SQLStatementScanner {
         return result + 1;
     }
     
-    private int findLineCommentEnd(final String sql, final List<Token> tokens, final int startIndex) {
+    private int findLineCommentEnd(final String sql, final List<Token> tokens, final int startIndex, final boolean lineCommentsHandledByLexer) {
         Token start = tokens.get(startIndex);
         if (lineCommentsHandledByLexer || !"-".equals(start.getText()) || startIndex + 1 >= tokens.size() || !"-".equals(tokens.get(startIndex + 1).getText())
                 || tokens.get(startIndex + 1).getStartIndex() != start.getStopIndex() + 1) {
@@ -365,6 +325,10 @@ final class SQLStatementScanner {
         return -1 == result ? sql.length() - 1 : result;
     }
     
+    private boolean startsWithExecutableCommentMarker(final String text) {
+        return text.startsWith("/*!") || text.toUpperCase(Locale.ENGLISH).startsWith("/*M!");
+    }
+    
     private boolean areLineCommentsHandledByLexer(final List<Token> tokens) {
         for (String each : ((Lexer) tokens.get(0).getTokenSource()).getRuleNames()) {
             if (each.contains("LINE_COMMENT")) {
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementToken.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementToken.java
deleted file mode 100644
index d6bf4c0e7f0..00000000000
--- a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementToken.java
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one or more
- * contributor license agreements.  See the NOTICE file distributed with
- * this work for additional information regarding copyright ownership.
- * The ASF licenses this file to You under the Apache License, Version 2.0
- * (the "License"); you may not use this file except in compliance with
- * the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package org.apache.shardingsphere.mcp.core.tool.handler.execute;
-
-import java.util.Locale;
-
-final class SQLStatementToken {
-    
-    private final String text;
-    
-    private final String upperText;
-    
-    private final boolean quotedIdentifier;
-    
-    private final int startIndex;
-    
-    SQLStatementToken(final String text, final int startIndex) {
-        this.text = text;
-        upperText = text.toUpperCase(Locale.ENGLISH);
-        quotedIdentifier = isQuotedIdentifier(text);
-        this.startIndex = startIndex;
-    }
-    
-    String text() {
-        return text;
-    }
-    
-    String upperText() {
-        return upperText;
-    }
-    
-    boolean quotedIdentifier() {
-        return quotedIdentifier;
-    }
-    
-    int startIndex() {
-        return startIndex;
-    }
-    
-    boolean identifier() {
-        return quotedIdentifier || !text.isEmpty() && isIdentifierStart(text.charAt(0));
-    }
-    
-    private boolean isIdentifierStart(final char value) {
-        return Character.isLetterOrDigit(value) || '_' == value || '$' == value;
-    }
-    
-    private boolean isQuotedIdentifier(final String text) {
-        if (2 > text.length()) {
-            return false;
-        }
-        char firstChar = text.charAt(0);
-        char lastChar = text.charAt(text.length() - 1);
-        return '"' == firstChar && '"' == lastChar || '`' == firstChar && '`' == lastChar || '[' == firstChar && ']' == lastChar;
-    }
-}
diff --git a/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementTreeWalker.java b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementTreeWalker.java
new file mode 100644
index 00000000000..a6f77d2ca0d
--- /dev/null
+++ b/mcp/core/src/main/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/SQLStatementTreeWalker.java
@@ -0,0 +1,452 @@
+/*
+ * 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.shardingsphere.mcp.core.tool.handler.execute;
+
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.assignment.ColumnAssignmentSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.combine.CombineSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.datetime.DatetimeExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.CaseWhenExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.CollateExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExistsSubqueryExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.IntervalExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.KeyValueSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ListExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.QuantifySubqueryExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.RowExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.TypeCastExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.UnaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ValuesExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.DatetimeProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ExpressionProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.IntervalExpressionProjection;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.SubqueryProjectionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.join.OuterJoinExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.merge.MergeWhenAndThenSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.multiset.MultisetExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ExpressionOrderByItemSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.ExpressionPaginationValueSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.PaginationValueSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.table.MultiTableConditionalIntoSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.table.MultiTableConditionalIntoWhenThenSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlElementFunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlPiFunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlQueryAndExistsFunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlSerializeFunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlTableColumnSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlTableFunctionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.xml.XmlTableOptionsSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ModelColumnSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.ModelSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OutputSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WindowItemSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WithSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.match.MatchAgainstExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.CollectionTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.DeleteMultiTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.FunctionTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.JoinTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SubqueryTableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.TableSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.procedure.SQLStatementSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.SQLStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.function.CreateFunctionStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.procedure.CreateProcedureStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.table.CreateTableStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.trigger.CreateTriggerStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.view.AlterViewStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.view.CreateMaterializedViewStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.ddl.view.CreateViewStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.DeleteStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.InsertStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.MergeStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.UpdateStatement;
+
+import java.util.function.Consumer;
+
+@RequiredArgsConstructor
+final class SQLStatementTreeWalker {
+    
+    private final Consumer<SQLStatement> statementConsumer;
+    
+    private final Consumer<ExpressionSegment> expressionConsumer;
+    
+    void walk(final SQLStatement sqlStatement) {
+        if (null == sqlStatement) {
+            return;
+        }
+        statementConsumer.accept(sqlStatement);
+        if (sqlStatement instanceof SelectStatement) {
+            walkSelect((SelectStatement) sqlStatement);
+        } else if (sqlStatement instanceof InsertStatement) {
+            walkInsert((InsertStatement) sqlStatement);
+        } else if (sqlStatement instanceof UpdateStatement) {
+            walkUpdate((UpdateStatement) sqlStatement);
+        } else if (sqlStatement instanceof DeleteStatement) {
+            walkDelete((DeleteStatement) sqlStatement);
+        } else if (sqlStatement instanceof MergeStatement) {
+            walkMerge((MergeStatement) sqlStatement);
+        } else {
+            walkDDL(sqlStatement);
+        }
+    }
+    
+    private void walkDDL(final SQLStatement sqlStatement) {
+        if (sqlStatement instanceof CreateTableStatement) {
+            ((CreateTableStatement) sqlStatement).getSelectStatement().ifPresent(this::walk);
+        } else if (sqlStatement instanceof CreateViewStatement) {
+            walk(((CreateViewStatement) sqlStatement).getSelect());
+        } else if (sqlStatement instanceof AlterViewStatement) {
+            ((AlterViewStatement) sqlStatement).getSelect().ifPresent(this::walk);
+        } else if (sqlStatement instanceof CreateMaterializedViewStatement) {
+            walk(((CreateMaterializedViewStatement) sqlStatement).getSelect());
+        } else if (sqlStatement instanceof CreateFunctionStatement) {
+            walkRoutine(((CreateFunctionStatement) sqlStatement).getSqlStatements(), ((CreateFunctionStatement) sqlStatement).getDynamicSqlStatementExpressions());
+        } else if (sqlStatement instanceof CreateProcedureStatement) {
+            walkRoutine(((CreateProcedureStatement) sqlStatement).getSqlStatements(), ((CreateProcedureStatement) sqlStatement).getDynamicSqlStatementExpressions());
+        } else if (sqlStatement instanceof CreateTriggerStatement) {
+            walkRoutine(((CreateTriggerStatement) sqlStatement).getSqlStatements(), ((CreateTriggerStatement) sqlStatement).getDynamicSqlStatementExpressions());
+        }
+    }
+    
+    private void walkRoutine(final Iterable<SQLStatementSegment> sqlStatements, final Iterable<ExpressionSegment> expressions) {
+        sqlStatements.forEach(each -> walk(each.getSqlStatement()));
+        expressions.forEach(this::walkExpression);
+    }
+    
+    private void walkSelect(final SelectStatement sqlStatement) {
+        walkProjections(sqlStatement.getProjections());
+        sqlStatement.getWhere().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getHaving().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getGroupBy().ifPresent(each -> walkOrderByItems(each.getGroupByItems()));
+        sqlStatement.getOrderBy().ifPresent(each -> walkOrderByItems(each.getOrderByItems()));
+        sqlStatement.getFrom().ifPresent(this::walkTable);
+        sqlStatement.getHierarchicalQuery().ifPresent(each -> {
+            walkExpression(each.getStartWith());
+            walkExpression(each.getConnectBy());
+        });
+        sqlStatement.getCombine().ifPresent(this::walkCombine);
+        sqlStatement.getWith().ifPresent(this::walkWith);
+        sqlStatement.getLimit().ifPresent(this::walkLimit);
+        sqlStatement.getWindow().ifPresent(each -> each.getItemSegments().forEach(this::walkWindow));
+        sqlStatement.getModel().ifPresent(this::walkModel);
+        sqlStatement.getTransformSegments().forEach(this::walkExpression);
+    }
+    
+    private void walkInsert(final InsertStatement sqlStatement) {
+        sqlStatement.getInsertSelect().ifPresent(each -> walk(each.getSelect()));
+        sqlStatement.getSetAssignment().ifPresent(each -> each.getAssignments().forEach(assignment -> walkExpression(assignment.getValue())));
+        sqlStatement.getOnDuplicateKeyColumns().ifPresent(each -> each.getColumns().forEach(assignment -> walkExpression(assignment.getValue())));
+        sqlStatement.getValues().forEach(each -> each.getValues().forEach(this::walkExpression));
+        sqlStatement.getWhere().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getExec().ifPresent(each -> each.getExpressionSegments().forEach(this::walkExpression));
+        sqlStatement.getRowSetFunction().ifPresent(this::walkExpression);
+        sqlStatement.getMultiTableInsertInto().ifPresent(each -> each.getInsertStatements().forEach(this::walk));
+        sqlStatement.getMultiTableConditionalInto().ifPresent(this::walkMultiTableConditionalInto);
+        sqlStatement.getWith().ifPresent(this::walkWith);
+        sqlStatement.getReturning().ifPresent(each -> walkProjections(each.getProjections()));
+        sqlStatement.getOutput().ifPresent(this::walkOutput);
+    }
+    
+    private void walkMultiTableConditionalInto(final MultiTableConditionalIntoSegment segment) {
+        for (MultiTableConditionalIntoWhenThenSegment each : segment.getWhenThenSegments()) {
+            walkExpression(each.getWhenSegment());
+            each.getThenSegment().getInsertStatements().forEach(this::walk);
+        }
+        segment.getElseSegment().ifPresent(each -> each.getInsertStatements().forEach(this::walk));
+    }
+    
+    private void walkUpdate(final UpdateStatement sqlStatement) {
+        walkTable(sqlStatement.getTable());
+        sqlStatement.getAssignment().ifPresent(each -> each.getAssignments().forEach(assignment -> walkExpression(assignment.getValue())));
+        sqlStatement.getWhere().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getDeleteWhere().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getOrderBy().ifPresent(each -> walkOrderByItems(each.getOrderByItems()));
+        sqlStatement.getLimit().ifPresent(this::walkLimit);
+        sqlStatement.getFrom().ifPresent(this::walkTable);
+        sqlStatement.getWith().ifPresent(this::walkWith);
+        sqlStatement.getReturning().ifPresent(each -> walkProjections(each.getProjections()));
+        sqlStatement.getOutput().ifPresent(this::walkOutput);
+    }
+    
+    private void walkDelete(final DeleteStatement sqlStatement) {
+        walkTable(sqlStatement.getTable());
+        sqlStatement.getWhere().ifPresent(each -> walkExpression(each.getExpr()));
+        sqlStatement.getOrderBy().ifPresent(each -> walkOrderByItems(each.getOrderByItems()));
+        sqlStatement.getLimit().ifPresent(this::walkLimit);
+        sqlStatement.getWith().ifPresent(this::walkWith);
+        sqlStatement.getReturning().ifPresent(each -> walkProjections(each.getProjections()));
+        sqlStatement.getOutput().ifPresent(this::walkOutput);
+    }
+    
+    private void walkMerge(final MergeStatement sqlStatement) {
+        walkTable(sqlStatement.getTarget());
+        walkTable(sqlStatement.getSource());
+        if (null != sqlStatement.getExpression()) {
+            walkExpression(sqlStatement.getExpression().getExpr());
+        }
+        sqlStatement.getUpdate().ifPresent(this::walk);
+        sqlStatement.getInsert().ifPresent(this::walk);
+        for (MergeWhenAndThenSegment each : sqlStatement.getWhenAndThens()) {
+            walkExpression(each.getAndExpr());
+            if (null != each.getUpdate()) {
+                walk(each.getUpdate());
+            }
+            if (null != each.getInsert()) {
+                walk(each.getInsert());
+            }
+        }
+        sqlStatement.getWith().ifPresent(this::walkWith);
+        sqlStatement.getOutput().ifPresent(this::walkOutput);
+    }
+    
+    private void walkWith(final WithSegment with) {
+        with.getCommonTableExpressions().forEach(each -> walk(each.getSubquery().getSelect()));
+    }
+    
+    private void walkCombine(final CombineSegment combine) {
+        walk(combine.getLeft().getSelect());
+        walk(combine.getRight().getSelect());
+    }
+    
+    private void walkProjections(final ProjectionsSegment projections) {
+        if (null == projections) {
+            return;
+        }
+        for (ProjectionSegment each : projections.getProjections()) {
+            if (each instanceof ExpressionProjectionSegment) {
+                walkExpression(((ExpressionProjectionSegment) each).getExpr());
+            } else if (each instanceof ExpressionSegment) {
+                walkExpression((ExpressionSegment) each);
+            } else if (each instanceof ColumnProjectionSegment) {
+                walkExpression(((ColumnProjectionSegment) each).getColumn());
+            } else if (each instanceof SubqueryProjectionSegment) {
+                walk(((SubqueryProjectionSegment) each).getSubquery().getSelect());
+            } else if (each instanceof DatetimeProjectionSegment) {
+                walkExpression(((DatetimeProjectionSegment) each).getLeft());
+                walkExpression(((DatetimeProjectionSegment) each).getRight());
+            }
+        }
+    }
+    
+    private void walkOrderByItems(final Iterable<OrderByItemSegment> items) {
+        for (OrderByItemSegment each : items) {
+            if (each instanceof ExpressionOrderByItemSegment) {
+                walkExpression(((ExpressionOrderByItemSegment) each).getExpr());
+            }
+        }
+    }
+    
+    private void walkLimit(final LimitSegment limit) {
+        limit.getOffset().ifPresent(this::walkPaginationValue);
+        limit.getRowCount().ifPresent(this::walkPaginationValue);
+    }
+    
+    private void walkPaginationValue(final PaginationValueSegment value) {
+        if (value instanceof ExpressionPaginationValueSegment) {
+            walkExpression(((ExpressionPaginationValueSegment) value).getExpression());
+        }
+    }
+    
+    private void walkOutput(final OutputSegment output) {
+        walkProjections(output.getOutputColumns());
+    }
+    
+    private void walkWindow(final WindowItemSegment window) {
+        if (null != window.getPartitionListSegments()) {
+            window.getPartitionListSegments().forEach(this::walkExpression);
+        }
+        if (null != window.getOrderBySegment()) {
+            walkOrderByItems(window.getOrderBySegment().getOrderByItems());
+        }
+        walkExpression(window.getFrameClause());
+    }
+    
+    private void walkModel(final ModelSegment model) {
+        model.getReferenceModelSelects().forEach(each -> walk(each.getSelect()));
+        model.getCellAssignmentSelects().forEach(each -> walk(each.getSelect()));
+        model.getOrderBySegments().forEach(each -> walkOrderByItems(each.getOrderByItems()));
+        model.getPartitionColumns().forEach(this::walkModelColumn);
+        model.getDimensionColumns().forEach(this::walkModelColumn);
+        model.getMeasureColumns().forEach(this::walkModelColumn);
+        model.getCellAssignmentColumns().forEach(this::walkExpression);
+    }
+    
+    private void walkModelColumn(final ModelColumnSegment modelColumn) {
+        walkExpression(modelColumn.getExpression());
+    }
+    
+    private void walkTable(final TableSegment table) {
+        if (table instanceof SimpleTableSegment) {
+            ((SimpleTableSegment) table).getTableSampleExpression().ifPresent(this::walkExpression);
+        } else if (table instanceof FunctionTableSegment) {
+            walkExpression(((FunctionTableSegment) table).getTableFunction());
+        } else if (table instanceof JoinTableSegment) {
+            JoinTableSegment join = (JoinTableSegment) table;
+            walkTable(join.getLeft());
+            walkTable(join.getRight());
+            walkExpression(join.getCondition());
+            join.getLeftQueryPartitionListSegments().forEach(this::walkExpression);
+            join.getRightQueryPartitionListSegments().forEach(this::walkExpression);
+        } else if (table instanceof SubqueryTableSegment) {
+            walk(((SubqueryTableSegment) table).getSubquery().getSelect());
+        } else if (table instanceof CollectionTableSegment) {
+            walkExpression(((CollectionTableSegment) table).getExpressionSegment());
+        } else if (table instanceof DeleteMultiTableSegment) {
+            walkTable(((DeleteMultiTableSegment) table).getRelationTable());
+        }
+    }
+    
+    private void walkExpression(final ExpressionSegment expression) {
+        if (null == expression) {
+            return;
+        }
+        expressionConsumer.accept(expression);
+        if (expression instanceof FunctionSegment) {
+            walkFunction((FunctionSegment) expression);
+        } else if (expression instanceof AggregationProjectionSegment) {
+            AggregationProjectionSegment aggregation = (AggregationProjectionSegment) expression;
+            aggregation.getParameters().forEach(this::walkExpression);
+            aggregation.getWindow().ifPresent(this::walkWindow);
+        } else if (expression instanceof BinaryOperationExpression) {
+            walkExpression(((BinaryOperationExpression) expression).getLeft());
+            walkExpression(((BinaryOperationExpression) expression).getRight());
+        } else if (expression instanceof ColumnAssignmentSegment) {
+            walkExpression(((ColumnAssignmentSegment) expression).getValue());
+        } else if (expression instanceof ListExpression) {
+            ((ListExpression) expression).getItems().forEach(this::walkExpression);
+        } else if (expression instanceof BetweenExpression) {
+            BetweenExpression between = (BetweenExpression) expression;
+            walkExpression(between.getLeft());
+            walkExpression(between.getBetweenExpr());
+            walkExpression(between.getAndExpr());
+        } else if (expression instanceof InExpression) {
+            walkExpression(((InExpression) expression).getLeft());
+            walkExpression(((InExpression) expression).getRight());
+        } else if (expression instanceof CaseWhenExpression) {
+            walkCaseWhen((CaseWhenExpression) expression);
+        } else if (expression instanceof NotExpression) {
+            walkExpression(((NotExpression) expression).getExpression());
+        } else if (expression instanceof TypeCastExpression) {
+            walkExpression(((TypeCastExpression) expression).getExpression());
+        } else if (expression instanceof CollateExpression) {
+            ((CollateExpression) expression).getExpr().ifPresent(this::walkExpression);
+        } else if (expression instanceof DatetimeExpression) {
+            walkExpression(((DatetimeExpression) expression).getLeft());
+            walkExpression(((DatetimeExpression) expression).getRight());
+        } else if (expression instanceof IntervalExpression) {
+            walkExpression(((IntervalExpression) expression).getValue());
+        } else if (expression instanceof IntervalExpressionProjection) {
+            walkIntervalProjection((IntervalExpressionProjection) expression);
+        } else if (expression instanceof KeyValueSegment) {
+            walkExpression(((KeyValueSegment) expression).getKey());
+            walkExpression(((KeyValueSegment) expression).getValue());
+        } else if (expression instanceof RowExpression) {
+            ((RowExpression) expression).getItems().forEach(this::walkExpression);
+        } else if (expression instanceof UnaryOperationExpression) {
+            walkExpression(((UnaryOperationExpression) expression).getExpression());
+        } else if (expression instanceof ValuesExpression) {
+            ((ValuesExpression) expression).getRowConstructorList().forEach(each -> each.getValues().forEach(this::walkExpression));
+        } else if (expression instanceof MatchAgainstExpression) {
+            walkMatchAgainst((MatchAgainstExpression) expression);
+        } else if (expression instanceof MultisetExpression) {
+            walkExpression(((MultisetExpression) expression).getLeft());
+            walkExpression(((MultisetExpression) expression).getRight());
+        } else if (expression instanceof OuterJoinExpression) {
+            walkExpression(((OuterJoinExpression) expression).getColumnName());
+        } else if (expression instanceof SubquerySegment) {
+            walk(((SubquerySegment) expression).getSelect());
+        } else if (expression instanceof SubqueryExpressionSegment) {
+            walk(((SubqueryExpressionSegment) expression).getSubquery().getSelect());
+        } else if (expression instanceof ExistsSubqueryExpression) {
+            walk(((ExistsSubqueryExpression) expression).getSubquery().getSelect());
+        } else if (expression instanceof QuantifySubqueryExpression) {
+            walk(((QuantifySubqueryExpression) expression).getSubquery().getSelect());
+        } else {
+            walkXMLExpression(expression);
+        }
+    }
+    
+    private void walkFunction(final FunctionSegment function) {
+        function.getParameters().forEach(this::walkExpression);
+        function.getWindow().ifPresent(this::walkWindow);
+    }
+    
+    private void walkCaseWhen(final CaseWhenExpression caseWhen) {
+        walkExpression(caseWhen.getCaseExpr());
+        caseWhen.getWhenExprs().forEach(this::walkExpression);
+        caseWhen.getThenExprs().forEach(this::walkExpression);
+        walkExpression(caseWhen.getElseExpr());
+    }
+    
+    private void walkIntervalProjection(final IntervalExpressionProjection interval) {
+        walkExpression(interval.getLeft());
+        walkExpression(interval.getMinus());
+        walkExpression(interval.getRight());
+    }
+    
+    private void walkMatchAgainst(final MatchAgainstExpression match) {
+        match.getColumns().forEach(this::walkExpression);
+        walkExpression(match.getExpr());
+    }
+    
+    private void walkXMLExpression(final ExpressionSegment expression) {
+        if (expression instanceof XmlElementFunctionSegment) {
+            XmlElementFunctionSegment xmlElement = (XmlElementFunctionSegment) expression;
+            xmlElement.getXmlAttributes().forEach(this::walkExpression);
+            xmlElement.getParameters().forEach(this::walkExpression);
+        } else if (expression instanceof XmlPiFunctionSegment) {
+            walkExpression(((XmlPiFunctionSegment) expression).getEvalNameValueExpr());
+            walkExpression(((XmlPiFunctionSegment) expression).getValueExpr());
+        } else if (expression instanceof XmlQueryAndExistsFunctionSegment) {
+            ((XmlQueryAndExistsFunctionSegment) expression).getParameters().forEach(this::walkExpression);
+        } else if (expression instanceof XmlSerializeFunctionSegment) {
+            walkExpression(((XmlSerializeFunctionSegment) expression).getParameter());
+        } else if (expression instanceof XmlTableFunctionSegment) {
+            walkXmlTableOptions(((XmlTableFunctionSegment) expression).getXmlTableOption());
+        } else if (expression instanceof XmlTableOptionsSegment) {
+            walkXmlTableOptions((XmlTableOptionsSegment) expression);
+        } else if (expression instanceof XmlTableColumnSegment) {
+            walkExpression(((XmlTableColumnSegment) expression).getDefaultExpr());
+        }
+    }
+    
+    private void walkXmlTableOptions(final XmlTableOptionsSegment options) {
+        if (null == options) {
+            return;
+        }
+        options.getParameters().forEach(this::walkExpression);
+        options.getXmlTableColumnSegments().forEach(each -> walkExpression(each.getDefaultExpr()));
+    }
+}
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacadeTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacadeTest.java
index 5bfbef12945..d1502f48eeb 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacadeTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPSQLExecutionFacadeTest.java
@@ -398,7 +398,7 @@ class MCPSQLExecutionFacadeTest {
         MCPDatabaseCapabilityProvider capabilityProvider = mock(MCPDatabaseCapabilityProvider.class);
         MCPSessionExecutionCoordinator coordinator = mock(MCPSessionExecutionCoordinator.class);
         MCPDatabaseCapability capability = createCapability(Set.of(SupportedMCPStatement.EXPLAIN));
-        SQLExecutionRequest request = createExecutionRequest("EXPLAIN BROKEN SELECT * FROM orders");
+        SQLExecutionRequest request = createExecutionRequest("EXPLAIN SELECT * FROM orders");
         mockSessionLock(coordinator);
         when(capabilityProvider.provide("logic_db")).thenReturn(Optional.of(capability));
         MCPJdbcStatementExecutor statementExecutor = mock(MCPJdbcStatementExecutor.class);
@@ -408,7 +408,7 @@ class MCPSQLExecutionFacadeTest {
         assertThat(actual.getDatabase(), is("logic_db"));
         assertThat(actual.getSchema(), is("public"));
         assertThat(actual.getSql(), is("SELECT * FROM orders"));
-        assertThat(actual.getExplainSql(), is("EXPLAIN BROKEN SELECT * FROM orders"));
+        assertThat(actual.getExplainSql(), is("EXPLAIN SELECT * FROM orders"));
     }
     
     @Test
diff --git a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzerTest.java b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzerTest.java
index 2e83c157b81..1721c4a4d2c 100644
--- a/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzerTest.java
+++ b/mcp/core/src/test/java/org/apache/shardingsphere/mcp/core/tool/handler/execute/MCPStatementAnalyzerTest.java
@@ -151,6 +151,13 @@ class MCPStatementAnalyzerTest {
         assertTrue(actual.getReferencedObjects().iterator().next().isNamespaceTarget());
     }
     
+    @Test
+    void assertAnalyzeMultipleDCLReferences() {
+        ClassificationResult actual = analyzer.analyze("GRANT CONNECT ON DATABASE other_db, archive_db TO PUBLIC", createCapability("PostgreSQL"));
+        assertThat(getObjectNames(actual), contains("other_db", "archive_db"));
+        assertTrue(actual.getReferencedObjects().stream().allMatch(SQLStatementObjectName::isNamespaceTarget));
+    }
+    
     @Test
     void assertAnalyzeQualifiedFunctionReference() {
         ClassificationResult actual = analyzer.analyze("SELECT other_db.foo_refresh_orders()", createCapability("MySQL"));
@@ -228,7 +235,9 @@ class MCPStatementAnalyzerTest {
                 Arguments.of("drop schema", "PostgreSQL", "DROP SCHEMA order_archive", List.of("order_archive")),
                 Arguments.of("create sequence", "PostgreSQL", "CREATE SEQUENCE order_seq", List.of("order_seq")),
                 Arguments.of("alter sequence", "PostgreSQL", "ALTER SEQUENCE order_seq INCREMENT BY 2", List.of("order_seq")),
-                Arguments.of("drop sequence", "PostgreSQL", "DROP SEQUENCE order_seq", List.of("order_seq")));
+                Arguments.of("drop sequence", "PostgreSQL", "DROP SEQUENCE order_seq", List.of("order_seq")),
+                Arguments.of("qualified function in XML expression", "PostgreSQL", "SELECT XMLELEMENT(NAME result, other_db.foo_refresh_orders())",
+                        List.of("other_db.foo_refresh_orders")));
     }
     
     private static Stream<Arguments> statementCases() {
@@ -236,14 +245,15 @@ class MCPStatementAnalyzerTest {
                 Arguments.of("trim trailing semicolon", "MySQL", "  SELECT * FROM orders ;  ", SupportedMCPStatement.QUERY, "SELECT", "SELECT * FROM orders", "orders", ""),
                 Arguments.of("trailing comment after semicolon", "ClickHouse", "SELECT 1; /* trailing comment */", SupportedMCPStatement.QUERY, "SELECT", "SELECT 1", "", ""),
                 Arguments.of("trailing line comment after semicolon", "ClickHouse", "SELECT 1; --trailing comment", SupportedMCPStatement.QUERY, "SELECT", "SELECT 1", "", ""),
+                Arguments.of("trailing executable comment after semicolon", "MySQL", "SELECT 1; /*!80018 SELECT 2 */", SupportedMCPStatement.QUERY, "SELECT", "SELECT 1", "", ""),
                 Arguments.of("supplementary character before semicolon", "MySQL", "SELECT '😀';", SupportedMCPStatement.QUERY, "SELECT", "SELECT '😀'", "", ""),
                 Arguments.of("semicolon literal", "MySQL", "SELECT ';' AS literal_value", SupportedMCPStatement.QUERY, "SELECT", "SELECT ';' AS literal_value", "", ""),
                 Arguments.of("mysql hash comment", "MySQL", "SELECT 1 # @order_status := 1", SupportedMCPStatement.QUERY, "SELECT",
                         "SELECT 1 # @order_status := 1", "", ""),
                 Arguments.of("postgresql adjacent dash comment", "PostgreSQL", "SELECT 1--@order_status:=1", SupportedMCPStatement.QUERY, "SELECT",
                         "SELECT 1--@order_status:=1", "", ""),
-                Arguments.of("postgresql dollar quoted literal", "PostgreSQL", "SELECT $$@order_status:=1; /*!80018 ANALYZE */$$", SupportedMCPStatement.QUERY, "SELECT",
-                        "SELECT $$@order_status:=1; /*!80018 ANALYZE */$$", "", ""),
+                Arguments.of("postgresql dollar quoted literal", "PostgreSQL", "SELECT $$/*!80018 ANALYZE */; @order_status:=1$$", SupportedMCPStatement.QUERY, "SELECT",
+                        "SELECT $$/*!80018 ANALYZE */; @order_status:=1$$", "", ""),
                 Arguments.of("opengauss tagged dollar quoted literal", "openGauss", "SELECT $tag$a;b$tag$", SupportedMCPStatement.QUERY, "SELECT",
                         "SELECT $tag$a;b$tag$", "", ""),
                 Arguments.of("user variable assignment string", "MySQL", "SELECT '@order_status := 1'", SupportedMCPStatement.QUERY, "SELECT",
@@ -271,6 +281,7 @@ class MCPStatementAnalyzerTest {
                 Arguments.of("grant", "MySQL", "GRANT SELECT ON orders TO PUBLIC", SupportedMCPStatement.DCL, "GRANT", "GRANT SELECT ON orders TO PUBLIC", "orders", ""),
                 Arguments.of("revoke", "MySQL", "REVOKE SELECT ON orders FROM PUBLIC", SupportedMCPStatement.DCL, "REVOKE", "REVOKE SELECT ON orders FROM PUBLIC", "orders", ""),
                 Arguments.of("begin", "MySQL", "BEGIN", SupportedMCPStatement.TRANSACTION_CONTROL, "BEGIN", "BEGIN", "", ""),
+                Arguments.of("begin without dialect parser support", "SQLServer", "BEGIN", SupportedMCPStatement.TRANSACTION_CONTROL, "BEGIN", "BEGIN", "", ""),
                 Arguments.of("start transaction", "MySQL", "START TRANSACTION", SupportedMCPStatement.TRANSACTION_CONTROL, "START TRANSACTION", "START TRANSACTION", "", ""),
                 Arguments.of("commit", "MySQL", "COMMIT", SupportedMCPStatement.TRANSACTION_CONTROL, "COMMIT", "COMMIT", "", ""),
                 Arguments.of("rollback", "MySQL", "ROLLBACK", SupportedMCPStatement.TRANSACTION_CONTROL, "ROLLBACK", "ROLLBACK", "", ""),
@@ -319,6 +330,10 @@ class MCPStatementAnalyzerTest {
                 Arguments.of("banned call", "MySQL", "CALL refresh_orders()", MCPBannedSQLStatementException.class, "Statement is banned by the MCP contract."),
                 Arguments.of("banned select into outfile", "MySQL", "SELECT * FROM orders INTO OUTFILE '/tmp/orders.csv'", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
+                Arguments.of("banned select into outfile before from", "MySQL", "SELECT * INTO OUTFILE '/tmp/orders.csv' FROM orders", MCPBannedSQLStatementException.class,
+                        "Statement is banned by the MCP contract."),
+                Arguments.of("banned select into dumpfile", "MySQL", "SELECT * FROM orders INTO DUMPFILE '/tmp/orders.bin'", MCPBannedSQLStatementException.class,
+                        "Statement is banned by the MCP contract."),
                 Arguments.of("banned executable comment", "MySQL", "SELECT 1 /*!50000 UNION SELECT 2 */", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned MariaDB executable comment", "MariaDB", "SELECT 1 /*M!100000 UNION SELECT 2 */", MCPBannedSQLStatementException.class,
@@ -333,6 +348,8 @@ class MCPStatementAnalyzerTest {
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned next value for", "SQLServer", "SELECT NEXT VALUE FOR order_seq", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
+                Arguments.of("banned next value for with ordering", "SQLServer", "SELECT NEXT VALUE FOR logic_db.dbo.order_seq OVER (ORDER BY order_id)",
+                        MCPBannedSQLStatementException.class, "Statement is banned by the MCP contract."),
                 Arguments.of("banned nextval pseudocolumn", "Oracle", "SELECT order_seq.NEXTVAL FROM dual", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned named lock", "MySQL", "SELECT GET_LOCK('order_lock', 1)", MCPBannedSQLStatementException.class,
@@ -341,6 +358,12 @@ class MCPStatementAnalyzerTest {
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned advisory lock", "PostgreSQL", "SELECT pg_advisory_lock(1)", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
+                Arguments.of("banned advisory lock in combined query", "PostgreSQL", "SELECT 1 UNION SELECT pg_advisory_lock(1)", MCPBannedSQLStatementException.class,
+                        "Statement is banned by the MCP contract."),
+                Arguments.of("banned advisory lock in XML expression", "PostgreSQL", "SELECT XMLELEMENT(NAME result, pg_advisory_lock(1))",
+                        MCPBannedSQLStatementException.class, "Statement is banned by the MCP contract."),
+                Arguments.of("banned advisory lock in aggregation window", "PostgreSQL", "SELECT SUM(order_id) OVER (ORDER BY pg_advisory_lock(1)) FROM orders",
+                        MCPBannedSQLStatementException.class, "Statement is banned by the MCP contract."),
                 Arguments.of("banned configuration mutation", "PostgreSQL", "SELECT set_config('search_path', 'public', false)", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned replication slot advance", "PostgreSQL", "SELECT pg_replication_slot_advance('order_slot', '0/1')",
@@ -361,8 +384,13 @@ class MCPStatementAnalyzerTest {
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned metadata lookup", "PostgreSQL", "SELECT to_regclass('orders')", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
+                Arguments.of("banned metadata lookup in SQL Server case expression", "SQLServer",
+                        "SELECT CASE WHEN 1 = 1 THEN OBJECT_ID('foo_orders') ELSE 0 END", MCPBannedSQLStatementException.class,
+                        "Statement is banned by the MCP contract."),
                 Arguments.of("banned alter system", "PostgreSQL", "ALTER SYSTEM SET shared_buffers = '128MB'", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
+                Arguments.of("banned alter system with line break", "PostgreSQL", "ALTER\nSYSTEM SET shared_buffers = '128MB'", MCPBannedSQLStatementException.class,
+                        "Statement is banned by the MCP contract."),
                 Arguments.of("banned create user", "MySQL", "CREATE USER app_user IDENTIFIED BY 'pwd'", MCPBannedSQLStatementException.class,
                         "Statement is banned by the MCP contract."),
                 Arguments.of("banned alter role", "PostgreSQL", "ALTER ROLE app_role SET search_path = public", MCPBannedSQLStatementException.class,
diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
index e74f7c80add..b29af21ad9a 100644
--- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
+++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/MySQLStatementVisitor.java
@@ -119,6 +119,9 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Replace
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowAliasContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.RowConstructorListContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectFieldsIntoContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectIntoExpressionContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectLinesIntoContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectSpecificationContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SelectWithIntoContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SeparatorNameContext;
@@ -219,6 +222,9 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.ite
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ExpressionOrderByItemSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.IndexOrderByItemSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.outfile.OutfileColumnsSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.outfile.OutfileLinesSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.outfile.OutfileSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.PaginationValueSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.LimitSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.pagination.limit.NumberLiteralLimitValueSegment;
@@ -402,6 +408,10 @@ public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<AS
     
     @Override
     public ASTNode visitFunctionName(final FunctionNameContext ctx) {
+        return createFunctionSegment(ctx);
+    }
+    
+    private FunctionSegment createFunctionSegment(final FunctionNameContext ctx) {
         FunctionSegment result = new FunctionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.identifier().IDENTIFIER_().getText(), ctx.getText());
         if (null != ctx.owner()) {
             result.setOwner((OwnerSegment) visit(ctx.owner()));
@@ -781,10 +791,68 @@ public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<AS
             return visit(ctx.selectWithInto());
         }
         SelectStatement result = (SelectStatement) visit(ctx.queryExpression());
+        OutfileSegment outfile = null;
+        if (null != ctx.selectIntoExpression()) {
+            ASTNode intoSegment = visit(ctx.selectIntoExpression());
+            if (intoSegment instanceof OutfileSegment) {
+                outfile = (OutfileSegment) intoSegment;
+            }
+        }
+        if (null == outfile && null == ctx.lockClauseList()) {
+            return result;
+        }
+        SelectStatement.SelectStatementBuilder selectStatementBuilder = createSelectStatementBuilder(result).outfile(outfile);
         if (null != ctx.lockClauseList()) {
-            result = createSelectStatementBuilder(result).lock((LockSegment) visit(ctx.lockClauseList())).build();
+            selectStatementBuilder.lock((LockSegment) visit(ctx.lockClauseList()));
         }
-        return result;
+        return selectStatementBuilder.build();
+    }
+    
+    @Override
+    public ASTNode visitSelectIntoExpression(final SelectIntoExpressionContext ctx) {
+        if (null == ctx.OUTFILE() && null == ctx.DUMPFILE()) {
+            return visitChildren(ctx);
+        }
+        String characterSet = null == ctx.charsetName() ? null : ctx.charsetName().getText();
+        OutfileColumnsSegment columns = ctx.selectFieldsInto().isEmpty() ? null : createOutfileColumnsSegment(ctx);
+        OutfileLinesSegment lines = ctx.selectLinesInto().isEmpty() ? null : createOutfileLinesSegment(ctx);
+        return new OutfileSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), SQLUtils.getExactlyValue(ctx.string_().getText()),
+                null, null, characterSet, columns, lines);
+    }
+    
+    private OutfileColumnsSegment createOutfileColumnsSegment(final SelectIntoExpressionContext ctx) {
+        int startIndex = ctx.selectFieldsInto(0).getStart().getStartIndex();
+        int stopIndex = ctx.selectFieldsInto(ctx.selectFieldsInto().size() - 1).getStop().getStopIndex();
+        String terminatedBy = null;
+        String enclosedBy = null;
+        String escapedBy = null;
+        boolean optionallyEnclosed = false;
+        for (SelectFieldsIntoContext each : ctx.selectFieldsInto()) {
+            if (null != each.TERMINATED()) {
+                terminatedBy = SQLUtils.getExactlyValue(each.string_().getText());
+            } else if (null != each.ENCLOSED()) {
+                enclosedBy = SQLUtils.getExactlyValue(each.string_().getText());
+                optionallyEnclosed = null != each.OPTIONALLY();
+            } else {
+                escapedBy = SQLUtils.getExactlyValue(each.string_().getText());
+            }
+        }
+        return new OutfileColumnsSegment(startIndex, stopIndex, terminatedBy, enclosedBy, escapedBy, optionallyEnclosed);
+    }
+    
+    private OutfileLinesSegment createOutfileLinesSegment(final SelectIntoExpressionContext ctx) {
+        int startIndex = ctx.selectLinesInto(0).getStart().getStartIndex();
+        int stopIndex = ctx.selectLinesInto(ctx.selectLinesInto().size() - 1).getStop().getStopIndex();
+        String startingBy = null;
+        String terminatedBy = null;
+        for (SelectLinesIntoContext each : ctx.selectLinesInto()) {
+            if (null != each.STARTING()) {
+                startingBy = SQLUtils.getExactlyValue(each.string_().getText());
+            } else {
+                terminatedBy = SQLUtils.getExactlyValue(each.string_().getText());
+            }
+        }
+        return new OutfileLinesSegment(startIndex, stopIndex, startingBy, terminatedBy);
     }
     
     @Override
@@ -872,7 +940,15 @@ public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<AS
         if (null != ctx.lockClauseList()) {
             lock = (LockSegment) visit(ctx.lockClauseList());
         }
-        return SelectStatement.builder().databaseType(databaseType).projections(projections).from(from).where(where).groupBy(groupBy).having(having).window(window).lock(lock).build();
+        OutfileSegment outfile = null;
+        if (null != ctx.selectIntoExpression()) {
+            ASTNode intoSegment = visit(ctx.selectIntoExpression());
+            if (intoSegment instanceof OutfileSegment) {
+                outfile = (OutfileSegment) intoSegment;
+            }
+        }
+        return SelectStatement.builder().databaseType(databaseType).projections(projections).from(from).where(where).groupBy(groupBy).having(having).window(window).lock(lock)
+                .outfile(outfile).build();
     }
     
     @Override
@@ -900,8 +976,7 @@ public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<AS
     public ASTNode visitTableStatement(final TableStatementContext ctx) {
         ProjectionsSegment projections = new ProjectionsSegment(ctx.start.getStartIndex(), ctx.start.getStartIndex());
         projections.getProjections().add(new ShorthandProjectionSegment(ctx.start.getStartIndex(), ctx.start.getStartIndex()));
-        return SelectStatement.builder().databaseType(databaseType).projections(projections)
-                .from(new SimpleTableSegment(new TableNameSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), new IdentifierValue(ctx.tableName().getText())))).build();
+        return SelectStatement.builder().databaseType(databaseType).projections(projections).from((SimpleTableSegment) visit(ctx.tableName())).build();
     }
     
     @Override
@@ -942,7 +1017,9 @@ public abstract class MySQLStatementVisitor extends MySQLStatementBaseVisitor<AS
     
     @Override
     public ASTNode visitUdfFunction(final UdfFunctionContext ctx) {
-        FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), getOriginalText(ctx), getOriginalText(ctx));
+        FunctionSegment functionName = createFunctionSegment(ctx.functionName());
+        FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), functionName.getFunctionName(), getOriginalText(ctx));
+        result.setOwner(functionName.getOwner());
         if (null != ctx.expr()) {
             for (ExprContext each : ctx.expr()) {
                 result.getParameters().add((ExpressionSegment) visit(each));
diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDCLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDCLStatementVisitor.java
index aee6d93eb6e..1ef012070a5 100644
--- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDCLStatementVisitor.java
+++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDCLStatementVisitor.java
@@ -92,6 +92,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.enums.ACLAttributeTyp
 import org.apache.shardingsphere.sql.parser.statement.core.enums.SSLType;
 import org.apache.shardingsphere.sql.parser.statement.core.enums.UserResourceSpecifiedLimitType;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PasswordOrLockOptionSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.RoleOrPrivilegeSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.TLSOptionSegment;
@@ -114,6 +115,7 @@ import org.apache.shardingsphere.sql.parser.statement.mysql.dcl.user.MySQLRename
 import org.apache.shardingsphere.sql.parser.statement.mysql.dcl.user.MySQLSetPasswordStatement;
 
 import java.util.Collections;
+import java.util.Locale;
 import java.util.stream.Collectors;
 
 /**
@@ -144,11 +146,13 @@ public final class MySQLDCLStatementVisitor extends MySQLStatementVisitor implem
             fillRoleOrPrivileges(result, ctx.roleOrPrivileges());
         }
         result.setLevel(generateGrantLevel(ctx.grantIdentifier()));
+        String objectType = null == ctx.aclType() ? "TABLE" : ctx.aclType().getText().toUpperCase(Locale.ENGLISH);
+        result.getPrivilegeObjects().add(generatePrivilegeObject(ctx.grantIdentifier(), objectType));
         for (UsernameContext each : ctx.userList().username()) {
             result.getUsers().add((UserSegment) visit(each));
         }
         if (null != ctx.aclType()) {
-            result.setAclObject(ctx.aclType().getText().toUpperCase());
+            result.setAclObject(objectType);
         }
         return result;
     }
@@ -193,6 +197,24 @@ public final class MySQLDCLStatementVisitor extends MySQLStatementVisitor implem
         return new GrantLevelSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), databaseName, tableName);
     }
     
+    private PrivilegeObjectSegment generatePrivilegeObject(final GrantIdentifierContext ctx, final String objectType) {
+        PrivilegeObjectSegment result = new PrivilegeObjectSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), objectType);
+        if (ctx instanceof GrantLevelGlobalContext) {
+            result.getIdentifiers().add(new IdentifierValue("*"));
+            result.getIdentifiers().add(new IdentifierValue("*"));
+        } else if (ctx instanceof GrantLevelDatabaseGlobalContext) {
+            result.getIdentifiers().add(new IdentifierValue(((GrantLevelDatabaseGlobalContext) ctx).databaseName().getText()));
+            result.getIdentifiers().add(new IdentifierValue("*"));
+        } else {
+            GrantLevelTableContext tableContext = (GrantLevelTableContext) ctx;
+            if (null != tableContext.tableName().owner()) {
+                result.getIdentifiers().add(new IdentifierValue(tableContext.tableName().owner().getText()));
+            }
+            result.getIdentifiers().add(new IdentifierValue(tableContext.tableName().name().getText()));
+        }
+        return result;
+    }
+    
     @Override
     public ASTNode visitRoleOrDynamicPrivilege(final RoleOrDynamicPrivilegeContext ctx) {
         String role = new IdentifierValue(ctx.roleIdentifierOrText().getText()).getValue();
@@ -446,6 +468,11 @@ public final class MySQLDCLStatementVisitor extends MySQLStatementVisitor implem
         }
         if (null != ctx.grantIdentifier()) {
             result.setLevel(generateGrantLevel(ctx.grantIdentifier()));
+            String objectType = null == ctx.aclType() ? "TABLE" : ctx.aclType().getText().toUpperCase(Locale.ENGLISH);
+            result.getPrivilegeObjects().add(generatePrivilegeObject(ctx.grantIdentifier(), objectType));
+            if (null != ctx.aclType()) {
+                result.setAclObject(objectType);
+            }
         }
         for (UsernameContext each : ctx.userList().username()) {
             result.getFromUsers().add((UserSegment) visit(each));
diff --git a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDDLStatementVisitor.java b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDDLStatementVisitor.java
index c62e4c9aaa2..7849b048cce 100644
--- a/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDDLStatementVisitor.java
+++ b/parser/sql/engine/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/engine/mysql/visitor/statement/type/MySQLDDLStatementVisitor.java
@@ -287,6 +287,7 @@ public final class MySQLDDLStatementVisitor extends MySQLStatementVisitor implem
                 .temporary(null != ctx.TEMPORARY())
                 .likeTable(null == ctx.createLikeClause() ? null : (SimpleTableSegment) visit(ctx.createLikeClause()))
                 .createTableOption(null == ctx.createTableOptions() ? null : (CreateTableOptionSegment) visit(ctx.createTableOptions()))
+                .selectStatement(null == ctx.duplicateAsQueryExpression() ? null : (SelectStatement) visit(ctx.duplicateAsQueryExpression().select()))
                 .columnDefinitions(columnDefinitions)
                 .constraintDefinitions(constraintDefinitions)
                 .build();
diff --git a/parser/sql/engine/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/engine/opengauss/visitor/statement/type/OpenGaussDCLStatementVisitor.java b/parser/sql/engine/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/engine/opengauss/visitor/statement/type/OpenGaussDCLStatementVisitor.java
index 553da1fde69..e3cac071833 100644
--- a/parser/sql/engine/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/engine/opengauss/visitor/statement/type/OpenGaussDCLStatementVisitor.java
+++ b/parser/sql/engine/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/engine/opengauss/visitor/statement/type/OpenGaussDCLStatementVisitor.java
@@ -22,14 +22,28 @@ import org.apache.shardingsphere.sql.parser.api.ASTNode;
 import org.apache.shardingsphere.sql.parser.api.visitor.statement.type.DCLStatementVisitor;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.AlterRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.AlterUserContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.AnyNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.AttrsContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.CreateRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.CreateUserContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.DropRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.DropUserContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.FuncNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.FunctionWithArgtypesContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.GrantContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.IndirectionContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.NameContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.NameListContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.NumericOnlyContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.OnObjectClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.PrivilegeClauseContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.PrivilegeLevelContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.QualifiedNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.QualifiedNameListContext;
 import org.apache.shardingsphere.sql.parser.autogen.OpenGaussStatementParser.RevokeContext;
 import org.apache.shardingsphere.sql.parser.engine.opengauss.visitor.statement.OpenGaussStatementVisitor;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.RevokeStatement;
@@ -40,9 +54,13 @@ import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.us
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.CreateUserStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.DropUserStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.value.collection.CollectionValue;
+import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import org.antlr.v4.runtime.ParserRuleContext;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * DCL statement visitor for openGauss.
@@ -55,12 +73,16 @@ public final class OpenGaussDCLStatementVisitor extends OpenGaussStatementVisito
     
     @Override
     public ASTNode visitGrant(final GrantContext ctx) {
-        return new GrantStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        GrantStatement result = new GrantStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        fillPrivilegeObjects(result.getPrivilegeObjects(), ctx.privilegeClause());
+        return result;
     }
     
     @Override
     public ASTNode visitRevoke(final RevokeContext ctx) {
-        return new RevokeStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        RevokeStatement result = new RevokeStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        fillPrivilegeObjects(result.getPrivilegeObjects(), ctx.privilegeClause());
+        return result;
     }
     
     private boolean containsTableSegment(final PrivilegeClauseContext ctx) {
@@ -72,6 +94,193 @@ public final class OpenGaussDCLStatementVisitor extends OpenGaussStatementVisito
         return ((CollectionValue<SimpleTableSegment>) visit(ctx.onObjectClause().privilegeLevel().tableNames())).getValue();
     }
     
+    private void fillPrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final PrivilegeClauseContext ctx) {
+        if (null == ctx || null == ctx.onObjectClause()) {
+            return;
+        }
+        OnObjectClauseContext onObjectClause = ctx.onObjectClause();
+        String objectType = getObjectType(onObjectClause);
+        if (null != onObjectClause.nameList()) {
+            fillNamePrivilegeObjects(result, objectType, onObjectClause.nameList());
+        } else if (null != onObjectClause.anyNameList()) {
+            for (AnyNameContext each : onObjectClause.anyNameList().anyName()) {
+                addPrivilegeObject(result, objectType, each, getAnyNameIdentifiers(each));
+            }
+        } else if (null != onObjectClause.functionWithArgtypesList()) {
+            for (FunctionWithArgtypesContext each : onObjectClause.functionWithArgtypesList().functionWithArgtypes()) {
+                addPrivilegeObject(result, objectType, each, getFunctionIdentifiers(each));
+            }
+        } else if (null != onObjectClause.numericOnlyList()) {
+            for (NumericOnlyContext each : onObjectClause.numericOnlyList().numericOnly()) {
+                addPrivilegeObject(result, objectType, each, Collections.singletonList(new IdentifierValue(each.getText())));
+            }
+        } else if (null != onObjectClause.qualifiedNameList()) {
+            fillQualifiedNamePrivilegeObjects(result, objectType, onObjectClause.qualifiedNameList());
+        } else {
+            fillPrivilegeLevelObjects(result, objectType, onObjectClause.privilegeLevel());
+        }
+    }
+    
+    private String getObjectType(final OnObjectClauseContext ctx) {
+        if (null != ctx.ALL() || null != ctx.SCHEMA()) {
+            return "SCHEMA";
+        }
+        if (null != ctx.DATABASE()) {
+            return "DATABASE";
+        }
+        if (null != ctx.DOMAIN()) {
+            return "DOMAIN";
+        }
+        if (null != ctx.FUNCTION()) {
+            return "FUNCTION";
+        }
+        if (null != ctx.PROCEDURE()) {
+            return "PROCEDURE";
+        }
+        if (null != ctx.ROUTINE()) {
+            return "ROUTINE";
+        }
+        if (null != ctx.LANGUAGE()) {
+            return "LANGUAGE";
+        }
+        if (null != ctx.LARGE()) {
+            return "LARGE OBJECT";
+        }
+        if (null != ctx.TABLESPACE()) {
+            return "TABLESPACE";
+        }
+        if (null != ctx.TYPE()) {
+            return "TYPE";
+        }
+        if (null != ctx.SEQUENCE()) {
+            return "SEQUENCE";
+        }
+        if (null != ctx.FOREIGN()) {
+            return null == ctx.DATA() ? "FOREIGN SERVER" : "FOREIGN DATA WRAPPER";
+        }
+        if (null != ctx.CLIENT_MASTER_KEY()) {
+            return "CLIENT MASTER KEY";
+        }
+        if (null != ctx.COLUMN_ENCRYPTION_KEY()) {
+            return "COLUMN ENCRYPTION KEY";
+        }
+        return "TABLE";
+    }
+    
+    private void fillNamePrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final String objectType, final NameListContext ctx) {
+        if (null != ctx.nameList()) {
+            fillNamePrivilegeObjects(result, objectType, ctx.nameList());
+        }
+        NameContext name = ctx.name();
+        addPrivilegeObject(result, objectType, name, Collections.singletonList(new IdentifierValue(name.getText())));
+    }
+    
+    private List<IdentifierValue> getAnyNameIdentifiers(final AnyNameContext ctx) {
+        List<IdentifierValue> result = new LinkedList<>();
+        result.add(new IdentifierValue(ctx.colId().getText()));
+        if (null != ctx.attrs()) {
+            fillAttrsIdentifiers(result, ctx.attrs());
+        }
+        return result;
+    }
+    
+    private void fillAttrsIdentifiers(final Collection<IdentifierValue> result, final AttrsContext ctx) {
+        if (null != ctx.attrs()) {
+            fillAttrsIdentifiers(result, ctx.attrs());
+        }
+        result.add(new IdentifierValue(ctx.attrName().getText()));
+    }
+    
+    private List<IdentifierValue> getFunctionIdentifiers(final FunctionWithArgtypesContext ctx) {
+        if (null != ctx.funcName()) {
+            return getFunctionIdentifiers(ctx.funcName());
+        }
+        List<IdentifierValue> result = new LinkedList<>();
+        if (null != ctx.typeFuncNameKeyword()) {
+            result.add(new IdentifierValue(ctx.typeFuncNameKeyword().getText()));
+        } else {
+            result.add(new IdentifierValue(ctx.colId().getText()));
+            fillIndirectionIdentifiers(result, ctx.indirection());
+        }
+        return result;
+    }
+    
+    private List<IdentifierValue> getFunctionIdentifiers(final FuncNameContext ctx) {
+        List<IdentifierValue> result = new LinkedList<>();
+        if (null != ctx.typeFunctionName()) {
+            result.add(new IdentifierValue(ctx.typeFunctionName().getText()));
+        } else {
+            result.add(new IdentifierValue(ctx.colId().getText()));
+            fillIndirectionIdentifiers(result, ctx.indirection());
+        }
+        return result;
+    }
+    
+    private void fillIndirectionIdentifiers(final Collection<IdentifierValue> result, final IndirectionContext ctx) {
+        if (null == ctx) {
+            return;
+        }
+        if (null != ctx.indirection()) {
+            fillIndirectionIdentifiers(result, ctx.indirection());
+        }
+        if (null != ctx.indirectionEl().attrName()) {
+            result.add(new IdentifierValue(ctx.indirectionEl().attrName().getText()));
+        }
+    }
+    
+    private void fillQualifiedNamePrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final String objectType, final QualifiedNameListContext ctx) {
+        if (null != ctx.qualifiedNameList()) {
+            fillQualifiedNamePrivilegeObjects(result, objectType, ctx.qualifiedNameList());
+        }
+        QualifiedNameContext qualifiedName = ctx.qualifiedName();
+        addSimpleTablePrivilegeObject(result, objectType, (SimpleTableSegment) visit(qualifiedName));
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void fillPrivilegeLevelObjects(final Collection<PrivilegeObjectSegment> result, final String objectType, final PrivilegeLevelContext ctx) {
+        if (null != ctx.tableNames()) {
+            for (SimpleTableSegment each : ((CollectionValue<SimpleTableSegment>) visit(ctx.tableNames())).getValue()) {
+                addSimpleTablePrivilegeObject(result, objectType, each);
+            }
+            return;
+        }
+        List<IdentifierValue> identifiers = new LinkedList<>();
+        if (null != ctx.identifier()) {
+            identifiers.add((IdentifierValue) visit(ctx.identifier()));
+            identifiers.add(new IdentifierValue("*"));
+        } else if (null != ctx.schemaName()) {
+            identifiers.add((IdentifierValue) visit(ctx.schemaName()));
+            identifiers.add(new IdentifierValue(ctx.routineName().getText()));
+        } else {
+            identifiers.add(new IdentifierValue("*"));
+            if (null != ctx.DOT_ASTERISK_()) {
+                identifiers.add(new IdentifierValue("*"));
+            }
+        }
+        addPrivilegeObject(result, objectType, ctx, identifiers);
+    }
+    
+    private void addSimpleTablePrivilegeObject(final Collection<PrivilegeObjectSegment> result, final String objectType, final SimpleTableSegment table) {
+        List<IdentifierValue> identifiers = new LinkedList<>();
+        table.getOwner().ifPresent(owner -> fillOwnerIdentifiers(identifiers, owner));
+        identifiers.add(table.getTableName().getIdentifier());
+        PrivilegeObjectSegment privilegeObject = new PrivilegeObjectSegment(table.getStartIndex(), table.getStopIndex(), objectType);
+        privilegeObject.getIdentifiers().addAll(identifiers);
+        result.add(privilegeObject);
+    }
+    
+    private void fillOwnerIdentifiers(final Collection<IdentifierValue> result, final OwnerSegment owner) {
+        owner.getOwner().ifPresent(each -> fillOwnerIdentifiers(result, each));
+        result.add(owner.getIdentifier());
+    }
+    
+    private void addPrivilegeObject(final Collection<PrivilegeObjectSegment> result, final String objectType, final ParserRuleContext ctx,
+                                    final Collection<IdentifierValue> identifiers) {
+        PrivilegeObjectSegment privilegeObject = new PrivilegeObjectSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), objectType);
+        privilegeObject.getIdentifiers().addAll(identifiers);
+        result.add(privilegeObject);
+    }
+    
     @Override
     public ASTNode visitCreateUser(final CreateUserContext ctx) {
         return new CreateUserStatement(getDatabaseType());
diff --git a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
index 774ff498b85..6155e385ca4 100644
--- a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
+++ b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/OracleStatementVisitor.java
@@ -35,6 +35,7 @@ import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.BitExp
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.BitValueLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.BooleanLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.BooleanPrimaryContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.BuiltinFunctionsExprContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CaseExpressionContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CaseWhenContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CastFunctionContext;
@@ -612,6 +613,9 @@ public abstract class OracleStatementVisitor extends OracleStatementBaseVisitor<
         if (null != ctx.multisetExpr()) {
             return createMultisetExpression(ctx);
         }
+        if (null != ctx.builtinFunctionsExpr()) {
+            return visit(ctx.builtinFunctionsExpr());
+        }
         return new NotExpression(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.expr(0)), false);
     }
     
@@ -1514,6 +1518,15 @@ public abstract class OracleStatementVisitor extends OracleStatementBaseVisitor<
         return result;
     }
     
+    @Override
+    public final ASTNode visitBuiltinFunctionsExpr(final BuiltinFunctionsExprContext ctx) {
+        FunctionSegment result = new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), ctx.builtinFunction().getText(), getOriginalText(ctx));
+        result.setOwner(new OwnerSegment(ctx.packageIdentifier().getStart().getStartIndex(), ctx.packageIdentifier().getStop().getStopIndex(),
+                (IdentifierValue) visit(ctx.packageIdentifier().identifier())));
+        result.getParameters().add((ExpressionSegment) visit(ctx.expr()));
+        return result;
+    }
+    
     @Override
     public final ASTNode visitDataTypeName(final DataTypeNameContext ctx) {
         Collection<String> dataTypeNames = new LinkedList<>();
diff --git a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDDLStatementVisitor.java b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDDLStatementVisitor.java
index 71b2c737713..2f84b12efba 100644
--- a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDDLStatementVisitor.java
+++ b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDDLStatementVisitor.java
@@ -95,6 +95,7 @@ import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.Create
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateLockdownProfileContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateMaterializedViewContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateMaterializedViewLogContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateObjectTableClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateOperatorContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateOutlineContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreatePFileContext;
@@ -111,6 +112,7 @@ import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.Create
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateTriggerContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateTypeContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateViewContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CreateXMLTypeTableClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CursorDefinitionContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CursorParameterDecContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.CursorForLoopStatementContext;
@@ -202,6 +204,7 @@ import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.Statem
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.SwitchContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.SystemActionContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.TableNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.TablePropertiesContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.TriggerBodyContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.TriggerNameContext;
 import org.apache.shardingsphere.sql.parser.autogen.OracleStatementParser.TruncateTableContext;
@@ -412,12 +415,39 @@ public final class OracleDDLStatementVisitor extends OracleStatementVisitor impl
                 }
             }
         }
-        return CreateTableStatement.builder()
+        SelectStatement selectStatement = getCreateTableSelectStatement(ctx.createDefinitionClause());
+        CreateTableStatement result = CreateTableStatement.builder()
                 .databaseType(getDatabaseType())
                 .table((SimpleTableSegment) visit(ctx.tableName()))
+                .selectStatement(selectStatement)
                 .columnDefinitions(columnDefinitions)
                 .constraintDefinitions(constraintDefinitions)
                 .build();
+        if (null != selectStatement) {
+            result.addParameterMarkers(getGlobalParameterMarkerSegments());
+        }
+        return result;
+    }
+    
+    private SelectStatement getCreateTableSelectStatement(final CreateDefinitionClauseContext ctx) {
+        TablePropertiesContext tableProperties = null;
+        if (null != ctx.createRelationalTableClause()) {
+            tableProperties = ctx.createRelationalTableClause().tableProperties();
+        } else if (null != ctx.createObjectTableClause()) {
+            CreateObjectTableClauseContext objectTable = ctx.createObjectTableClause();
+            tableProperties = objectTable.tableProperties();
+        } else if (null != ctx.createXMLTypeTableClause()) {
+            CreateXMLTypeTableClauseContext xmlTypeTable = ctx.createXMLTypeTableClause();
+            tableProperties = xmlTypeTable.tableProperties();
+        }
+        if (null == tableProperties || null == tableProperties.selectSubquery()) {
+            return null;
+        }
+        OracleDMLStatementVisitor visitor = new OracleDMLStatementVisitor(getDatabaseType());
+        SelectStatement result = (SelectStatement) visitor.visit(tableProperties.selectSubquery());
+        getGlobalParameterMarkerSegments().addAll(visitor.getGlobalParameterMarkerSegments());
+        getStatementParameterMarkerSegments().addAll(visitor.getStatementParameterMarkerSegments());
+        return result;
     }
     
     @Override
diff --git a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
index c329de1fa69..33076ea1594 100644
--- a/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
+++ b/parser/sql/engine/dialect/oracle/src/main/java/org/apache/shardingsphere/sql/parser/engine/oracle/visitor/statement/type/OracleDMLStatementVisitor.java
@@ -609,7 +609,9 @@ public final class OracleDMLStatementVisitor extends OracleStatementVisitor impl
         if (null != ctx.pivotInClause()) {
             ctx.pivotInClause().pivotInClauseExpr().forEach(each -> {
                 ExpressionSegment expr = (ExpressionSegment) visit(each.expr());
-                String columnName = null == each.alias() || null == each.alias().identifier() ? expr.getText() : each.alias().identifier().IDENTIFIER_().getText();
+                String columnName = null == each.alias() || null == each.alias().identifier()
+                        ? expr.getText()
+                        : ((IdentifierValue) visit(each.alias().identifier())).getValue();
                 ColumnSegment columnSegment = new ColumnSegment(each.getStart().getStartIndex(), each.getStop().getStopIndex(), new IdentifierValue(columnName));
                 pivotInColumns.add(columnSegment);
             });
diff --git a/parser/sql/engine/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/engine/postgresql/visitor/statement/type/PostgreSQLDCLStatementVisitor.java b/parser/sql/engine/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/engine/postgresql/visitor/statement/type/PostgreSQLDCLStatementVisitor.java
index c77cc378550..18ae604fbb5 100644
--- a/parser/sql/engine/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/engine/postgresql/visitor/statement/type/PostgreSQLDCLStatementVisitor.java
+++ b/parser/sql/engine/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/engine/postgresql/visitor/statement/type/PostgreSQLDCLStatementVisitor.java
@@ -22,16 +22,30 @@ import org.apache.shardingsphere.sql.parser.api.ASTNode;
 import org.apache.shardingsphere.sql.parser.api.visitor.statement.type.DCLStatementVisitor;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.AlterRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.AlterUserContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.AnyNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.AttrsContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.CreateGroupContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.CreateRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.CreateUserContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.DropRoleContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.DropUserContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.FuncNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.FunctionWithArgtypesContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.GrantContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.IndirectionContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.NameContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.NameListContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.NumericOnlyContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.OnObjectClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.PrivilegeClauseContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.PrivilegeLevelContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.QualifiedNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.QualifiedNameListContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.ReassignOwnedContext;
 import org.apache.shardingsphere.sql.parser.autogen.PostgreSQLStatementParser.RevokeContext;
 import org.apache.shardingsphere.sql.parser.engine.postgresql.visitor.statement.PostgreSQLStatementVisitor;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.GrantStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.RevokeStatement;
@@ -42,11 +56,15 @@ import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.us
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.CreateUserStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl.user.DropUserStatement;
 import org.apache.shardingsphere.sql.parser.statement.core.value.collection.CollectionValue;
+import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 import org.apache.shardingsphere.sql.parser.statement.postgresql.dcl.PostgreSQLCreateGroupStatement;
 import org.apache.shardingsphere.sql.parser.statement.postgresql.dcl.PostgreSQLReassignOwnedStatement;
+import org.antlr.v4.runtime.ParserRuleContext;
 
 import java.util.Collection;
 import java.util.Collections;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * DCL statement visitor for PostgreSQL.
@@ -59,12 +77,16 @@ public final class PostgreSQLDCLStatementVisitor extends PostgreSQLStatementVisi
     
     @Override
     public ASTNode visitGrant(final GrantContext ctx) {
-        return new GrantStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        GrantStatement result = new GrantStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        fillPrivilegeObjects(result.getPrivilegeObjects(), ctx.privilegeClause());
+        return result;
     }
     
     @Override
     public ASTNode visitRevoke(final RevokeContext ctx) {
-        return new RevokeStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        RevokeStatement result = new RevokeStatement(getDatabaseType(), containsTableSegment(ctx.privilegeClause()) ? getTableSegments(ctx.privilegeClause()) : Collections.emptyList());
+        fillPrivilegeObjects(result.getPrivilegeObjects(), ctx.privilegeClause());
+        return result;
     }
     
     private boolean containsTableSegment(final PrivilegeClauseContext ctx) {
@@ -76,6 +98,191 @@ public final class PostgreSQLDCLStatementVisitor extends PostgreSQLStatementVisi
         return ((CollectionValue<SimpleTableSegment>) visit(ctx.onObjectClause().privilegeLevel().tableNames())).getValue();
     }
     
+    private void fillPrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final PrivilegeClauseContext ctx) {
+        if (null == ctx || null == ctx.onObjectClause()) {
+            return;
+        }
+        OnObjectClauseContext onObjectClause = ctx.onObjectClause();
+        String objectType = getObjectType(onObjectClause);
+        if (null != onObjectClause.nameList()) {
+            fillNamePrivilegeObjects(result, objectType, onObjectClause.nameList());
+        } else if (null != onObjectClause.anyNameList()) {
+            for (AnyNameContext each : onObjectClause.anyNameList().anyName()) {
+                addPrivilegeObject(result, objectType, each, getAnyNameIdentifiers(each));
+            }
+        } else if (null != onObjectClause.functionWithArgtypesList()) {
+            for (FunctionWithArgtypesContext each : onObjectClause.functionWithArgtypesList().functionWithArgtypes()) {
+                addPrivilegeObject(result, objectType, each, getFunctionIdentifiers(each));
+            }
+        } else if (null != onObjectClause.numericOnlyList()) {
+            for (NumericOnlyContext each : onObjectClause.numericOnlyList().numericOnly()) {
+                addPrivilegeObject(result, objectType, each, Collections.singletonList(new IdentifierValue(each.getText())));
+            }
+        } else if (null != onObjectClause.qualifiedNameList()) {
+            fillQualifiedNamePrivilegeObjects(result, objectType, onObjectClause.qualifiedNameList());
+        } else {
+            fillPrivilegeLevelObjects(result, objectType, onObjectClause.privilegeLevel());
+        }
+    }
+    
+    private String getObjectType(final OnObjectClauseContext ctx) {
+        if (null != ctx.ALL() || null != ctx.SCHEMA()) {
+            return "SCHEMA";
+        }
+        if (null != ctx.DATABASE()) {
+            return "DATABASE";
+        }
+        if (null != ctx.DOMAIN()) {
+            return "DOMAIN";
+        }
+        if (null != ctx.FUNCTION()) {
+            return "FUNCTION";
+        }
+        if (null != ctx.PROCEDURE()) {
+            return "PROCEDURE";
+        }
+        if (null != ctx.ROUTINE()) {
+            return "ROUTINE";
+        }
+        if (null != ctx.LANGUAGE()) {
+            return "LANGUAGE";
+        }
+        if (null != ctx.LARGE()) {
+            return "LARGE OBJECT";
+        }
+        if (null != ctx.TABLESPACE()) {
+            return "TABLESPACE";
+        }
+        if (null != ctx.TYPE()) {
+            return "TYPE";
+        }
+        if (null != ctx.SEQUENCE()) {
+            return "SEQUENCE";
+        }
+        if (null != ctx.FOREIGN()) {
+            return null == ctx.DATA() ? "FOREIGN SERVER" : "FOREIGN DATA WRAPPER";
+        }
+        return "TABLE";
+    }
+    
+    private void fillNamePrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final String objectType,
+                                          final NameListContext ctx) {
+        if (null != ctx.nameList()) {
+            fillNamePrivilegeObjects(result, objectType, ctx.nameList());
+        }
+        NameContext name = ctx.name();
+        addPrivilegeObject(result, objectType, name, Collections.singletonList(new IdentifierValue(name.getText())));
+    }
+    
+    private List<IdentifierValue> getAnyNameIdentifiers(final AnyNameContext ctx) {
+        List<IdentifierValue> result = new LinkedList<>();
+        result.add(new IdentifierValue(ctx.colId().getText()));
+        if (null != ctx.attrs()) {
+            fillAttrsIdentifiers(result, ctx.attrs());
+        }
+        return result;
+    }
+    
+    private void fillAttrsIdentifiers(final Collection<IdentifierValue> result, final AttrsContext ctx) {
+        if (null != ctx.attrs()) {
+            fillAttrsIdentifiers(result, ctx.attrs());
+        }
+        result.add(new IdentifierValue(ctx.attrName().getText()));
+    }
+    
+    private List<IdentifierValue> getFunctionIdentifiers(final FunctionWithArgtypesContext ctx) {
+        if (null != ctx.funcName()) {
+            return getFunctionIdentifiers(ctx.funcName());
+        }
+        List<IdentifierValue> result = new LinkedList<>();
+        if (null != ctx.typeFuncNameKeyword()) {
+            result.add(new IdentifierValue(ctx.typeFuncNameKeyword().getText()));
+        } else {
+            result.add(new IdentifierValue(ctx.colId().getText()));
+            fillIndirectionIdentifiers(result, ctx.indirection());
+        }
+        return result;
+    }
+    
+    private List<IdentifierValue> getFunctionIdentifiers(final FuncNameContext ctx) {
+        List<IdentifierValue> result = new LinkedList<>();
+        if (null == ctx.typeFunctionName()) {
+            result.add(new IdentifierValue(ctx.colId().getText()));
+            fillIndirectionIdentifiers(result, ctx.indirection());
+            return result;
+        }
+        if (null != ctx.owner()) {
+            result.add(new IdentifierValue(ctx.owner().getText()));
+        }
+        result.add(new IdentifierValue(ctx.typeFunctionName().getText()));
+        return result;
+    }
+    
+    private void fillIndirectionIdentifiers(final Collection<IdentifierValue> result, final IndirectionContext ctx) {
+        if (null == ctx) {
+            return;
+        }
+        if (null != ctx.indirection()) {
+            fillIndirectionIdentifiers(result, ctx.indirection());
+        }
+        if (null != ctx.indirectionEl().attrName()) {
+            result.add(new IdentifierValue(ctx.indirectionEl().attrName().getText()));
+        }
+    }
+    
+    private void fillQualifiedNamePrivilegeObjects(final Collection<PrivilegeObjectSegment> result, final String objectType, final QualifiedNameListContext ctx) {
+        if (null != ctx.qualifiedNameList()) {
+            fillQualifiedNamePrivilegeObjects(result, objectType, ctx.qualifiedNameList());
+        }
+        QualifiedNameContext qualifiedName = ctx.qualifiedName();
+        addSimpleTablePrivilegeObject(result, objectType, (SimpleTableSegment) visit(qualifiedName));
+    }
+    
+    @SuppressWarnings("unchecked")
+    private void fillPrivilegeLevelObjects(final Collection<PrivilegeObjectSegment> result, final String objectType, final PrivilegeLevelContext ctx) {
+        if (null != ctx.tableNames()) {
+            for (SimpleTableSegment each : ((CollectionValue<SimpleTableSegment>) visit(ctx.tableNames())).getValue()) {
+                addSimpleTablePrivilegeObject(result, objectType, each);
+            }
+            return;
+        }
+        List<IdentifierValue> identifiers = new LinkedList<>();
+        if (null != ctx.identifier()) {
+            identifiers.add((IdentifierValue) visit(ctx.identifier()));
+            identifiers.add(new IdentifierValue("*"));
+        } else if (null != ctx.schemaName()) {
+            identifiers.add((IdentifierValue) visit(ctx.schemaName()));
+            identifiers.add(new IdentifierValue(ctx.routineName().getText()));
+        } else {
+            identifiers.add(new IdentifierValue("*"));
+            if (null != ctx.DOT_ASTERISK_()) {
+                identifiers.add(new IdentifierValue("*"));
+            }
+        }
+        addPrivilegeObject(result, objectType, ctx, identifiers);
+    }
+    
+    private void addSimpleTablePrivilegeObject(final Collection<PrivilegeObjectSegment> result, final String objectType, final SimpleTableSegment table) {
+        List<IdentifierValue> identifiers = new LinkedList<>();
+        table.getOwner().ifPresent(owner -> fillOwnerIdentifiers(identifiers, owner));
+        identifiers.add(table.getTableName().getIdentifier());
+        PrivilegeObjectSegment privilegeObject = new PrivilegeObjectSegment(table.getStartIndex(), table.getStopIndex(), objectType);
+        privilegeObject.getIdentifiers().addAll(identifiers);
+        result.add(privilegeObject);
+    }
+    
+    private void fillOwnerIdentifiers(final Collection<IdentifierValue> result, final OwnerSegment owner) {
+        owner.getOwner().ifPresent(each -> fillOwnerIdentifiers(result, each));
+        result.add(owner.getIdentifier());
+    }
+    
+    private void addPrivilegeObject(final Collection<PrivilegeObjectSegment> result, final String objectType, final ParserRuleContext ctx,
+                                    final Collection<IdentifierValue> identifiers) {
+        PrivilegeObjectSegment privilegeObject = new PrivilegeObjectSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), objectType);
+        privilegeObject.getIdentifiers().addAll(identifiers);
+        result.add(privilegeObject);
+    }
+    
     @Override
     public ASTNode visitCreateUser(final CreateUserContext ctx) {
         return new CreateUserStatement(getDatabaseType());
diff --git a/parser/sql/engine/dialect/presto/src/main/java/org/apache/shardingsphere/sql/parser/engine/presto/visitor/statement/type/PrestoDDLStatementVisitor.java b/parser/sql/engine/dialect/presto/src/main/java/org/apache/shardingsphere/sql/parser/engine/presto/visitor/statement/type/PrestoDDLStatementVisitor.java
index 145dbf136b5..5fce5116595 100644
--- a/parser/sql/engine/dialect/presto/src/main/java/org/apache/shardingsphere/sql/parser/engine/presto/visitor/statement/type/PrestoDDLStatementVisitor.java
+++ b/parser/sql/engine/dialect/presto/src/main/java/org/apache/shardingsphere/sql/parser/engine/presto/visitor/statement/type/PrestoDDLStatementVisitor.java
@@ -30,6 +30,7 @@ import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.Create
 import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.DropTableContext;
 import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.DropViewContext;
 import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.FunctionNameContext;
+import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.SelectContext;
 import org.apache.shardingsphere.sql.parser.autogen.PrestoStatementParser.TableElementContext;
 import org.apache.shardingsphere.sql.parser.engine.presto.visitor.statement.PrestoStatementVisitor;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.ddl.CreateDefinitionSegment;
@@ -96,11 +97,16 @@ public final class PrestoDDLStatementVisitor extends PrestoStatementVisitor impl
                 .databaseType(getDatabaseType())
                 .table((SimpleTableSegment) visit(ctx.tableName()))
                 .ifNotExists(null != ctx.ifNotExists())
+                .selectStatement(null == ctx.duplicateAsQueryExpression() ? null : createSelectStatement(ctx.duplicateAsQueryExpression().select()))
                 .columnDefinitions(columnDefinitions)
                 .constraintDefinitions(constraintDefinitions)
                 .build();
     }
     
+    private SelectStatement createSelectStatement(final SelectContext ctx) {
+        return (SelectStatement) new PrestoDMLStatementVisitor(getDatabaseType()).visit(ctx);
+    }
+    
     @Override
     public ASTNode visitCreateDefinitionClause(final CreateDefinitionClauseContext ctx) {
         CollectionValue<CreateDefinitionSegment> result = new CollectionValue<>();
diff --git a/parser/sql/engine/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4 b/parser/sql/engine/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
index 90a8cb74d62..c87a8b097ff 100644
--- a/parser/sql/engine/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
+++ b/parser/sql/engine/dialect/sqlserver/src/main/antlr4/imports/sqlserver/BaseRule.g4
@@ -287,7 +287,8 @@ bitExpr
     ;
 
 simpleExpr
-    : functionCall
+    : nextValueFor
+    | functionCall
     | parameterMarker
     | literals
     | columnName
@@ -306,6 +307,10 @@ simpleExpr
     | matchExpression
     ;
 
+nextValueFor
+    : NEXT VALUE FOR (databaseName DOT_)? sequenceName overClause?
+    ;
+
 functionCall
     : aggregationFunction | specialFunction | regularFunction
     ;
diff --git a/parser/sql/engine/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/engine/sqlserver/visitor/statement/SQLServerStatementVisitor.java b/parser/sql/engine/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/engine/sqlserver/visitor/statement/SQLServerStatementVisitor.java
index cfefb57ecc8..acb77e4f0d2 100644
--- a/parser/sql/engine/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/engine/sqlserver/visitor/statement/SQLServerStatementVisitor.java
+++ b/parser/sql/engine/dialect/sqlserver/src/main/java/org/apache/shardingsphere/sql/parser/engine/sqlserver/visitor/statement/SQLServerStatementVisitor.java
@@ -42,6 +42,8 @@ import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.Bit
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.BooleanLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.BooleanPrimaryContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.CastFunctionContext;
+import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.CaseExpressionContext;
+import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.CaseWhenContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ChangeTableFunctionContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.CharFunctionContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.ColumnNameContext;
@@ -100,6 +102,7 @@ import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.Mer
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.MergeWhenClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.MultipleTableNamesContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.MultipleTablesClauseContext;
+import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.NextValueForContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.NullValueLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.NumberLiteralsContext;
 import org.apache.shardingsphere.sql.parser.autogen.SQLServerStatementParser.OpenDatasourceFunctionContext;
@@ -186,6 +189,7 @@ import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.In
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.exec.ExecSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.CaseWhenExpression;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionWithParamsSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.FunctionSegment;
@@ -649,6 +653,9 @@ public abstract class SQLServerStatementVisitor extends SQLServerStatementBaseVi
         if (null != ctx.literals()) {
             return SQLUtils.createLiteralExpression(visit(ctx.literals()), startIndex, stopIndex, ctx.literals().start.getInputStream().getText(new Interval(startIndex, stopIndex)));
         }
+        if (null != ctx.nextValueFor()) {
+            return visit(ctx.nextValueFor());
+        }
         if (null != ctx.functionCall()) {
             return visit(ctx.functionCall());
         }
@@ -664,11 +671,14 @@ public abstract class SQLServerStatementVisitor extends SQLServerStatementBaseVi
         return visitRemainSimpleExpr(ctx);
     }
     
+    @Override
+    public ASTNode visitNextValueFor(final NextValueForContext ctx) {
+        return new FunctionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), "NEXT VALUE FOR", getOriginalText(ctx));
+    }
+    
     private ASTNode visitRemainSimpleExpr(final SimpleExprContext ctx) {
         if (null != ctx.caseExpression()) {
-            visit(ctx.caseExpression());
-            String text = ctx.start.getInputStream().getText(new Interval(ctx.start.getStartIndex(), ctx.stop.getStopIndex()));
-            return new OtherLiteralValue(text);
+            return visit(ctx.caseExpression());
         }
         for (ExprContext each : ctx.expr()) {
             visit(each);
@@ -680,6 +690,19 @@ public abstract class SQLServerStatementVisitor extends SQLServerStatementBaseVi
         return new CommonExpressionSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), text);
     }
     
+    @Override
+    public ASTNode visitCaseExpression(final CaseExpressionContext ctx) {
+        ExpressionSegment caseExpr = null == ctx.simpleExpr() ? null : (ExpressionSegment) visit(ctx.simpleExpr());
+        Collection<ExpressionSegment> whenExprs = new LinkedList<>();
+        Collection<ExpressionSegment> thenExprs = new LinkedList<>();
+        for (CaseWhenContext each : ctx.caseWhen()) {
+            whenExprs.add((ExpressionSegment) visit(each.expr(0)));
+            thenExprs.add((ExpressionSegment) visit(each.expr(1)));
+        }
+        ExpressionSegment elseExpr = null == ctx.caseElse() ? null : (ExpressionSegment) visit(ctx.caseElse().expr());
+        return new CaseWhenExpression(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), caseExpr, whenExprs, thenExprs, elseExpr, getOriginalText(ctx));
+    }
+    
     @Override
     public final ASTNode visitFunctionCall(final FunctionCallContext ctx) {
         if (null != ctx.aggregationFunction()) {
@@ -1751,7 +1774,7 @@ public abstract class SQLServerStatementVisitor extends SQLServerStatementBaseVi
             return false;
         }
         if (fromSegment instanceof SimpleTableSegment) {
-            return targetName.equalsIgnoreCase(((SimpleTableSegment) fromSegment).getAliasName().orElse(null));
+            return targetName.equalsIgnoreCase(fromSegment.getAliasName().orElse(null));
         }
         if (fromSegment instanceof JoinTableSegment) {
             return isAliasInFromClause(targetTable, targetName, ((JoinTableSegment) fromSegment).getLeft())
diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dcl/PrivilegeObjectSegment.java
similarity index 51%
copy from parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java
copy to parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dcl/PrivilegeObjectSegment.java
index 13ba6535986..489462ec922 100644
--- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java
+++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/segment/dcl/PrivilegeObjectSegment.java
@@ -15,29 +15,28 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl;
+package org.apache.shardingsphere.sql.parser.statement.core.segment.dcl;
 
 import lombok.Getter;
-import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
-import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.SQLStatementAttributes;
-import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.TableSQLStatementAttribute;
+import lombok.RequiredArgsConstructor;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.SQLSegment;
+import org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
 
-import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
- * Grant statement.
+ * Privilege object segment.
  */
+@RequiredArgsConstructor
 @Getter
-public class GrantStatement extends DCLStatement {
+public final class PrivilegeObjectSegment implements SQLSegment {
     
-    private final Collection<SimpleTableSegment> tables;
+    private final int startIndex;
     
-    private final SQLStatementAttributes attributes;
+    private final int stopIndex;
     
-    public GrantStatement(final DatabaseType databaseType, final Collection<SimpleTableSegment> tables) {
-        super(databaseType);
-        this.tables = tables;
-        attributes = new SQLStatementAttributes(new TableSQLStatementAttribute(tables));
-    }
+    private final String objectType;
+    
+    private final List<IdentifierValue> identifiers = new LinkedList<>();
 }
diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java
index 13ba6535986..6fb74f33c76 100644
--- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java
+++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/GrantStatement.java
@@ -19,11 +19,14 @@ package org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl;
 
 import lombok.Getter;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.SQLStatementAttributes;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.TableSQLStatementAttribute;
 
 import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * Grant statement.
@@ -33,6 +36,8 @@ public class GrantStatement extends DCLStatement {
     
     private final Collection<SimpleTableSegment> tables;
     
+    private final List<PrivilegeObjectSegment> privilegeObjects = new LinkedList<>();
+    
     private final SQLStatementAttributes attributes;
     
     public GrantStatement(final DatabaseType databaseType, final Collection<SimpleTableSegment> tables) {
diff --git a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/RevokeStatement.java b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/RevokeStatement.java
index 134d7a37f1e..3397a14d080 100644
--- a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/RevokeStatement.java
+++ b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/statement/type/dcl/RevokeStatement.java
@@ -19,11 +19,14 @@ package org.apache.shardingsphere.sql.parser.statement.core.statement.type.dcl;
 
 import lombok.Getter;
 import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.sql.parser.statement.core.segment.dcl.PrivilegeObjectSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table.SimpleTableSegment;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.SQLStatementAttributes;
 import org.apache.shardingsphere.sql.parser.statement.core.statement.attribute.type.TableSQLStatementAttribute;
 
 import java.util.Collection;
+import java.util.LinkedList;
+import java.util.List;
 
 /**
  * Revoke statement.
@@ -33,6 +36,8 @@ public class RevokeStatement extends DCLStatement {
     
     private final Collection<SimpleTableSegment> tables;
     
+    private final List<PrivilegeObjectSegment> privilegeObjects = new LinkedList<>();
+    
     private final SQLStatementAttributes attributes;
     
     public RevokeStatement(final DatabaseType databaseType, final Collection<SimpleTableSegment> tables) {
diff --git a/test/it/parser/src/main/resources/case/dal/explain.xml b/test/it/parser/src/main/resources/case/dal/explain.xml
index ebd5f5c2435..556f1ae7872 100644
--- a/test/it/parser/src/main/resources/case/dal/explain.xml
+++ b/test/it/parser/src/main/resources/case/dal/explain.xml
@@ -455,7 +455,7 @@
                 <shorthand-projection start-index="8" stop-index="8" />
             </projections>
             <from>
-                <simple-table name="t_order" start-index="8" stop-index="20" />
+                <simple-table name="t_order" start-index="14" stop-index="20" />
             </from>
         </select>
     </explain>
diff --git a/test/it/parser/src/main/resources/case/ddl/create-table.xml b/test/it/parser/src/main/resources/case/ddl/create-table.xml
index ca859553ec2..e9d25435152 100644
--- a/test/it/parser/src/main/resources/case/ddl/create-table.xml
+++ b/test/it/parser/src/main/resources/case/ddl/create-table.xml
@@ -2299,10 +2299,59 @@
 
     <create-table sql-case-id="create_table_with_select_without_query" db-types="Oracle">
         <table name="t_order_new" start-index="13" stop-index="23"/>
+        <select>
+            <projections start-index="35" stop-index="35">
+                <shorthand-projection start-index="35" stop-index="35" />
+            </projections>
+            <from>
+                <simple-table name="t_order" start-index="42" stop-index="48" />
+            </from>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_as_select_with_pivot" db-types="Oracle">
         <table name="pivot_table" start-index="13" stop-index="23"/>
+        <select>
+            <projections start-index="35" stop-index="35">
+                <shorthand-projection start-index="35" stop-index="35" />
+            </projections>
+            <from>
+                <subquery-table start-index="42" stop-index="121">
+                    <subquery>
+                        <select>
+                            <projections start-index="50" stop-index="108">
+                                <expression-projection text="EXTRACT(YEAR FROM order_date)" alias="year" start-index="50" stop-index="83">
+                                    <expr>
+                                        <function function-name="EXTRACT" text="EXTRACT(YEAR FROM order_date)" start-index="50" stop-index="78">
+                                            <parameter>
+                                                <column name="order_date" start-index="68" stop-index="77" />
+                                            </parameter>
+                                        </function>
+                                    </expr>
+                                </expression-projection>
+                                <column-projection name="order_mode" start-index="86" stop-index="95" />
+                                <column-projection name="order_total" start-index="98" stop-index="108" />
+                            </projections>
+                            <from>
+                                <simple-table name="orders" start-index="115" stop-index="120" />
+                            </from>
+                        </select>
+                    </subquery>
+                    <pivot start-index="123" stop-index="206">
+                        <aggregation-columns>
+                            <column name="order_total" start-index="134" stop-index="144" />
+                        </aggregation-columns>
+                        <for-columns>
+                            <column name="order_mode" start-index="151" stop-index="160" />
+                        </for-columns>
+                        <in-columns>
+                            <column name="Store" start-index="166" stop-index="182" />
+                            <column name="Internet" start-index="185" stop-index="204" />
+                        </in-columns>
+                    </pivot>
+                </subquery-table>
+            </from>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_organization_index_parallel_with_select">
@@ -2319,6 +2368,16 @@
         <column-definition start-index="45" stop-index="45">
             <column name="l" start-index="45" stop-index="45" />
         </column-definition>
+        <select>
+            <projections start-index="86" stop-index="86">
+                <shorthand-projection start-index="86" stop-index="86" />
+            </projections>
+            <from>
+                <simple-table name="jobs" start-index="93" stop-index="99">
+                    <owner name="hr" start-index="93" stop-index="94" />
+                </simple-table>
+            </from>
+        </select>
     </create-table>
     
     <create-table sql-case-id="create_table_partition_by_range">
@@ -2588,14 +2647,64 @@
     
     <create-table sql-case-id="create_table_cluster_with_select1">
         <table name="dept_10" start-index="13" stop-index="19" />
+        <select>
+            <projections start-index="65" stop-index="65">
+                <shorthand-projection start-index="65" stop-index="65" />
+            </projections>
+            <from>
+                <simple-table name="employees" start-index="72" stop-index="80" />
+            </from>
+            <where start-index="82" stop-index="105">
+                <expr>
+                    <binary-operation-expression start-index="88" stop-index="105">
+                        <left>
+                            <column name="department_id" start-index="88" stop-index="100" />
+                        </left>
+                        <operator>=</operator>
+                        <right>
+                            <literal-expression value="10" start-index="104" stop-index="105" />
+                        </right>
+                    </binary-operation-expression>
+                </expr>
+            </where>
+        </select>
     </create-table>
     
     <create-table sql-case-id="create_table_cluster_with_select2">
         <table name="dept_20" start-index="13" stop-index="19" />
+        <select>
+            <projections start-index="65" stop-index="65">
+                <shorthand-projection start-index="65" stop-index="65" />
+            </projections>
+            <from>
+                <simple-table name="employees" start-index="72" stop-index="80" />
+            </from>
+            <where start-index="82" stop-index="105">
+                <expr>
+                    <binary-operation-expression start-index="88" stop-index="105">
+                        <left>
+                            <column name="department_id" start-index="88" stop-index="100" />
+                        </left>
+                        <operator>=</operator>
+                        <right>
+                            <literal-expression value="20" start-index="104" stop-index="105" />
+                        </right>
+                    </binary-operation-expression>
+                </expr>
+            </where>
+        </select>
     </create-table>
     
     <create-table sql-case-id="create_table_cluster_with_select3">
         <table name="customers_demo" start-index="13" stop-index="26" />
+        <select>
+            <projections start-index="38" stop-index="38">
+                <shorthand-projection start-index="38" stop-index="38" />
+            </projections>
+            <from>
+                <simple-table name="customers" start-index="45" stop-index="53" />
+            </from>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_with_ref_type_column_department_typ">
@@ -2624,12 +2733,43 @@
 
     <create-table sql-case-id="create_table_with_as_sub_query">
         <table name="employees_temp" start-index="13" stop-index="26"/>
+        <select>
+            <projections start-index="38" stop-index="38">
+                <shorthand-projection start-index="38" stop-index="38" />
+            </projections>
+            <from>
+                <simple-table name="EMPLOYEES" start-index="45" stop-index="53" />
+            </from>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_parallel_with_as_sub_query">
         <table name="admin_emp_dept" start-index="13" stop-index="29">
             <owner name="hr" start-index="13" stop-index="14"/>
         </table>
+        <select>
+            <projections start-index="59" stop-index="59">
+                <shorthand-projection start-index="59" stop-index="59" />
+            </projections>
+            <from>
+                <simple-table name="employees" start-index="66" stop-index="77">
+                    <owner name="hr" start-index="66" stop-index="67" />
+                </simple-table>
+            </from>
+            <where start-index="79" stop-index="102">
+                <expr>
+                    <binary-operation-expression start-index="85" stop-index="102">
+                        <left>
+                            <column name="department_id" start-index="85" stop-index="97" />
+                        </left>
+                        <operator>=</operator>
+                        <right>
+                            <literal-expression value="10" start-index="101" stop-index="102" />
+                        </right>
+                    </binary-operation-expression>
+                </expr>
+            </where>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_with_edge_constraint">
@@ -2655,6 +2795,23 @@
     
     <create-table sql-case-id="create_table_with_builtin_function">
         <table name="tab" start-index="13" stop-index="15"/>
+        <select>
+            <projections start-index="27" stop-index="63">
+                <expression-projection text="DBMS_LOB.GETLENGTH@dbs2(clob_col)" alias="len" start-index="27" stop-index="63">
+                    <expr>
+                        <function function-name="GETLENGTH" text="DBMS_LOB.GETLENGTH@dbs2(clob_col)" start-index="27" stop-index="59">
+                            <owner name="DBMS_LOB" start-index="27" stop-index="34" />
+                            <parameter>
+                                <column name="clob_col" start-index="51" stop-index="58" />
+                            </parameter>
+                        </function>
+                    </expr>
+                </expression-projection>
+            </projections>
+            <from>
+                <simple-table name="tab" start-index="70" stop-index="72" />
+            </from>
+        </select>
     </create-table>
 
     <create-table sql-case-id="create_table_with_autoextend_size">
diff --git a/test/it/parser/src/main/resources/case/ddl/create-view.xml b/test/it/parser/src/main/resources/case/ddl/create-view.xml
index c861ac75dc3..16687cbc034 100644
--- a/test/it/parser/src/main/resources/case/ddl/create-view.xml
+++ b/test/it/parser/src/main/resources/case/ddl/create-view.xml
@@ -23,7 +23,9 @@
             <projections start-index="29" stop-index="49">
                 <expression-projection text="DB29023216.TESTFUNC()" start-index="29" stop-index="49">
                     <expr>
-                        <function function-name="DB29023216.TESTFUNC()" text="DB29023216.TESTFUNC()" start-index="29" stop-index="49" />
+                        <function function-name="TESTFUNC" text="DB29023216.TESTFUNC()" start-index="29" stop-index="49">
+                            <owner name="DB29023216" start-index="29" stop-index="38" />
+                        </function>
                     </expr>
                 </expression-projection>
             </projections>
@@ -35,7 +37,8 @@
             <projections start-index="29" stop-index="54">
                 <expression-projection text="DB29023216.TESTFUNC(NOW())" start-index="29" stop-index="54">
                     <expr>
-                        <function function-name="DB29023216.TESTFUNC(NOW())" text="DB29023216.TESTFUNC(NOW())" start-index="29" stop-index="54">
+                        <function function-name="TESTFUNC" text="DB29023216.TESTFUNC(NOW())" start-index="29" stop-index="54">
+                            <owner name="DB29023216" start-index="29" stop-index="38" />
                             <parameter>
                                 <function function-name="NOW" text="NOW()" start-index="49" stop-index="53" />
                             </parameter>
@@ -51,7 +54,8 @@
             <projections start-index="29" stop-index="56">
                 <expression-projection text="DB29023216.TESTFUNC(1,2,3,4)" start-index="29" stop-index="56">
                     <expr>
-                        <function function-name="DB29023216.TESTFUNC(1,2,3,4)" text="DB29023216.TESTFUNC(1,2,3,4)" start-index="29" stop-index="56">
+                        <function function-name="TESTFUNC" text="DB29023216.TESTFUNC(1,2,3,4)" start-index="29" stop-index="56">
+                            <owner name="DB29023216" start-index="29" stop-index="38" />
                             <parameter>
                                 <literal-expression start-index="49" stop-index="49" value="1" />
                             </parameter>
diff --git a/test/it/parser/src/main/resources/case/dml/select-expression.xml b/test/it/parser/src/main/resources/case/dml/select-expression.xml
index 2de491a2625..b14cc7a590c 100644
--- a/test/it/parser/src/main/resources/case/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-expression.xml
@@ -3420,19 +3420,232 @@
                     </binary-operation-expression>
                 </expr>
             </expression-projection>
-            <expression-projection start-index="67" stop-index="212" alias="max_size" text="CASEdf.max_sizeWHEN0THEN'Autogrowth is off.'WHEN-1THEN'Autogrowth is on.'ELSE'Log file grows to a maximum size of 2 TB.'END">
+            <expression-projection start-index="67" stop-index="212" alias="max_size" text="CASE df.max_size WHEN 0 THEN 'Autogrowth is off.' WHEN -1 THEN 'Autogrowth is on.' ELSE 'Log file grows to a maximum size of 2 TB.' END">
                 <expr>
-                    <common-expression literal-text="CASEdf.max_sizeWHEN0THEN'Autogrowth is off.'WHEN-1THEN'Autogrowth is on.'ELSE'Log file grows to a maximum size of 2 TB.'END" start-index="78" stop-index="212"/>
+                    <case-when-expression start-index="78" stop-index="212">
+                        <case-expr>
+                            <column name="max_size" start-index="83" stop-index="93">
+                                <owner name="df" start-index="83" stop-index="84" />
+                            </column>
+                        </case-expr>
+                        <when-exprs>
+                            <literal-expression value="0" start-index="100" stop-index="100" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Autogrowth is off." start-index="107" stop-index="126" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="-1" start-index="133" stop-index="134" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Autogrowth is on." start-index="141" stop-index="159" />
+                        </then-exprs>
+                        <else-expr>
+                            <literal-expression value="Log file grows to a maximum size of 2 TB." start-index="166" stop-index="208" />
+                        </else-expr>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
-            <expression-projection start-index="215" stop-index="407" alias="growth_value" text="CASEWHENdf.growth=0THENdf.growthWHENdf.growth>0ANDdf.is_percent_growth=0THENdf.growth*1.0/128.0WHENdf.growth>0ANDdf.is_percent_growth=1THENdf.growthEND">
+            <expression-projection start-index="215" stop-index="407" alias="growth_value" text="CASE WHEN df.growth = 0 THEN df.growth WHEN df.growth > 0 AND df.is_percent_growth = 0 THEN df.growth*1.0/128.0 WHEN df.growth > 0 AND df.is_percent_growth = 1 THEN df.growth END">
                 <expr>
-                    <common-expression literal-text="CASEWHENdf.growth=0THENdf.growthWHENdf.growth>0ANDdf.is_percent_growth=0THENdf.growth*1.0/128.0WHENdf.growth>0ANDdf.is_percent_growth=1THENdf.growthEND" start-index="230" stop-index="407"/>
+                    <case-when-expression start-index="230" stop-index="407">
+                        <when-exprs>
+                            <binary-operation-expression start-index="240" stop-index="252">
+                                <left>
+                                    <column name="growth" start-index="240" stop-index="248">
+                                        <owner name="df" start-index="240" stop-index="241" />
+                                    </column>
+                                </left>
+                                <operator>=</operator>
+                                <right>
+                                    <literal-expression value="0" start-index="252" stop-index="252" />
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <column name="growth" start-index="259" stop-index="267">
+                                <owner name="df" start-index="259" stop-index="260" />
+                            </column>
+                        </then-exprs>
+                        <when-exprs>
+                            <binary-operation-expression start-index="274" stop-index="315">
+                                <left>
+                                    <binary-operation-expression start-index="274" stop-index="286">
+                                        <left>
+                                            <column name="growth" start-index="274" stop-index="282">
+                                                <owner name="df" start-index="274" stop-index="275" />
+                                            </column>
+                                        </left>
+                                        <operator>&gt;</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="286" stop-index="286" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>AND</operator>
+                                <right>
+                                    <binary-operation-expression start-index="292" stop-index="315">
+                                        <left>
+                                            <column name="is_percent_growth" start-index="292" stop-index="311">
+                                                <owner name="df" start-index="292" stop-index="293" />
+                                            </column>
+                                        </left>
+                                        <operator>=</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="315" stop-index="315" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <binary-operation-expression start-index="322" stop-index="340">
+                                <left>
+                                    <binary-operation-expression start-index="322" stop-index="334">
+                                        <left>
+                                            <column name="growth" start-index="322" stop-index="330">
+                                                <owner name="df" start-index="322" stop-index="323" />
+                                            </column>
+                                        </left>
+                                        <operator>*</operator>
+                                        <right>
+                                            <literal-expression value="1.0" start-index="332" stop-index="334" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>/</operator>
+                                <right>
+                                    <literal-expression value="128.0" start-index="336" stop-index="340" />
+                                </right>
+                            </binary-operation-expression>
+                        </then-exprs>
+                        <when-exprs>
+                            <binary-operation-expression start-index="347" stop-index="388">
+                                <left>
+                                    <binary-operation-expression start-index="347" stop-index="359">
+                                        <left>
+                                            <column name="growth" start-index="347" stop-index="355">
+                                                <owner name="df" start-index="347" stop-index="348" />
+                                            </column>
+                                        </left>
+                                        <operator>&gt;</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="359" stop-index="359" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>AND</operator>
+                                <right>
+                                    <binary-operation-expression start-index="365" stop-index="388">
+                                        <left>
+                                            <column name="is_percent_growth" start-index="365" stop-index="384">
+                                                <owner name="df" start-index="365" stop-index="366" />
+                                            </column>
+                                        </left>
+                                        <operator>=</operator>
+                                        <right>
+                                            <literal-expression value="1" start-index="388" stop-index="388" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <column name="growth" start-index="395" stop-index="403">
+                                <owner name="df" start-index="395" stop-index="396" />
+                            </column>
+                        </then-exprs>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
-            <expression-projection start-index="410" stop-index="644" alias="growth_increment_unit" text="CASEWHENdf.growth=0THEN'Size is fixed.'WHENdf.growth>0ANDdf.is_percent_growth=0THEN'Growth value is MB.'WHENdf.growth>0ANDdf.is_percent_growth=1THEN'Growth value is a percentage.'END">
+            <expression-projection start-index="410" stop-index="644" alias="growth_increment_unit" text="CASE WHEN df.growth = 0 THEN 'Size is fixed.' WHEN df.growth > 0 AND df.is_percent_growth = 0  THEN 'Growth value is MB.' WHEN df.growth > 0 AND df.is_percent_growth = 1  THEN 'Growth value is a percentage.' END">
                 <expr>
-                    <common-expression literal-text="CASEWHENdf.growth=0THEN'Size is fixed.'WHENdf.growth>0ANDdf.is_percent_growth=0THEN'Growth value is MB.'WHENdf.growth>0ANDdf.is_percent_growth=1THEN'Growth value is a percentage.'END" start-index="434" stop-index="644"/>
+                    <case-when-expression start-index="434" stop-index="644">
+                        <when-exprs>
+                            <binary-operation-expression start-index="444" stop-index="456">
+                                <left>
+                                    <column name="growth" start-index="444" stop-index="452">
+                                        <owner name="df" start-index="444" stop-index="445" />
+                                    </column>
+                                </left>
+                                <operator>=</operator>
+                                <right>
+                                    <literal-expression value="0" start-index="456" stop-index="456" />
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Size is fixed." start-index="463" stop-index="478" />
+                        </then-exprs>
+                        <when-exprs>
+                            <binary-operation-expression start-index="485" stop-index="526">
+                                <left>
+                                    <binary-operation-expression start-index="485" stop-index="497">
+                                        <left>
+                                            <column name="growth" start-index="485" stop-index="493">
+                                                <owner name="df" start-index="485" stop-index="486" />
+                                            </column>
+                                        </left>
+                                        <operator>&gt;</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="497" stop-index="497" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>AND</operator>
+                                <right>
+                                    <binary-operation-expression start-index="503" stop-index="526">
+                                        <left>
+                                            <column name="is_percent_growth" start-index="503" stop-index="522">
+                                                <owner name="df" start-index="503" stop-index="504" />
+                                            </column>
+                                        </left>
+                                        <operator>=</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="526" stop-index="526" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Growth value is MB." start-index="534" stop-index="554" />
+                        </then-exprs>
+                        <when-exprs>
+                            <binary-operation-expression start-index="561" stop-index="602">
+                                <left>
+                                    <binary-operation-expression start-index="561" stop-index="573">
+                                        <left>
+                                            <column name="growth" start-index="561" stop-index="569">
+                                                <owner name="df" start-index="561" stop-index="562" />
+                                            </column>
+                                        </left>
+                                        <operator>&gt;</operator>
+                                        <right>
+                                            <literal-expression value="0" start-index="573" stop-index="573" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>AND</operator>
+                                <right>
+                                    <binary-operation-expression start-index="579" stop-index="602">
+                                        <left>
+                                            <column name="is_percent_growth" start-index="579" stop-index="598">
+                                                <owner name="df" start-index="579" stop-index="580" />
+                                            </column>
+                                        </left>
+                                        <operator>=</operator>
+                                        <right>
+                                            <literal-expression value="1" start-index="602" stop-index="602" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Growth value is a percentage." start-index="610" stop-index="640" />
+                        </then-exprs>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
         </projections>
diff --git a/test/it/parser/src/main/resources/case/dml/select-into.xml b/test/it/parser/src/main/resources/case/dml/select-into.xml
index cf64c101d1f..d8ccb43d755 100644
--- a/test/it/parser/src/main/resources/case/dml/select-into.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-into.xml
@@ -97,6 +97,7 @@
         <limit start-index="22" stop-index="28">
             <row-count value="2" parameter-index="0" start-index="28" stop-index="28" />
         </limit>
+        <outfile start-index="30" stop-index="56" file-path="/tmp/tmp.txt" />
     </select>
 
     <select sql-case-id="select_into_out_file_with_charset" parameters="2">
@@ -109,6 +110,7 @@
         <limit start-index="22" stop-index="28">
             <row-count value="2" parameter-index="0" start-index="28" stop-index="28" />
         </limit>
+        <outfile start-index="30" stop-index="75" file-path="/tmp/tmp.txt" />
     </select>
 
     <select sql-case-id="select_into_out_file_with_fields" parameters="2">
@@ -121,6 +123,7 @@
         <limit start-index="22" stop-index="28">
             <row-count value="2" parameter-index="0" start-index="28" stop-index="28" />
         </limit>
+        <outfile start-index="30" stop-index="109" file-path="/tmp/tmp.txt" />
     </select>
 
     <select sql-case-id="select_into_out_file_with_fields_and_escaped" parameters="2">
@@ -134,6 +137,7 @@
         <limit start-index="36" stop-index="42">
             <row-count value="2" parameter-index="0" start-index="42" stop-index="42" />
         </limit>
+        <outfile start-index="44" stop-index="139" file-path="/tmp/tmp.txt" />
     </select>
 
     <select sql-case-id="select_into_out_file_with_lines" parameters="2">
@@ -146,6 +150,7 @@
         <limit start-index="22" stop-index="28">
             <row-count value="2" parameter-index="0" start-index="28" stop-index="28" />
         </limit>
+        <outfile start-index="30" stop-index="82" file-path="/tmp/tmp.txt" />
     </select>
 
     <select sql-case-id="select_into_with_lock_after_into" parameters="1">
diff --git a/test/it/parser/src/main/resources/case/dml/select-join.xml b/test/it/parser/src/main/resources/case/dml/select-join.xml
index 574d4466b0d..80201d83c86 100644
--- a/test/it/parser/src/main/resources/case/dml/select-join.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-join.xml
@@ -1941,9 +1941,39 @@
                     </function>
                 </expr>
             </expression-projection>
-            <expression-projection text="CASEtat.transaction_typeWHEN1THEN'Read/write transaction'WHEN2THEN'Read-only transaction'WHEN3THEN'System transaction'WHEN4THEN'Distributed transaction'END" start-index="175" stop-index="367" alias="transaction_type">
+            <expression-projection text="CASE tat.transaction_type  WHEN 1 THEN 'Read/write transaction' WHEN 2 THEN 'Read-only transaction' WHEN 3 THEN 'System transaction' WHEN 4 THEN 'Distributed transaction' END" start-index="175" stop-index="367" alias="transaction_type">
                 <expr>
-                    <common-expression literal-text="CASEtat.transaction_typeWHEN1THEN'Read/write transaction'WHEN2THEN'Read-only transaction'WHEN3THEN'System transaction'WHEN4THEN'Distributed transaction'END" start-index="194" stop-index="367"/>
+                    <case-when-expression start-index="194" stop-index="367">
+                        <case-expr>
+                            <column name="transaction_type" start-index="199" stop-index="218">
+                                <owner name="tat" start-index="199" stop-index="201" />
+                            </column>
+                        </case-expr>
+                        <when-exprs>
+                            <literal-expression value="1" start-index="226" stop-index="226" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Read/write transaction" start-index="233" stop-index="256" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="2" start-index="263" stop-index="263" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Read-only transaction" start-index="270" stop-index="292" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="3" start-index="299" stop-index="299" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="System transaction" start-index="306" stop-index="325" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="4" start-index="332" stop-index="332" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="Distributed transaction" start-index="339" stop-index="363" />
+                        </then-exprs>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
             <column-projection name="event_info" start-index="370" stop-index="397" alias="input_buffer">
@@ -1952,9 +1982,69 @@
             <column-projection name="transaction_uow" start-index="400" stop-index="418">
                 <owner name="tat" start-index="400" stop-index="402"/>
             </column-projection>
-            <expression-projection text="CASEtat.transaction_stateWHEN0THEN'The transaction has not been completely initialized yet.'WHEN1THEN'The transaction has been initialized but has not started.'WHEN2THEN'The transaction is active - has not been committed or rolled back.'WHEN3THEN'The transaction has ended. This is used for read-only transactions.'WHEN4THEN'The commit process has been initiated on the distributed transaction.'WHEN5THEN'The transaction is in a prepared state and wai [...]
+            <expression-projection text="CASE tat.transaction_state WHEN 0 THEN 'The transaction has not been completely initialized yet.' WHEN 1 THEN 'The transaction has been initialized but has not started.' WHEN 2 THEN 'The transaction is active - has not been committed or rolled back.' WHEN 3 THEN 'The transaction has ended. This is used for read-only transactions.' WHEN 4 THEN 'The commit process has been initiated on the distributed transaction.' WHEN 5 THEN 'The transaction is in [...]
                 <expr>
-                    <common-expression literal-text="CASEtat.transaction_stateWHEN0THEN'The transaction has not been completely initialized yet.'WHEN1THEN'The transaction has been initialized but has not started.'WHEN2THEN'The transaction is active - has not been committed or rolled back.'WHEN3THEN'The transaction has ended. This is used for read-only transactions.'WHEN4THEN'The commit process has been initiated on the distributed transaction.'WHEN5THEN'The transaction is in a prepared s [...]
+                    <case-when-expression start-index="442" stop-index="1092">
+                        <case-expr>
+                            <column name="transaction_state" start-index="447" stop-index="467">
+                                <owner name="tat" start-index="447" stop-index="449" />
+                            </column>
+                        </case-expr>
+                        <when-exprs>
+                            <literal-expression value="0" start-index="474" stop-index="474" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction has not been completely initialized yet." start-index="481" stop-index="538" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="1" start-index="545" stop-index="545" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction has been initialized but has not started." start-index="552" stop-index="610" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="2" start-index="617" stop-index="617" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction is active - has not been committed or rolled back." start-index="624" stop-index="691" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="3" start-index="698" stop-index="698" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction has ended. This is used for read-only transactions." start-index="705" stop-index="773" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="4" start-index="780" stop-index="780" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The commit process has been initiated on the distributed transaction." start-index="787" stop-index="857" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="5" start-index="864" stop-index="864" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction is in a prepared state and waiting resolution." start-index="871" stop-index="934" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="6" start-index="941" stop-index="941" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction has been committed." start-index="948" stop-index="984" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="7" start-index="991" stop-index="991" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction is being rolled back." start-index="998" stop-index="1036" />
+                        </then-exprs>
+                        <when-exprs>
+                            <literal-expression value="8" start-index="1043" stop-index="1043" />
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="The transaction has been rolled back." start-index="1050" stop-index="1088" />
+                        </then-exprs>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
             <column-projection name="name" start-index="1095" stop-index="1121" alias="transaction_name">
@@ -2226,7 +2316,28 @@
                                                                     <binary-operation-expression start-index="249" stop-index="370">
                                                                         <operator>-</operator>
                                                                         <left>
-                                                                            <common-expression literal-text="CASEstatement_end_offsetWHEN-1THENDATALENGTH(ST.text)ELSEreq.statement_end_offsetEND" start-index="249" stop-index="341"/>
+                                                                            <case-when-expression start-index="249" stop-index="341">
+                                                                                <case-expr>
+                                                                                    <column name="statement_end_offset" start-index="254" stop-index="273" />
+                                                                                </case-expr>
+                                                                                <when-exprs>
+                                                                                    <literal-expression value="-1" start-index="280" stop-index="281" />
+                                                                                </when-exprs>
+                                                                                <then-exprs>
+                                                                                    <function function-name="DATALENGTH" text="DATALENGTH(ST.text)" start-index="288" stop-index="306">
+                                                                                        <parameter>
+                                                                                            <column name="text" start-index="299" stop-index="305">
+                                                                                                <owner name="ST" start-index="299" stop-index="300" />
+                                                                                            </column>
+                                                                                        </parameter>
+                                                                                    </function>
+                                                                                </then-exprs>
+                                                                                <else-expr>
+                                                                                    <column name="statement_end_offset" start-index="314" stop-index="337">
+                                                                                        <owner name="req" start-index="314" stop-index="316" />
+                                                                                    </column>
+                                                                                </else-expr>
+                                                                            </case-when-expression>
                                                                         </left>
                                                                         <right>
                                                                             <column name="statement_start_offset" start-index="345" stop-index="370">
diff --git a/test/it/parser/src/main/resources/case/dml/select.xml b/test/it/parser/src/main/resources/case/dml/select.xml
index eecc420232b..041a96111c4 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -3882,7 +3882,7 @@
             <shorthand-projection start-index="0" stop-index="0" />
         </projections>
         <from>
-            <simple-table name="t_order" start-index="0" stop-index="12" />
+            <simple-table name="t_order" start-index="6" stop-index="12" />
         </from>
     </select>
 
@@ -9961,7 +9961,30 @@
                                                                 <left>
                                                                     <binary-operation-expression text="CASE [req].[statement_end_offset] WHEN -1 THEN DATALENGTH([ST].[text]) ELSE [req].[statement_end_offset] END - [req].[statement_start_offset]" start-index="234" stop-index="374">
                                                                         <left>
-                                                                            <common-expression text="CASE[req].[statement_end_offset]WHEN-1THENDATALENGTH([ST].[text])ELSE[req].[statement_end_offset]END" start-index="234" stop-index="341" />
+                                                                            <case-when-expression start-index="234" stop-index="341">
+                                                                                <case-expr>
+                                                                                    <column name="statement_end_offset" start-index="239" stop-index="266" start-delimiter="[" end-delimiter="]">
+                                                                                        <owner name="req" start-index="239" stop-index="243" start-delimiter="[" end-delimiter="]" />
+                                                                                    </column>
+                                                                                </case-expr>
+                                                                                <when-exprs>
+                                                                                    <literal-expression value="-1" start-index="273" stop-index="274" />
+                                                                                </when-exprs>
+                                                                                <then-exprs>
+                                                                                    <function function-name="DATALENGTH" text="DATALENGTH([ST].[text])" start-index="281" stop-index="303">
+                                                                                        <parameter>
+                                                                                            <column name="text" start-index="292" stop-index="302" start-delimiter="[" end-delimiter="]">
+                                                                                                <owner name="ST" start-index="292" stop-index="295" start-delimiter="[" end-delimiter="]" />
+                                                                                            </column>
+                                                                                        </parameter>
+                                                                                    </function>
+                                                                                </then-exprs>
+                                                                                <else-expr>
+                                                                                    <column name="statement_end_offset" start-index="310" stop-index="337" start-delimiter="[" end-delimiter="]">
+                                                                                        <owner name="req" start-index="310" stop-index="314" start-delimiter="[" end-delimiter="]" />
+                                                                                    </column>
+                                                                                </else-expr>
+                                                                            </case-when-expression>
                                                                         </left>
                                                                         <right>
                                                                             <column name="statement_start_offset" start-index="345" stop-index="374" start-delimiter="[" end-delimiter="]">
@@ -10065,9 +10088,47 @@
                 </function>
             </expression-projection>
             <column-projection name="max_length" start-index="75" stop-index="84"/>
-            <expression-projection text="CASEWHENmax_length=-1ANDTYPE_NAME(user_type_id)&lt;&gt;'xml'THEN1ELSE0END" start-index="86" stop-index="176" alias="(max)" start-delimiter="[" end-delimiter="]">
+            <expression-projection text="CASE WHEN max_length = -1 AND TYPE_NAME(user_type_id) &lt;&gt; 'xml' THEN 1 ELSE 0 END" start-index="86" stop-index="176" alias="(max)" start-delimiter="[" end-delimiter="]">
                 <expr>
-                    <common-expression text="CASEWHENmax_length=-1ANDTYPE_NAME(user_type_id)&lt;&gt;'xml'THEN1ELSE0END" start-index="86" stop-index="165"/>
+                    <case-when-expression start-index="86" stop-index="165">
+                        <when-exprs>
+                            <binary-operation-expression start-index="96" stop-index="147">
+                                <left>
+                                    <binary-operation-expression start-index="96" stop-index="110">
+                                        <left>
+                                            <column name="max_length" start-index="96" stop-index="105" />
+                                        </left>
+                                        <operator>=</operator>
+                                        <right>
+                                            <literal-expression value="-1" start-index="109" stop-index="110" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </left>
+                                <operator>AND</operator>
+                                <right>
+                                    <binary-operation-expression start-index="116" stop-index="147">
+                                        <left>
+                                            <function function-name="TYPE_NAME" text="TYPE_NAME(user_type_id)" start-index="116" stop-index="138">
+                                                <parameter>
+                                                    <column name="user_type_id" start-index="126" stop-index="137" />
+                                                </parameter>
+                                            </function>
+                                        </left>
+                                        <operator>&lt;&gt;</operator>
+                                        <right>
+                                            <literal-expression value="xml" start-index="143" stop-index="147" />
+                                        </right>
+                                    </binary-operation-expression>
+                                </right>
+                            </binary-operation-expression>
+                        </when-exprs>
+                        <then-exprs>
+                            <literal-expression value="1" start-index="154" stop-index="154" />
+                        </then-exprs>
+                        <else-expr>
+                            <literal-expression value="0" start-index="161" stop-index="161" />
+                        </else-expr>
+                    </case-when-expression>
                 </expr>
             </expression-projection>
         </projections>
diff --git a/test/it/parser/src/main/resources/case/dml/table.xml b/test/it/parser/src/main/resources/case/dml/table.xml
index 811d488247b..178d134d616 100644
--- a/test/it/parser/src/main/resources/case/dml/table.xml
+++ b/test/it/parser/src/main/resources/case/dml/table.xml
@@ -22,7 +22,7 @@
             <shorthand-projection start-index="0" stop-index="0" />
         </projections>
         <from>
-            <simple-table name="f" start-index="0" stop-index="6" />
+            <simple-table name="f" start-index="6" stop-index="6" />
         </from>
     </select>
 
@@ -31,7 +31,7 @@
             <shorthand-projection start-index="0" stop-index="0" />
         </projections>
         <from>
-            <simple-table name="t_order" start-index="0" stop-index="12" />
+            <simple-table name="t_order" start-index="6" stop-index="12" />
         </from>
         <order-by>
             <column-item name="order_id" start-index="23" stop-index="30" />
@@ -47,7 +47,7 @@
             <shorthand-projection start-index="0" stop-index="0" />
         </projections>
         <from>
-            <simple-table name="T1" start-index="0" stop-index="7" />
+            <simple-table name="T1" start-index="6" stop-index="7" />
         </from>
         <combine combine-type="UNION" start-index="0" stop-index="22">
             <left>
@@ -55,7 +55,7 @@
                     <shorthand-projection start-index="0" stop-index="0" />
                 </projections>
                 <from>
-                    <simple-table name="T1" start-index="0" stop-index="7" />
+                    <simple-table name="T1" start-index="6" stop-index="7" />
                 </from>
             </left>
             <right>
@@ -63,7 +63,7 @@
                     <shorthand-projection start-index="15" stop-index="15" />
                 </projections>
                 <from>
-                    <simple-table name="T2" start-index="15" stop-index="22" />
+                    <simple-table name="T2" start-index="21" stop-index="22" />
                 </from>
             </right>
         </combine>
@@ -81,7 +81,7 @@
                             <shorthand-projection start-index="15" stop-index="15" />
                         </projections>
                         <from>
-                            <simple-table name="t0" start-index="15" stop-index="22" />
+                            <simple-table name="t0" start-index="21" stop-index="22" />
                         </from>
                     </select>
                 </subquery>