You are viewing a plain text version of this content. The canonical link for it is here.
Posted to notifications@shardingsphere.apache.org by du...@apache.org on 2023/04/18 01:39:03 UTC

[shardingsphere] branch master updated: Fix variable was not parsed into VariableSegment (#25200)

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

duanzhengqiang 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 f015abb3d61 Fix variable was not parsed into VariableSegment (#25200)
f015abb3d61 is described below

commit f015abb3d617b4877afa687649c7b4b96e089db5
Author: 吴伟杰 <wu...@apache.org>
AuthorDate: Tue Apr 18 09:38:55 2023 +0800

    Fix variable was not parsed into VariableSegment (#25200)
    
    * Fix variable was not parsed into VariableSegment
    
    * Refactor VariableSegment
    
    * Complete tests for VariableSegment
    
    * Fix failed to parse scope of system variable
    
    * Add parser test cases for select system variable
---
 .../admin/MySQLSetVariableAdminExecutor.java       |  4 +-
 .../MySQLSetVariableAdminExecutorTest.java         |  6 +--
 .../PostgreSQLSetVariableAdminExecutorTest.java    |  3 +-
 .../command/query/extended/PortalTest.java         |  2 +-
 .../src/main/antlr4/imports/mysql/BaseRule.g4      |  7 ++-
 .../visitor/format/impl/MySQLFormatSQLVisitor.java |  7 +--
 .../impl/MySQLDALStatementSQLVisitor.java          | 57 +++++-----------------
 .../statement/impl/MySQLStatementSQLVisitor.java   | 31 ++++++++++++
 .../impl/OpenGaussDALStatementSQLVisitor.java      |  6 +--
 .../impl/PostgreSQLDALStatementSQLVisitor.java     | 10 +---
 .../sql/common/segment/dal/VariableSegment.java    | 23 +++++++--
 .../segment/expression/ExpressionAssert.java       | 13 +++++
 .../dal/impl/SetParameterStatementAssert.java      |  2 +-
 .../jaxb/segment/impl/expr/ExpectedExpression.java |  3 ++
 .../segment/impl/expr/ExpectedVariableSegment.java | 16 +++---
 .../main/resources/case/dml/select-expression.xml  |  2 +-
 .../parser/src/main/resources/case/dml/select.xml  | 20 ++++++++
 .../main/resources/sql/supported/dml/select.xml    |  1 +
 18 files changed, 128 insertions(+), 85 deletions(-)

diff --git a/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLSetVariableAdminExecutor.java b/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLSetVariableAdminExecutor.java
index c8bf5f8e2f5..31759684e2e 100644
--- a/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLSetVariableAdminExecutor.java
+++ b/proxy/backend/type/mysql/src/main/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/MySQLSetVariableAdminExecutor.java
@@ -62,12 +62,12 @@ public final class MySQLSetVariableAdminExecutor implements DatabaseAdminExecuto
     }
     
     private Map<String, String> extractSessionVariables() {
-        return setStatement.getVariableAssigns().stream().filter(each -> !"global".equalsIgnoreCase(each.getVariable().getScope()))
+        return setStatement.getVariableAssigns().stream().filter(each -> !"global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
                 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue));
     }
     
     private Map<String, String> extractGlobalVariables() {
-        return setStatement.getVariableAssigns().stream().filter(each -> "global".equalsIgnoreCase(each.getVariable().getScope()))
+        return setStatement.getVariableAssigns().stream().filter(each -> "global".equalsIgnoreCase(each.getVariable().getScope().orElse("")))
                 .collect(Collectors.toMap(each -> each.getVariable().getVariable(), VariableAssignSegment::getAssignValue, (oldValue, newValue) -> newValue, LinkedHashMap::new));
     }
     
diff --git a/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/MySQLSetVariableAdminExecutorTest.java b/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/MySQLSetVariableAdminExecutorTest.java
index 7e9e1597b28..d54286cb6e0 100644
--- a/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/MySQLSetVariableAdminExecutorTest.java
+++ b/proxy/backend/type/mysql/src/test/java/org/apache/shardingsphere/proxy/backend/mysql/handler/admin/executor/MySQLSetVariableAdminExecutorTest.java
@@ -71,14 +71,12 @@ class MySQLSetVariableAdminExecutorTest {
     
     private SetStatement prepareSetStatement() {
         VariableAssignSegment setGlobalMaxConnectionAssignSegment = new VariableAssignSegment();
-        VariableSegment maxConnectionVariableSegment = new VariableSegment();
+        VariableSegment maxConnectionVariableSegment = new VariableSegment(0, 0, "max_connections");
         maxConnectionVariableSegment.setScope("global");
-        maxConnectionVariableSegment.setVariable("max_connections");
         setGlobalMaxConnectionAssignSegment.setVariable(maxConnectionVariableSegment);
         setGlobalMaxConnectionAssignSegment.setAssignValue("151");
         VariableAssignSegment setTestFixtureAssignSegment = new VariableAssignSegment();
-        VariableSegment testFixtureSegment = new VariableSegment();
-        testFixtureSegment.setVariable("test_fixture");
+        VariableSegment testFixtureSegment = new VariableSegment(0, 0, "test_fixture");
         setTestFixtureAssignSegment.setVariable(testFixtureSegment);
         setTestFixtureAssignSegment.setAssignValue("'value'");
         SetStatement result = new MySQLSetStatement();
diff --git a/proxy/backend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/backend/postgresql/handler/admin/PostgreSQLSetVariableAdminExecutorTest.java b/proxy/backend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/backend/postgresql/handler/admin/PostgreSQLSetVariableAdminExecutorTest.java
index b0cae497ff3..d049ab866b1 100644
--- a/proxy/backend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/backend/postgresql/handler/admin/PostgreSQLSetVariableAdminExecutorTest.java
+++ b/proxy/backend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/backend/postgresql/handler/admin/PostgreSQLSetVariableAdminExecutorTest.java
@@ -33,8 +33,7 @@ class PostgreSQLSetVariableAdminExecutorTest {
     @Test
     void assertExecute() {
         VariableAssignSegment variableAssignSegment = new VariableAssignSegment();
-        VariableSegment variable = new VariableSegment();
-        variable.setVariable("key");
+        VariableSegment variable = new VariableSegment(0, 0, "key");
         variableAssignSegment.setVariable(variable);
         variableAssignSegment.setAssignValue("value");
         PostgreSQLSetStatement setStatement = new PostgreSQLSetStatement();
diff --git a/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PortalTest.java b/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PortalTest.java
index a738374a738..76e32ac8b05 100644
--- a/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PortalTest.java
+++ b/proxy/frontend/type/postgresql/src/test/java/org/apache/shardingsphere/proxy/frontend/postgresql/command/query/extended/PortalTest.java
@@ -226,7 +226,7 @@ class PortalTest {
         String sql = "set client_encoding = utf8";
         PostgreSQLSetStatement setStatement = new PostgreSQLSetStatement();
         VariableAssignSegment variableAssignSegment = new VariableAssignSegment();
-        variableAssignSegment.setVariable(new VariableSegment());
+        variableAssignSegment.setVariable(new VariableSegment(0, 0, "client_encoding"));
         setStatement.getVariableAssigns().add(variableAssignSegment);
         PostgreSQLServerPreparedStatement preparedStatement = new PostgreSQLServerPreparedStatement(sql, new CommonSQLStatementContext<>(setStatement), Collections.emptyList());
         Portal portal = new Portal("", preparedStatement, Collections.emptyList(), Collections.emptyList(), backendConnection);
diff --git a/sql-parser/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4 b/sql-parser/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
index 800281055bc..c261f1434c1 100644
--- a/sql-parser/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
+++ b/sql-parser/dialect/mysql/src/main/antlr4/imports/mysql/BaseRule.g4
@@ -582,7 +582,12 @@ userVariable
     ;
     
 systemVariable
-    : AT_ AT_ systemVariableScope=(GLOBAL | SESSION | LOCAL)? textOrIdentifier (DOT_ identifier)?
+    : AT_ AT_ (systemVariableScope=(GLOBAL | SESSION | LOCAL) DOT_)? rvalueSystemVariable
+    ;
+    
+rvalueSystemVariable
+    : textOrIdentifier
+    | textOrIdentifier DOT_ identifier
     ;
     
 setSystemVariable
diff --git a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/format/impl/MySQLFormatSQLVisitor.java b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/format/impl/MySQLFormatSQLVisitor.java
index 3d0a9d8acf1..cd7b92f80af 100644
--- a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/format/impl/MySQLFormatSQLVisitor.java
+++ b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/format/impl/MySQLFormatSQLVisitor.java
@@ -690,11 +690,12 @@ public abstract class MySQLFormatSQLVisitor extends MySQLStatementBaseVisitor<St
         formatPrint("@@");
         if (null != ctx.systemVariableScope) {
             formatPrint(upperCase ? ctx.systemVariableScope.getText().toUpperCase() : ctx.systemVariableScope.getText().toLowerCase());
+            formatPrint(".");
         }
-        visit(ctx.textOrIdentifier());
-        if (null != ctx.DOT_()) {
+        visit(ctx.rvalueSystemVariable().textOrIdentifier());
+        if (null != ctx.rvalueSystemVariable().DOT_()) {
             formatPrint(".");
-            visit(ctx.identifier());
+            visit(ctx.rvalueSystemVariable().identifier());
         }
         return result.toString();
     }
diff --git a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLDALStatementSQLVisitor.java b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLDALStatementSQLVisitor.java
index d05a6202ca5..3fe201370bc 100644
--- a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLDALStatementSQLVisitor.java
+++ b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLDALStatementSQLVisitor.java
@@ -112,14 +112,11 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShowVar
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShowWarningsContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShowWhereClauseContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ShutdownContext;
-import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SystemVariableContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableNameContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TablesOptionContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UninstallComponentContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UninstallPluginContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UseContext;
-import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UserVariableContext;
-import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.VariableContext;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.FromSchemaSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.FromTableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.ShowFilterSegment;
@@ -912,9 +909,8 @@ public final class MySQLDALStatementSQLVisitor extends MySQLStatementSQLVisitor
             VariableAssignSegment variableAssign = new VariableAssignSegment();
             variableAssign.setStartIndex(ctx.start.getStartIndex());
             variableAssign.setStopIndex(ctx.setExprOrDefault().stop.getStopIndex());
-            VariableSegment variable = new VariableSegment();
+            VariableSegment variable = new VariableSegment(ctx.internalVariableName().start.getStartIndex(), ctx.internalVariableName().stop.getStopIndex(), ctx.internalVariableName().getText());
             variable.setScope(ctx.optionType().getText());
-            variable.setVariable(ctx.internalVariableName().getText());
             variableAssign.setVariable(variable);
             variableAssign.setAssignValue(ctx.setExprOrDefault().getText());
             result.add(variableAssign);
@@ -931,21 +927,18 @@ public final class MySQLDALStatementSQLVisitor extends MySQLStatementSQLVisitor
         VariableAssignSegment result = new VariableAssignSegment();
         result.setStartIndex(ctx.start.getStartIndex());
         result.setStopIndex(ctx.stop.getStopIndex());
-        VariableSegment variable = new VariableSegment();
         if (null != ctx.NAMES()) {
-            variable.setVariable("charset");
-            result.setVariable(variable);
+            result.setVariable(new VariableSegment(ctx.NAMES().getSymbol().getStartIndex(), ctx.NAMES().getSymbol().getStopIndex(), "charset"));
             result.setAssignValue(ctx.charsetName().getText());
         } else if (null != ctx.internalVariableName()) {
-            variable.setVariable(ctx.internalVariableName().getText());
-            result.setVariable(variable);
+            result.setVariable(new VariableSegment(ctx.internalVariableName().start.getStartIndex(), ctx.internalVariableName().stop.getStopIndex(), ctx.internalVariableName().getText()));
             result.setAssignValue(ctx.setExprOrDefault().getText());
         } else if (null != ctx.userVariable()) {
-            variable.setVariable(ctx.userVariable().getText());
-            result.setVariable(variable);
+            result.setVariable(new VariableSegment(ctx.userVariable().start.getStartIndex(), ctx.userVariable().stop.getStopIndex(), ctx.userVariable().getText()));
             result.setAssignValue(ctx.expr().getText());
         } else if (null != ctx.setSystemVariable()) {
-            variable.setVariable(ctx.setSystemVariable().internalVariableName().getText());
+            VariableSegment variable = new VariableSegment(
+                    ctx.setSystemVariable().start.getStartIndex(), ctx.setSystemVariable().stop.getStopIndex(), ctx.setSystemVariable().internalVariableName().getText());
             result.setVariable(variable);
             result.setAssignValue(ctx.setExprOrDefault().getText());
             OptionTypeContext optionType = ctx.setSystemVariable().optionType();
@@ -955,15 +948,14 @@ public final class MySQLDALStatementSQLVisitor extends MySQLStatementSQLVisitor
     }
     
     private VariableAssignSegment getVariableAssign(final OptionValueContext ctx) {
-        VariableAssignSegment result = new VariableAssignSegment();
-        result.setStartIndex(ctx.start.getStartIndex());
-        result.setStopIndex(ctx.stop.getStopIndex());
-        VariableSegment variable = new VariableSegment();
         if (null != ctx.optionValueNoOptionType()) {
             return getVariableAssign(ctx.optionValueNoOptionType());
         }
+        VariableAssignSegment result = new VariableAssignSegment();
+        result.setStartIndex(ctx.start.getStartIndex());
+        result.setStopIndex(ctx.stop.getStopIndex());
+        VariableSegment variable = new VariableSegment(ctx.internalVariableName().start.getStartIndex(), ctx.internalVariableName().stop.getStopIndex(), ctx.internalVariableName().getText());
         variable.setScope(ctx.optionType().getText());
-        variable.setVariable(ctx.internalVariableName().getText());
         result.setVariable(variable);
         result.setAssignValue(ctx.setExprOrDefault().getText());
         return result;
@@ -972,9 +964,10 @@ public final class MySQLDALStatementSQLVisitor extends MySQLStatementSQLVisitor
     @Override
     public ASTNode visitSetCharacter(final SetCharacterContext ctx) {
         VariableAssignSegment characterSet = new VariableAssignSegment();
-        VariableSegment variable = new VariableSegment();
+        int startIndex = null != ctx.CHARSET() ? ctx.CHARSET().getSymbol().getStartIndex() : ctx.CHARACTER().getSymbol().getStartIndex();
+        int stopIndex = null != ctx.CHARSET() ? ctx.CHARSET().getSymbol().getStopIndex() : ctx.SET(1).getSymbol().getStopIndex();
         String variableName = (null != ctx.CHARSET()) ? ctx.CHARSET().getText() : "charset";
-        variable.setVariable(variableName);
+        VariableSegment variable = new VariableSegment(startIndex, stopIndex, variableName);
         characterSet.setVariable(variable);
         String assignValue = (null != ctx.DEFAULT()) ? ctx.DEFAULT().getText() : ctx.charsetName().getText();
         characterSet.setAssignValue(assignValue);
@@ -983,30 +976,6 @@ public final class MySQLDALStatementSQLVisitor extends MySQLStatementSQLVisitor
         return result;
     }
     
-    @Override
-    public ASTNode visitVariable(final VariableContext ctx) {
-        return super.visitVariable(ctx);
-    }
-    
-    @Override
-    public ASTNode visitUserVariable(final UserVariableContext ctx) {
-        VariableSegment result = new VariableSegment();
-        result.setStartIndex(ctx.start.getStartIndex());
-        result.setStopIndex(ctx.stop.getStopIndex());
-        result.setVariable(ctx.textOrIdentifier().getText());
-        return result;
-    }
-    
-    @Override
-    public ASTNode visitSystemVariable(final SystemVariableContext ctx) {
-        VariableSegment result = new VariableSegment();
-        result.setScope(ctx.systemVariableScope.getText());
-        result.setStartIndex(ctx.start.getStartIndex());
-        result.setStopIndex(ctx.stop.getStopIndex());
-        result.setVariable(ctx.textOrIdentifier().getText());
-        return result;
-    }
-    
     @Override
     public ASTNode visitFromSchema(final FromSchemaContext ctx) {
         return new FromSchemaSegment(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), (DatabaseSegment) visit(ctx.schemaName()));
diff --git a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLStatementSQLVisitor.java b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLStatementSQLVisitor.java
index 95e399d57f2..ea06e1e665d 100644
--- a/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLStatementSQLVisitor.java
+++ b/sql-parser/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/impl/MySQLStatementSQLVisitor.java
@@ -119,6 +119,7 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.StringL
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.String_Context;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SubqueryContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SubstringFunctionContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.SystemVariableContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableAliasRefListContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableFactorContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TableIdentOptWildContext;
@@ -131,7 +132,9 @@ import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.Tempora
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TrimFunctionContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.TypeDatetimePrecisionContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UpdateContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.UserVariableContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ValuesFunctionContext;
+import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.VariableContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNameContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.ViewNamesContext;
 import org.apache.shardingsphere.sql.parser.autogen.MySQLStatementParser.WeightStringFunctionContext;
@@ -143,6 +146,7 @@ import org.apache.shardingsphere.sql.parser.sql.common.enums.CombineType;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.JoinType;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.OrderDirection;
 import org.apache.shardingsphere.sql.parser.sql.common.enums.ParameterMarkerType;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.constraint.ConstraintSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexNameSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.ddl.index.IndexSegment;
@@ -1042,6 +1046,9 @@ public abstract class MySQLStatementSQLVisitor extends MySQLStatementBaseVisitor
         if (null != ctx.BINARY()) {
             return visit(ctx.simpleExpr(0));
         }
+        if (null != ctx.variable()) {
+            return visit(ctx.variable());
+        }
         for (ExprContext each : ctx.expr()) {
             visit(each);
         }
@@ -1065,6 +1072,25 @@ public abstract class MySQLStatementSQLVisitor extends MySQLStatementBaseVisitor
         return new CaseWhenExpression(ctx.getStart().getStartIndex(), ctx.getStop().getStopIndex(), caseExpr, whenExprs, thenExprs, elseExpr);
     }
     
+    @Override
+    public ASTNode visitVariable(final VariableContext ctx) {
+        return null != ctx.systemVariable() ? visit(ctx.systemVariable()) : visit(ctx.userVariable());
+    }
+    
+    @Override
+    public ASTNode visitUserVariable(final UserVariableContext ctx) {
+        return new VariableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.textOrIdentifier().getText());
+    }
+    
+    @Override
+    public ASTNode visitSystemVariable(final SystemVariableContext ctx) {
+        VariableSegment result = new VariableSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), ctx.rvalueSystemVariable().getText());
+        if (null != ctx.systemVariableScope) {
+            result.setScope(ctx.systemVariableScope.getText());
+        }
+        return result;
+    }
+    
     @Override
     public final ASTNode visitMatchExpression(final MatchExpressionContext ctx) {
         visit(ctx.expr());
@@ -1568,6 +1594,11 @@ public abstract class MySQLStatementSQLVisitor extends MySQLStatementBaseVisitor
             result.setAlias(alias);
             return result;
         }
+        if (projection instanceof VariableSegment) {
+            ExpressionProjectionSegment result = new ExpressionProjectionSegment(ctx.start.getStartIndex(), ctx.stop.getStopIndex(), getOriginalText(ctx.expr()), (VariableSegment) projection);
+            result.setAlias(alias);
+            return result;
+        }
         LiteralExpressionSegment column = (LiteralExpressionSegment) projection;
         ExpressionProjectionSegment result = null == alias
                 ? new ExpressionProjectionSegment(column.getStartIndex(), column.getStopIndex(), String.valueOf(column.getLiterals()), column)
diff --git a/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussDALStatementSQLVisitor.java b/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussDALStatementSQLVisitor.java
index 508643bea9e..b4cd2ab1229 100644
--- a/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussDALStatementSQLVisitor.java
+++ b/sql-parser/dialect/opengauss/src/main/java/org/apache/shardingsphere/sql/parser/opengauss/visitor/statement/impl/OpenGaussDALStatementSQLVisitor.java
@@ -101,11 +101,7 @@ public final class OpenGaussDALStatementSQLVisitor extends OpenGaussStatementSQL
         VariableAssignSegment result = new VariableAssignSegment();
         result.setStartIndex(ctx.start.getStartIndex());
         result.setStopIndex(ctx.stop.getStopIndex());
-        VariableSegment variable = new VariableSegment();
-        variable.setStartIndex(ctx.varName().start.getStartIndex());
-        variable.setStopIndex(ctx.varName().stop.getStopIndex());
-        variable.setVariable(ctx.varName().getText());
-        result.setVariable(variable);
+        result.setVariable(new VariableSegment(ctx.varName().start.getStartIndex(), ctx.varName().stop.getStopIndex(), ctx.varName().getText()));
         if (null != ctx.varList()) {
             result.setAssignValue(ctx.varList().getText());
         }
diff --git a/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLDALStatementSQLVisitor.java b/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLDALStatementSQLVisitor.java
index dc60842fbe8..20815848fa7 100644
--- a/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLDALStatementSQLVisitor.java
+++ b/sql-parser/dialect/postgresql/src/main/java/org/apache/shardingsphere/sql/parser/postgresql/visitor/statement/impl/PostgreSQLDALStatementSQLVisitor.java
@@ -94,9 +94,7 @@ public final class PostgreSQLDALStatementSQLVisitor extends PostgreSQLStatementS
         }
         if (null != ctx.encoding()) {
             VariableAssignSegment variableAssignSegment = new VariableAssignSegment();
-            VariableSegment variableSegment = new VariableSegment();
-            variableSegment.setVariable("client_encoding");
-            variableAssignSegment.setVariable(variableSegment);
+            variableAssignSegment.setVariable(new VariableSegment(ctx.NAMES().getSymbol().getStartIndex(), ctx.NAMES().getSymbol().getStopIndex(), "client_encoding"));
             String value = ctx.encoding().getText();
             variableAssignSegment.setAssignValue(value);
             variableAssigns.add(variableAssignSegment);
@@ -110,11 +108,7 @@ public final class PostgreSQLDALStatementSQLVisitor extends PostgreSQLStatementS
         VariableAssignSegment result = new VariableAssignSegment();
         result.setStartIndex(ctx.start.getStartIndex());
         result.setStopIndex(ctx.stop.getStopIndex());
-        VariableSegment variable = new VariableSegment();
-        variable.setStartIndex(ctx.varName().start.getStartIndex());
-        variable.setStopIndex(ctx.varName().stop.getStopIndex());
-        variable.setVariable(ctx.varName().getText());
-        result.setVariable(variable);
+        result.setVariable(new VariableSegment(ctx.varName().start.getStartIndex(), ctx.varName().stop.getStopIndex(), ctx.varName().getText()));
         if (null != ctx.varList()) {
             result.setAssignValue(ctx.varList().getText());
         }
diff --git a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java
index f37c9b8ebf5..f6edb248019 100644
--- a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java
+++ b/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java
@@ -18,21 +18,34 @@
 package org.apache.shardingsphere.sql.parser.sql.common.segment.dal;
 
 import lombok.Getter;
+import lombok.RequiredArgsConstructor;
 import lombok.Setter;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.SQLSegment;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ExpressionSegment;
+
+import java.util.Optional;
 
 /**
  * Variable segment.
  */
+@RequiredArgsConstructor
 @Getter
 @Setter
-public final class VariableSegment implements SQLSegment {
+public final class VariableSegment implements ExpressionSegment {
+    
+    private final int startIndex;
     
-    private int startIndex;
+    private final int stopIndex;
     
-    private int stopIndex;
+    private final String variable;
     
     private String scope;
     
-    private String variable;
+    /**
+     * Get scope.
+     *
+     * @return scope
+     */
+    public Optional<String> getScope() {
+        return Optional.ofNullable(scope);
+    }
 }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
index 896ddb4c860..43ebb719ea9 100644
--- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
@@ -19,6 +19,7 @@ package org.apache.shardingsphere.test.it.sql.parser.internal.asserts.segment.ex
 
 import lombok.AccessLevel;
 import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.sql.parser.sql.common.segment.dal.VariableSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.column.ColumnSegment;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BetweenExpression;
 import org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.BinaryOperationExpression;
@@ -57,6 +58,7 @@ import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedListExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedNotExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedTypeCastExpression;
+import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedVariableSegment;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.complex.ExpectedCommonExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedLiteralExpression;
 import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedParameterMarkerExpression;
@@ -361,6 +363,15 @@ public final class ExpressionAssert {
         assertExpression(assertContext, actual.getExpression(), expected.getExpression());
     }
     
+    private static void assertVariableSegment(final SQLCaseAssertContext assertContext, final VariableSegment actual, final ExpectedVariableSegment expected) {
+        if (null == expected) {
+            assertNull(actual, assertContext.getText("Variable segment should not exist."));
+            return;
+        }
+        assertThat(assertContext.getText("Actual scope is different with expected scope."), actual.getScope().orElse(null), is(expected.getScope()));
+        assertThat(assertContext.getText("Actual variable is different with expected variable."), actual.getVariable(), is(expected.getVariable()));
+    }
+    
     /**
      * Assert expression by actual expression segment class type.
      *
@@ -412,6 +423,8 @@ public final class ExpressionAssert {
             assertCaseWhenExpression(assertContext, (CaseWhenExpression) actual, expected.getCaseWhenExpression());
         } else if (actual instanceof TypeCastExpression) {
             assertTypeCastExpression(assertContext, (TypeCastExpression) actual, expected.getTypeCastExpression());
+        } else if (actual instanceof VariableSegment) {
+            assertVariableSegment(assertContext, (VariableSegment) actual, expected.getVariableSegment());
         } else {
             throw new UnsupportedOperationException(String.format("Unsupported expression: %s", actual.getClass().getName()));
         }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/impl/SetParameterStatementAssert.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/impl/SetParameterStatementAssert.java
index d6a0fa9bda2..ee9a05ae60b 100644
--- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/impl/SetParameterStatementAssert.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/statement/dal/impl/SetParameterStatementAssert.java
@@ -53,6 +53,6 @@ public final class SetParameterStatementAssert {
     
     private static void assertVariable(final SQLCaseAssertContext assertContext, final VariableSegment actual, final ExpectedVariable expected) {
         assertThat(assertContext.getText("variable assertion error: "), actual.getVariable(), is(expected.getName()));
-        assertThat(assertContext.getText("scope assertion error: "), actual.getScope(), is(expected.getScope()));
+        assertThat(assertContext.getText("scope assertion error: "), actual.getScope().orElse(null), is(expected.getScope()));
     }
 }
diff --git a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
index a5fa04ed7be..032c17e8192 100644
--- a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
@@ -92,4 +92,7 @@ public final class ExpectedExpression extends AbstractExpectedSQLSegment {
     
     @XmlElement(name = "type-cast-expression")
     private ExpectedTypeCastExpression typeCastExpression;
+    
+    @XmlElement(name = "variable-segment")
+    private ExpectedVariableSegment variableSegment;
 }
diff --git a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedVariableSegment.java
similarity index 69%
copy from sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java
copy to test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedVariableSegment.java
index f37c9b8ebf5..1b90357e1fe 100644
--- a/sql-parser/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dal/VariableSegment.java
+++ b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedVariableSegment.java
@@ -15,24 +15,24 @@
  * limitations under the License.
  */
 
-package org.apache.shardingsphere.sql.parser.sql.common.segment.dal;
+package org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
 
 import lombok.Getter;
 import lombok.Setter;
-import org.apache.shardingsphere.sql.parser.sql.common.segment.SQLSegment;
+import org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
+
+import javax.xml.bind.annotation.XmlAttribute;
 
 /**
- * Variable segment.
+ * Expected variable segment.
  */
 @Getter
 @Setter
-public final class VariableSegment implements SQLSegment {
-    
-    private int startIndex;
-    
-    private int stopIndex;
+public final class ExpectedVariableSegment extends AbstractExpectedSQLSegment {
     
+    @XmlAttribute
     private String scope;
     
+    @XmlAttribute
     private String variable;
 }
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 574d59db415..4f5c3bb9ac9 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
@@ -1434,7 +1434,7 @@
             <expr>
                 <binary-operation-expression start-index="28" stop-index="55">
                     <left>
-                        <common-expression text="@@max_connections" start-index="28" stop-index="44" />
+                        <variable-segment text="@@max_connections" start-index="28" stop-index="44" variable="max_connections" />
                     </left>
                     <operator>&lt;</operator>
                     <right>
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 b9a4ad1a2bf..dc3634cf070 100644
--- a/test/it/parser/src/main/resources/case/dml/select.xml
+++ b/test/it/parser/src/main/resources/case/dml/select.xml
@@ -73,6 +73,26 @@
             </expression-projection>
         </projections>
     </select>
+    
+    <select sql-case-id="select_system_variables" >
+        <projections start-index="7" stop-index="121">
+            <expression-projection text="@@session.auto_increment_increment" alias="auto_increment_increment" start-index="7" stop-index="65">
+                <expr>
+                    <variable-segment text="@@session.auto_increment_increment" start-index="7" stop-index="40" scope="session" variable="auto_increment_increment" />
+                </expr>
+            </expression-projection>
+            <expression-projection text="@@global.max_connections" alias="max_connections" start-index="68" stop-index="107">
+                <expr>
+                    <variable-segment text="@@global.max_connections" start-index="68" stop-index="91" scope="global" variable="max_connections" />
+                </expr>
+            </expression-projection>
+            <expression-projection text="@@autocommit" start-index="110" stop-index="121">
+                <expr>
+                    <variable-segment text="@@autocommit" start-index="110" stop-index="121" variable="autocommit" />
+                </expr>
+            </expression-projection>
+        </projections>
+    </select>
 
     <select sql-case-id="select_sqlmode_ansi_quotes" >
         <projections start-index="7" stop-index="10">
diff --git a/test/it/parser/src/main/resources/sql/supported/dml/select.xml b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
index b3a2ebd9c8e..843d70ca529 100644
--- a/test/it/parser/src/main/resources/sql/supported/dml/select.xml
+++ b/test/it/parser/src/main/resources/sql/supported/dml/select.xml
@@ -21,6 +21,7 @@
     <sql-case id="select_with_operator_ilike" value="SELECT id from t_order where name !~ '^pg_toast'" db-types="PostgreSQL,openGauss" />
     <sql-case id="select_with_binary_operation_of_aggregation_expr" value="SELECT (count(*)+1) as a" db-types="MySQL" />
     <sql-case id="select_with_schema_func" value="SELECT schema(), database()" db-types="MySQL" />
+    <sql-case id="select_system_variables" value="SELECT @@session.auto_increment_increment auto_increment_increment, @@global.max_connections max_connections, @@autocommit" db-types="MySQL" />
     <sql-case id="select_sqlmode_ansi_quotes" value='select "id" from "t_order" where "t_order"."id"=10' db-types="MySQL" />
     <sql-case id="select_with_function_name" value="SELECT current_timestamp" db-types="MySQL" />
     <sql-case id="select_with_same_table_name_and_alias" value="SELECT t_order.* FROM t_order t_order WHERE user_id = ? AND order_id = ?" />