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

zhangliang 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 2582036098e Add more converter test cases (#37353)
2582036098e is described below

commit 2582036098e839df94f677565f0df79707ef8215
Author: Liang Zhang <[email protected]>
AuthorDate: Thu Dec 11 23:31:51 2025 +0800

    Add more converter test cases (#37353)
    
    * Add more converter test cases
    
    * Add more converter test cases
---
 .../impl/BetweenExpressionConverterTest.java       |  86 +++++++++
 .../BinaryOperationExpressionConverterTest.java    | 211 +++++++++++++++++++++
 .../impl/CaseWhenExpressionConverterTest.java      | 109 +++++++++++
 .../impl/CollateExpressionConverterTest.java       |  75 ++++++++
 .../expression/impl/ColumnConverterTest.java       |  54 ++++++
 .../impl/DataTypeExpressionConverterTest.java      |  65 +++++++
 .../ExistsSubqueryExpressionConverterTest.java     |  82 ++++++++
 .../impl/ExtractArgExpressionConverterTest.java    |  42 ++++
 .../expression/impl/FunctionConverterTest.java     | 140 ++++++++++++++
 9 files changed, 864 insertions(+)

diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BetweenExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BetweenExpressionConverterTest.java
new file mode 100644
index 00000000000..91b1525ab7e
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BetweenExpressionConverterTest.java
@@ -0,0 +1,86 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BetweenExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Arrays;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ExpressionConverter.class)
+class BetweenExpressionConverterTest {
+    
+    @Test
+    void assertConvertReturnsEmptyForNullExpression() {
+        assertFalse(BetweenExpressionConverter.convert(null).isPresent());
+    }
+    
+    @Test
+    void assertConvertBetweenExpression() {
+        ExpressionSegment left = new LiteralExpressionSegment(0, 0, "left");
+        ExpressionSegment betweenExpr = new LiteralExpressionSegment(0, 0, 
"between");
+        ExpressionSegment andExpr = new LiteralExpressionSegment(0, 0, "and");
+        SqlNode leftNode = mock(SqlNode.class);
+        SqlNode betweenNode = mock(SqlNode.class);
+        SqlNode andNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        
when(ExpressionConverter.convert(betweenExpr)).thenReturn(Optional.of(betweenNode));
+        
when(ExpressionConverter.convert(andExpr)).thenReturn(Optional.of(andNode));
+        Optional<SqlNode> actual = BetweenExpressionConverter.convert(new 
BetweenExpression(0, 0, left, betweenExpr, andExpr, false));
+        assertTrue(actual.isPresent());
+        SqlBasicCall call = (SqlBasicCall) actual.orElse(null);
+        assertThat(call.getOperator(), is(SqlStdOperatorTable.BETWEEN));
+        assertThat(call.getOperandList(), is(Arrays.asList(leftNode, 
betweenNode, andNode)));
+    }
+    
+    @Test
+    void assertConvertNotBetweenExpression() {
+        ExpressionSegment left = new LiteralExpressionSegment(0, 0, "left");
+        ExpressionSegment betweenExpr = new LiteralExpressionSegment(0, 0, 
"between");
+        ExpressionSegment andExpr = new LiteralExpressionSegment(0, 0, "and");
+        SqlNode leftNode = mock(SqlNode.class);
+        SqlNode betweenNode = mock(SqlNode.class);
+        SqlNode andNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        
when(ExpressionConverter.convert(betweenExpr)).thenReturn(Optional.of(betweenNode));
+        
when(ExpressionConverter.convert(andExpr)).thenReturn(Optional.of(andNode));
+        Optional<SqlNode> actual = BetweenExpressionConverter.convert(new 
BetweenExpression(0, 0, left, betweenExpr, andExpr, true));
+        assertTrue(actual.isPresent());
+        SqlBasicCall call = (SqlBasicCall) actual.orElse(null);
+        assertThat(call.getOperator(), is(SqlStdOperatorTable.NOT_BETWEEN));
+        assertThat(call.getOperandList(), is(Arrays.asList(leftNode, 
betweenNode, andNode)));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BinaryOperationExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BinaryOperationExpressionConverterTest.java
new file mode 100644
index 00000000000..597557e053d
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/BinaryOperationExpressionConverterTest.java
@@ -0,0 +1,211 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlNumericLiteral;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.BinaryOperationExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.QuantifySubqueryExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.Arguments;
+import org.junit.jupiter.params.provider.MethodSource;
+
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+import java.util.stream.Stream;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ExpressionConverter.class)
+class BinaryOperationExpressionConverterTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+    
+    @Test
+    void assertConvertThrowsForUnsupportedOperator() {
+        BinaryOperationExpression expression = new 
BinaryOperationExpression(0, 0, new LiteralExpressionSegment(0, 0, 1), new 
LiteralExpressionSegment(0, 0, 1), "UNSUPPORTED", "");
+        assertThrows(IllegalStateException.class, () -> 
BinaryOperationExpressionConverter.convert(expression));
+    }
+    
+    @Test
+    void assertConvertThrowsWhenIsOperatorUnsupportedLiteral() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"unknown");
+        BinaryOperationExpression expression = new 
BinaryOperationExpression(0, 0, left, right, "IS", "");
+        assertThrows(IllegalStateException.class, () -> 
BinaryOperationExpressionConverter.convert(expression));
+    }
+    
+    @Test
+    void assertConvertIsNullOperator() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"NULL");
+        SqlNode leftNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_NULL));
+        assertThat(actual.getOperandList(), 
is(Collections.singletonList(leftNode)));
+    }
+    
+    @Test
+    void assertConvertIsNotNullOperator() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"NOT NULL");
+        SqlNode leftNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_NOT_NULL));
+        assertThat(actual.getOperandList(), 
is(Collections.singletonList(leftNode)));
+    }
+    
+    @Test
+    void assertConvertIsFalseConvertsNumericZeroToBooleanFalse() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 0);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"FALSE");
+        SqlNumericLiteral leftNode = SqlLiteral.createExactNumeric("0", 
SqlParserPos.ZERO);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_FALSE));
+        SqlLiteral operand = (SqlLiteral) actual.getOperandList().get(0);
+        assertThat(operand.getValueAs(Boolean.class), is(false));
+    }
+    
+    @Test
+    void assertConvertIsNotFalseConvertsNumericToBooleanTrue() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 2);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"NOT FALSE");
+        SqlNumericLiteral leftNode = SqlLiteral.createExactNumeric("2", 
SqlParserPos.ZERO);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_NOT_FALSE));
+        SqlLiteral operand = (SqlLiteral) actual.getOperandList().get(0);
+        assertThat(operand.getValueAs(Boolean.class), is(true));
+    }
+    
+    @Test
+    void assertConvertIsTrueKeepsNonNumericLeft() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 
"left");
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"TRUE");
+        SqlNode leftNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_TRUE));
+        assertThat(actual.getOperandList().get(0), is(leftNode));
+    }
+    
+    @Test
+    void assertConvertIsNotTrueConvertsNumericZeroToBooleanFalse() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 0);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 
"NOT TRUE");
+        SqlNumericLiteral leftNode = SqlLiteral.createExactNumeric("0", 
SqlParserPos.ZERO);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "IS", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.IS_NOT_TRUE));
+        SqlLiteral operand = (SqlLiteral) actual.getOperandList().get(0);
+        assertThat(operand.getValueAs(Boolean.class), is(false));
+    }
+    
+    @Test
+    void assertConvertFlattensSqlNodeListOperands() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        LiteralExpressionSegment right = new LiteralExpressionSegment(0, 0, 2);
+        BinaryOperationExpression expression = new 
BinaryOperationExpression(0, 0, left, right, "+", "");
+        SqlNode leftNode = mock(SqlNode.class);
+        SqlNode firstRightNode = mock(SqlNode.class);
+        SqlNode secondRightNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        when(ExpressionConverter.convert(right)).thenReturn(Optional.of(new 
SqlNodeList(Arrays.asList(firstRightNode, secondRightNode), 
SqlParserPos.ZERO)));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(expression).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.PLUS));
+        assertThat(actual.getOperandList(), is(Arrays.asList(leftNode, 
firstRightNode, secondRightNode)));
+    }
+    
+    @Test
+    void assertConvertQuantifySubqueryFallsBackToOriginalOperator() {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        QuantifySubqueryExpression right = new QuantifySubqueryExpression(0, 
0, new SubquerySegment(0, 0, new SelectStatement(databaseType), "sub"), "ALL");
+        SqlNode leftNode = mock(SqlNode.class);
+        SqlNode rightNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        
when(ExpressionConverter.convert(right)).thenReturn(Optional.of(rightNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, "AND", "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.AND));
+        assertThat(actual.getOperandList(), is(Arrays.asList(leftNode, 
rightNode)));
+    }
+    
+    @ParameterizedTest(name = "{0} {1}")
+    @MethodSource("provideQuantifyOperators")
+    void assertConvertQuantifySubquery(final String operator, final String 
quantifyOperator, final SqlOperator expectedOperator) {
+        LiteralExpressionSegment left = new LiteralExpressionSegment(0, 0, 1);
+        QuantifySubqueryExpression right = new QuantifySubqueryExpression(0, 
0, new SubquerySegment(0, 0, new SelectStatement(databaseType), "sub"), 
quantifyOperator);
+        SqlNode leftNode = mock(SqlNode.class);
+        SqlNode rightNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(left)).thenReturn(Optional.of(leftNode));
+        
when(ExpressionConverter.convert(right)).thenReturn(Optional.of(rightNode));
+        SqlBasicCall actual = (SqlBasicCall) 
BinaryOperationExpressionConverter.convert(new BinaryOperationExpression(0, 0, 
left, right, operator, "")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(expectedOperator));
+        assertThat(actual.getOperandList(), is(Arrays.asList(leftNode, 
rightNode)));
+    }
+    
+    private static Stream<Arguments> provideQuantifyOperators() {
+        return Stream.of(
+                Arguments.of("=", "ALL", SqlStdOperatorTable.ALL_EQ),
+                Arguments.of("=", "SOME", SqlStdOperatorTable.SOME_EQ),
+                Arguments.of(">", "ALL", SqlStdOperatorTable.ALL_GT),
+                Arguments.of(">", "SOME", SqlStdOperatorTable.SOME_GT),
+                Arguments.of(">=", "ALL", SqlStdOperatorTable.ALL_GE),
+                Arguments.of(">=", "SOME", SqlStdOperatorTable.SOME_GE),
+                Arguments.of("<", "ALL", SqlStdOperatorTable.ALL_LT),
+                Arguments.of("<", "SOME", SqlStdOperatorTable.SOME_LT),
+                Arguments.of("<=", "ALL", SqlStdOperatorTable.ALL_LE),
+                Arguments.of("<=", "SOME", SqlStdOperatorTable.SOME_LE),
+                Arguments.of("!=", "ALL", SqlStdOperatorTable.ALL_NE),
+                Arguments.of("<>", "SOME", SqlStdOperatorTable.SOME_NE));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CaseWhenExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CaseWhenExpressionConverterTest.java
new file mode 100644
index 00000000000..041da02576b
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CaseWhenExpressionConverterTest.java
@@ -0,0 +1,109 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlLiteral;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.fun.SqlCase;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+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.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ExpressionConverter.class)
+class CaseWhenExpressionConverterTest {
+    
+    @Test
+    void assertConvertCaseExpressionWithElseExpr() {
+        ExpressionSegment caseExpr = new LiteralExpressionSegment(0, 0, 
"case_expr");
+        ExpressionSegment whenExpr = new LiteralExpressionSegment(0, 0, 
"when_expr");
+        ExpressionSegment thenExpr = new LiteralExpressionSegment(0, 0, 
"then_expr");
+        ExpressionSegment elseExpr = new LiteralExpressionSegment(0, 0, 
"else_expr");
+        CaseWhenExpression expression = new CaseWhenExpression(0, 0, caseExpr, 
Collections.singleton(whenExpr), Collections.singleton(thenExpr), elseExpr);
+        SqlNode caseNode = mock(SqlNode.class);
+        SqlNode whenNode = mock(SqlNode.class);
+        SqlNode thenNode = mock(SqlNode.class);
+        SqlNode elseNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(caseExpr)).thenReturn(Optional.of(caseNode));
+        
when(ExpressionConverter.convert(whenExpr)).thenReturn(Optional.of(whenNode));
+        
when(ExpressionConverter.convert(thenExpr)).thenReturn(Optional.of(thenNode));
+        
when(ExpressionConverter.convert(elseExpr)).thenReturn(Optional.of(elseNode));
+        SqlCase actual = (SqlCase) 
CaseWhenExpressionConverter.convert(expression).orElse(null);
+        assertNotNull(actual);
+        SqlBasicCall whenCall = (SqlBasicCall) actual.getWhenOperands().get(0);
+        assertThat(whenCall.getOperator(), is(SqlStdOperatorTable.EQUALS));
+        assertThat(whenCall.getOperandList().get(0), is(caseNode));
+        assertThat(whenCall.getOperandList().get(1), is(whenNode));
+        assertThat(actual.getThenOperands().get(0), is(thenNode));
+        assertThat(actual.getElseOperand(), is(elseNode));
+    }
+    
+    @Test
+    void assertConvertSearchedCaseWithDefaultElse() {
+        ExpressionSegment whenExpr = new LiteralExpressionSegment(0, 0, 
"when_expr");
+        ExpressionSegment thenExpr = new LiteralExpressionSegment(0, 0, 
"then_expr");
+        CaseWhenExpression expression = new CaseWhenExpression(0, 0, null, 
Collections.singleton(whenExpr), Collections.singleton(thenExpr), null);
+        SqlNode whenNode = mock(SqlNode.class);
+        SqlNode thenNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(whenExpr)).thenReturn(Optional.of(whenNode));
+        
when(ExpressionConverter.convert(thenExpr)).thenReturn(Optional.of(thenNode));
+        when(ExpressionConverter.convert(null)).thenReturn(Optional.empty());
+        SqlCase actual = (SqlCase) 
CaseWhenExpressionConverter.convert(expression).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getValueOperand(), is((SqlNode) null));
+        assertThat(actual.getWhenOperands().get(0), is(whenNode));
+        assertThat(actual.getThenOperands().get(0), is(thenNode));
+        assertNotNull(actual.getElseOperand());
+        assertThat(((SqlLiteral) 
actual.getElseOperand()).getValueAs(String.class), is("NULL"));
+    }
+    
+    @Test
+    void assertConvertSkipsWhenExpressionIfConversionEmpty() {
+        ExpressionSegment caseExpr = new LiteralExpressionSegment(0, 0, 
"case_expr");
+        ExpressionSegment whenExpr = new LiteralExpressionSegment(0, 0, 
"when_expr");
+        ExpressionSegment thenExpr = new LiteralExpressionSegment(0, 0, 
"then_expr");
+        CaseWhenExpression expression = new CaseWhenExpression(0, 0, caseExpr, 
Collections.singleton(whenExpr), Collections.singleton(thenExpr), null);
+        SqlNode caseNode = mock(SqlNode.class);
+        SqlNode thenNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(caseExpr)).thenReturn(Optional.of(caseNode));
+        
when(ExpressionConverter.convert(whenExpr)).thenReturn(Optional.empty());
+        
when(ExpressionConverter.convert(thenExpr)).thenReturn(Optional.of(thenNode));
+        when(ExpressionConverter.convert(null)).thenReturn(Optional.empty());
+        SqlCase actual = (SqlCase) 
CaseWhenExpressionConverter.convert(expression).orElse(null);
+        assertNotNull(actual);
+        assertTrue(actual.getWhenOperands().isEmpty());
+        assertThat(actual.getThenOperands().get(0), is(thenNode));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CollateExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CollateExpressionConverterTest.java
new file mode 100644
index 00000000000..8977e4a70c8
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/CollateExpressionConverterTest.java
@@ -0,0 +1,75 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.CollateExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.operator.common.SQLExtensionOperatorTable;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.isA;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ExpressionConverter.class)
+class CollateExpressionConverterTest {
+    
+    @Test
+    void assertConvertCollateExpression() {
+        ExpressionSegment expr = new LiteralExpressionSegment(0, 0, "value");
+        LiteralExpressionSegment collateName = new LiteralExpressionSegment(0, 
0, "collation");
+        CollateExpression collateExpression = new CollateExpression(0, 0, 
collateName, expr);
+        SqlNode exprNode = mock(SqlNode.class);
+        SqlNode collateNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(expr)).thenReturn(Optional.of(exprNode));
+        
when(ExpressionConverter.convert(collateName)).thenReturn(Optional.of(collateNode));
+        SqlBasicCall actual = (SqlBasicCall) 
CollateExpressionConverter.convert(collateExpression).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), 
is(SQLExtensionOperatorTable.COLLATE));
+        assertThat(actual.getOperandList().get(0), is(exprNode));
+        assertThat(actual.getOperandList().get(1), is(collateNode));
+    }
+    
+    @Test
+    void assertConvertCollateExpressionWithEmptyParts() {
+        LiteralExpressionSegment collateName = new LiteralExpressionSegment(0, 
0, "collation");
+        CollateExpression collateExpression = new CollateExpression(0, 0, 
collateName, null);
+        
when(ExpressionConverter.convert(collateName)).thenReturn(Optional.empty());
+        SqlBasicCall actual = (SqlBasicCall) 
CollateExpressionConverter.convert(collateExpression).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperandList().get(0), isA(SqlNodeList.class));
+        assertTrue(((SqlNodeList) actual.getOperandList().get(0)).isEmpty());
+        assertThat(actual.getOperandList().get(1), isA(SqlNodeList.class));
+        assertTrue(((SqlNodeList) actual.getOperandList().get(1)).isEmpty());
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ColumnConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ColumnConverterTest.java
new file mode 100644
index 00000000000..bd472e9a011
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ColumnConverterTest.java
@@ -0,0 +1,54 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlIdentifier;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class ColumnConverterTest {
+    
+    @Test
+    void assertConvertColumnWithoutOwner() {
+        ColumnSegment columnSegment = new ColumnSegment(0, 0, new 
IdentifierValue("col"));
+        SqlIdentifier actual = (SqlIdentifier) 
ColumnConverter.convert(columnSegment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getSimple(), is("col"));
+        assertThat(actual.names, is(Collections.singletonList("col")));
+    }
+    
+    @Test
+    void assertConvertColumnWithNestedOwner() {
+        OwnerSegment owner = new OwnerSegment(0, 0, new 
IdentifierValue("schema"));
+        owner.setOwner(new OwnerSegment(0, 0, new IdentifierValue("catalog")));
+        ColumnSegment columnSegment = new ColumnSegment(0, 0, new 
IdentifierValue("col"));
+        columnSegment.setOwner(owner);
+        SqlIdentifier actual = (SqlIdentifier) 
ColumnConverter.convert(columnSegment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.names, is(Arrays.asList("catalog", "schema", 
"col")));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/DataTypeExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/DataTypeExpressionConverterTest.java
new file mode 100644
index 00000000000..fae75f622a5
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/DataTypeExpressionConverterTest.java
@@ -0,0 +1,65 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicTypeNameSpec;
+import org.apache.calcite.sql.SqlDataTypeSpec;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.DataTypeLengthSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.DataTypeSegment;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class DataTypeExpressionConverterTest {
+    
+    @Test
+    void assertConvertReturnsEmptyForNullSegment() {
+        assertFalse(DataTypeExpressionConverter.convert(null).isPresent());
+    }
+    
+    @Test
+    void assertConvertWithoutLength() {
+        DataTypeSegment segment = new DataTypeSegment();
+        segment.setStartIndex(0);
+        segment.setStopIndex(0);
+        segment.setDataTypeName("INTEGER");
+        SqlDataTypeSpec actual = (SqlDataTypeSpec) 
DataTypeExpressionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        SqlBasicTypeNameSpec typeNameSpec = (SqlBasicTypeNameSpec) 
actual.getTypeNameSpec();
+        assertThat(typeNameSpec.getTypeName().getSimple(), is("INTEGER"));
+        assertThat(typeNameSpec.getPrecision(), is(-1));
+    }
+    
+    @Test
+    void assertConvertWithLength() {
+        DataTypeSegment segment = new DataTypeSegment();
+        segment.setStartIndex(0);
+        segment.setStopIndex(0);
+        segment.setDataTypeName("varchar");
+        DataTypeLengthSegment dataLength = new DataTypeLengthSegment();
+        dataLength.setPrecision(10);
+        segment.setDataLength(dataLength);
+        SqlDataTypeSpec actual = (SqlDataTypeSpec) 
DataTypeExpressionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        SqlBasicTypeNameSpec typeNameSpec = (SqlBasicTypeNameSpec) 
actual.getTypeNameSpec();
+        assertThat(typeNameSpec.getPrecision(), is(10));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExistsSubqueryExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExistsSubqueryExpressionConverterTest.java
new file mode 100644
index 00000000000..42905f5a293
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExistsSubqueryExpressionConverterTest.java
@@ -0,0 +1,82 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.shardingsphere.database.connector.core.type.DatabaseType;
+import org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExistsSubqueryExpression;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubquerySegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.statement.type.SelectStatementConverter;
+import org.junit.jupiter.api.Test;
+import org.mockito.MockedConstruction;
+
+import java.util.Collections;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.when;
+
+class ExistsSubqueryExpressionConverterTest {
+    
+    private final DatabaseType databaseType = 
TypedSPILoader.getService(DatabaseType.class, "FIXTURE");
+    
+    @Test
+    void assertConvertReturnsEmptyForNullExpression() {
+        
assertFalse(ExistsSubqueryExpressionConverter.convert(null).isPresent());
+    }
+    
+    @Test
+    void assertConvertExistsExpression() {
+        SqlNode expected = mock(SqlNode.class);
+        try (
+                MockedConstruction<SelectStatementConverter> ignored = 
mockConstruction(SelectStatementConverter.class,
+                        (mock, context) -> 
when(mock.convert(any(SelectStatement.class))).thenReturn(expected))) {
+            ExistsSubqueryExpression expression = new 
ExistsSubqueryExpression(0, 0, new SubquerySegment(0, 0, new 
SelectStatement(databaseType), "text"));
+            SqlBasicCall actual = (SqlBasicCall) 
ExistsSubqueryExpressionConverter.convert(expression).orElse(null);
+            assertNotNull(actual);
+            assertThat(actual.getOperator(), is(SqlStdOperatorTable.EXISTS));
+            assertThat(actual.getOperandList(), 
is(Collections.singletonList(expected)));
+        }
+    }
+    
+    @Test
+    void assertConvertNotExistsExpression() {
+        SqlNode expected = mock(SqlNode.class);
+        try (
+                MockedConstruction<SelectStatementConverter> ignored = 
mockConstruction(SelectStatementConverter.class,
+                        (mock, context) -> 
when(mock.convert(any(SelectStatement.class))).thenReturn(expected))) {
+            ExistsSubqueryExpression expression = new 
ExistsSubqueryExpression(0, 0, new SubquerySegment(0, 0, new 
SelectStatement(databaseType), "text"));
+            expression.setNot(true);
+            SqlBasicCall actual = (SqlBasicCall) 
ExistsSubqueryExpressionConverter.convert(expression).orElse(null);
+            assertNotNull(actual);
+            assertThat(actual.getOperator(), is(SqlStdOperatorTable.NOT));
+            SqlBasicCall existsCall = (SqlBasicCall) 
actual.getOperandList().get(0);
+            assertThat(existsCall.getOperator(), 
is(SqlStdOperatorTable.EXISTS));
+            assertThat(existsCall.getOperandList(), 
is(Collections.singletonList(expected)));
+        }
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExtractArgExpressionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExtractArgExpressionConverterTest.java
new file mode 100644
index 00000000000..b74434e3f34
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/ExtractArgExpressionConverterTest.java
@@ -0,0 +1,42 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlIdentifier;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExtractArgExpression;
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+class ExtractArgExpressionConverterTest {
+    
+    @Test
+    void assertConvertReturnsEmptyForNullExpression() {
+        assertFalse(ExtractArgExpressionConverter.convert(null).isPresent());
+    }
+    
+    @Test
+    void assertConvertExtractArgExpression() {
+        SqlIdentifier actual = (SqlIdentifier) 
ExtractArgExpressionConverter.convert(new ExtractArgExpression(0, 0, 
"DAY")).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getSimple(), is("DAY"));
+    }
+}
diff --git 
a/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
new file mode 100644
index 00000000000..cdb0c18f79c
--- /dev/null
+++ 
b/kernel/sql-federation/compiler/src/test/java/org/apache/shardingsphere/sqlfederation/compiler/sql/ast/converter/segment/expression/impl/FunctionConverterTest.java
@@ -0,0 +1,140 @@
+/*
+ * 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.sqlfederation.compiler.sql.ast.converter.segment.expression.impl;
+
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlIdentifier;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlNodeList;
+import org.apache.calcite.sql.SqlUnresolvedFunction;
+import org.apache.calcite.sql.SqlWindow;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
+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.simple.LiteralExpressionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.OwnerSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.WindowItemSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.value.identifier.IdentifierValue;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.expression.ExpressionConverter;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.generic.OwnerConverter;
+import 
org.apache.shardingsphere.sqlfederation.compiler.sql.ast.converter.segment.window.WindowConverter;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.AutoMockExtension;
+import 
org.apache.shardingsphere.test.infra.framework.extension.mock.StaticMockSettings;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.extension.ExtendWith;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.Optional;
+
+import static org.hamcrest.CoreMatchers.instanceOf;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings({ExpressionConverter.class, TrimFunctionConverter.class, 
WindowFunctionConverter.class, WindowConverter.class, OwnerConverter.class})
+class FunctionConverterTest {
+    
+    @Test
+    void assertConvertReturnsCurrentUserIdentifier() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "CURRENT_USER", 
"CURRENT_USER");
+        SqlIdentifier actual = (SqlIdentifier) 
FunctionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getSimple(), is("CURRENT_USER"));
+    }
+    
+    @Test
+    void assertConvertDelegatesToTrimFunctionConverter() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "TRIM", "TRIM");
+        SqlNode expected = mock(SqlNode.class);
+        
when(TrimFunctionConverter.convert(segment)).thenReturn(Optional.of(expected));
+        SqlNode actual = FunctionConverter.convert(segment).orElse(null);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertConvertDelegatesToWindowFunctionConverter() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "OVER", "OVER");
+        SqlNode expected = mock(SqlNode.class);
+        
when(WindowFunctionConverter.convert(segment)).thenReturn(Optional.of(expected));
+        SqlNode actual = FunctionConverter.convert(segment).orElse(null);
+        assertThat(actual, is(expected));
+    }
+    
+    @Test
+    void assertConvertResolvedFunctionWithWindow() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "COUNT", "COUNT");
+        ExpressionSegment param = new LiteralExpressionSegment(0, 0, 1);
+        segment.getParameters().add(param);
+        WindowItemSegment windowItemSegment = new WindowItemSegment(0, 0);
+        segment.setWindow(windowItemSegment);
+        SqlNode paramNode = mock(SqlNode.class);
+        SqlWindow windowNode = mock(SqlWindow.class);
+        
when(ExpressionConverter.convert(param)).thenReturn(Optional.of(paramNode));
+        
when(WindowConverter.convertWindowItem(windowItemSegment)).thenReturn(windowNode);
+        SqlBasicCall actual = (SqlBasicCall) 
FunctionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), is(SqlStdOperatorTable.OVER));
+        SqlBasicCall functionCall = (SqlBasicCall) 
actual.getOperandList().get(0);
+        assertThat(functionCall.getOperator().getName(), is("COUNT"));
+        assertThat(functionCall.getOperandList(), 
is(Collections.singletonList(paramNode)));
+        assertThat(actual.getOperandList().get(1), is(windowNode));
+    }
+    
+    @Test
+    void assertConvertResolvedFunctionWithoutWindowFlattensParameters() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "SUM", "SUM");
+        ExpressionSegment firstParam = new LiteralExpressionSegment(0, 0, 
"list");
+        ExpressionSegment secondParam = new LiteralExpressionSegment(0, 0, 
"single");
+        segment.getParameters().add(firstParam);
+        segment.getParameters().add(secondParam);
+        SqlNode nodeInList = mock(SqlNode.class);
+        SqlNode listSecondNode = mock(SqlNode.class);
+        SqlNode secondNode = mock(SqlNode.class);
+        
when(ExpressionConverter.convert(firstParam)).thenReturn(Optional.of(new 
SqlNodeList(Arrays.asList(nodeInList, listSecondNode), SqlParserPos.ZERO)));
+        
when(ExpressionConverter.convert(secondParam)).thenReturn(Optional.of(secondNode));
+        SqlBasicCall actual = (SqlBasicCall) 
FunctionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator().getName(), is("SUM"));
+        assertThat(actual.getOperandList(), is(Arrays.asList(nodeInList, 
listSecondNode, secondNode)));
+    }
+    
+    @Test
+    void assertConvertUnresolvedFunctionWithOwner() {
+        FunctionSegment segment = new FunctionSegment(0, 0, "custom_func", 
"custom_func");
+        OwnerSegment owner = new OwnerSegment(0, 0, new 
IdentifierValue("schema"));
+        segment.setOwner(owner);
+        ExpressionSegment param = new LiteralExpressionSegment(0, 0, "p");
+        segment.getParameters().add(param);
+        SqlNode paramNode = mock(SqlNode.class);
+        when(OwnerConverter.convert(owner)).thenReturn(new ArrayList<>());
+        
when(ExpressionConverter.convert(param)).thenReturn(Optional.of(paramNode));
+        SqlBasicCall actual = (SqlBasicCall) 
FunctionConverter.convert(segment).orElse(null);
+        assertNotNull(actual);
+        assertThat(actual.getOperator(), 
instanceOf(SqlUnresolvedFunction.class));
+        SqlIdentifier functionName = actual.getOperator().getNameAsId();
+        assertThat(functionName.names, 
is(Collections.singletonList("custom_func")));
+        assertThat(functionName.getSimple(), is("custom_func"));
+        assertThat(actual.getOperandList(), 
is(Collections.singletonList(paramNode)));
+    }
+}

Reply via email to