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)));
+ }
+}