This is an automated email from the ASF dual-hosted git repository.
zhaojinchao 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 7121e652a1f support unary operation (#28320)
7121e652a1f is described below
commit 7121e652a1f3ca34ff5024758ca007b89dea7459
Author: Yunbo Ni <[email protected]>
AuthorDate: Mon Sep 4 14:11:21 2023 +0800
support unary operation (#28320)
* feat: unary operation
* fix: import *
* fix: check style
---------
Co-authored-by: Zhengqiang Duan <[email protected]>
---
.../segment/expression/ExpressionConverter.java | 5 ++
.../expression/impl/SQLExtensionOperatorTable.java | 2 +
.../impl/UnaryOperationExpressionConverter.java | 76 ++++++++++++++++++++++
.../visitor/statement/MySQLStatementVisitor.java | 4 ++
.../segment/dml/expr/UnaryOperationExpression.java | 41 ++++++++++++
.../test/resources/converter/select-expression.xml | 1 +
.../segment/expression/ExpressionAssert.java | 22 +++++++
.../jaxb/segment/impl/expr/ExpectedExpression.java | 3 +
.../expr/ExpectedUnaryOperationExpression.java | 38 +++++++++++
.../main/resources/case/dml/select-expression.xml | 9 ++-
10 files changed, 200 insertions(+), 1 deletion(-)
diff --git
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/ExpressionConverter.java
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/ExpressionConverter.java
index 79252fddb66..6cb5542caf5 100644
---
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/ExpressionConverter.java
+++
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/ExpressionConverter.java
@@ -38,6 +38,7 @@ import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.MatchAga
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.item.AggregationProjectionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.CollateExpression;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.generic.DataTypeSegment;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.SQLSegmentConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.BetweenExpressionConverter;
@@ -54,6 +55,7 @@ import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expres
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.ParameterMarkerExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.SubqueryExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.TypeCastExpressionConverter;
+import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.UnaryOperationExpressionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.projection.impl.AggregationProjectionConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.projection.impl.DataTypeConverter;
import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.impl.NotExpressionConverter;
@@ -129,6 +131,9 @@ public final class ExpressionConverter implements
SQLSegmentConverter<Expression
if (segment instanceof CollateExpression) {
return new
CollateExpressionConverter().convert((CollateExpression) segment);
}
+ if (segment instanceof UnaryOperationExpression) {
+ return new
UnaryOperationExpressionConverter().convert((UnaryOperationExpression) segment);
+ }
throw new UnsupportedSQLOperationException("unsupported TableSegment
type: " + segment.getClass());
}
}
diff --git
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/SQLExtensionOperatorTable.java
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/SQLExtensionOperatorTable.java
index 6a82cdbcfa0..c7ae21a671c 100644
---
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/SQLExtensionOperatorTable.java
+++
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/SQLExtensionOperatorTable.java
@@ -55,4 +55,6 @@ public final class SQLExtensionOperatorTable {
public static final MySQLMatchAgainstFunction MATCH_AGAINST = new
MySQLMatchAgainstFunction();
public static final SqlBinaryOperator COLLATE = new
SqlBinaryOperator("COLLATE", SqlKind.OTHER, 30, true, null, null, null);
+
+ public static final SqlPrefixOperator TILDE = new SqlPrefixOperator("~",
SqlKind.OTHER, 26, null, null, null);
}
diff --git
a/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/UnaryOperationExpressionConverter.java
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/UnaryOperationExpressionConverter.java
new file mode 100644
index 00000000000..a3d72496ac1
--- /dev/null
+++
b/kernel/sql-federation/core/src/main/java/org/apache/shardingsphere/sqlfederation/compiler/converter/segment/expression/impl/UnaryOperationExpressionConverter.java
@@ -0,0 +1,76 @@
+/*
+ * 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.converter.segment.expression.impl;
+
+import com.google.common.base.Preconditions;
+import org.apache.calcite.sql.SqlBasicCall;
+import org.apache.calcite.sql.SqlNode;
+import org.apache.calcite.sql.SqlOperator;
+import org.apache.calcite.sql.fun.SqlStdOperatorTable;
+import org.apache.calcite.sql.parser.SqlParserPos;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
+import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.SQLSegmentConverter;
+import
org.apache.shardingsphere.sqlfederation.compiler.converter.segment.expression.ExpressionConverter;
+
+import java.util.Map;
+import java.util.Optional;
+import java.util.TreeMap;
+import java.util.List;
+import java.util.LinkedList;
+
+/**
+ * Unary operation expression converter.
+ */
+public class UnaryOperationExpressionConverter implements
SQLSegmentConverter<UnaryOperationExpression, SqlNode> {
+
+ private static final Map<String, SqlOperator> REGISTRY = new
TreeMap<>(String.CASE_INSENSITIVE_ORDER);
+
+ static {
+ register();
+ }
+
+ private static void register() {
+ register(SqlStdOperatorTable.UNARY_PLUS);
+ register(SqlStdOperatorTable.UNARY_MINUS);
+ register(SQLExtensionOperatorTable.TILDE);
+ }
+
+ private static void register(final SqlOperator sqlOperator) {
+ REGISTRY.put(sqlOperator.getName(), sqlOperator);
+ }
+
+ @Override
+ public Optional<SqlNode> convert(final UnaryOperationExpression segment) {
+ SqlOperator operator = convertOperator(segment);
+ List<SqlNode> sqlNodes = convertSqlNodes(segment);
+ return Optional.of(new SqlBasicCall(operator, sqlNodes,
SqlParserPos.ZERO));
+ }
+
+ private SqlOperator convertOperator(final UnaryOperationExpression
segment) {
+ String operator = segment.getOperator();
+ Preconditions.checkState(REGISTRY.containsKey(operator), "Unsupported
SQL operator: %s", operator);
+ return REGISTRY.get(operator);
+ }
+
+ private List<SqlNode> convertSqlNodes(final UnaryOperationExpression
segment) {
+ SqlNode expression = new
ExpressionConverter().convert(segment.getExpression()).orElseThrow(IllegalStateException::new);
+ List<SqlNode> result = new LinkedList<>();
+ result.add(expression);
+ return result;
+ }
+}
diff --git
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
index fcde225efc5..da49df9f066 100644
---
a/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
+++
b/parser/sql/dialect/mysql/src/main/java/org/apache/shardingsphere/sql/parser/mysql/visitor/statement/MySQLStatementVisitor.java
@@ -177,6 +177,7 @@ import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ListExpr
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.MatchAgainstExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ValuesExpression;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.LiteralExpressionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ParameterMarkerExpressionSegment;
@@ -1168,6 +1169,9 @@ public abstract class MySQLStatementVisitor extends
MySQLStatementBaseVisitor<AS
if (null != ctx.BINARY()) {
return visit(ctx.simpleExpr(0));
}
+ if (null != ctx.TILDE_()) {
+ return new UnaryOperationExpression(ctx.start.getStartIndex(),
ctx.stop.getStopIndex(), (ExpressionSegment) visit(ctx.simpleExpr(0)), "~",
ctx.getText());
+ }
if (null != ctx.variable()) {
return visit(ctx.variable());
}
diff --git
a/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/UnaryOperationExpression.java
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/UnaryOperationExpression.java
new file mode 100644
index 00000000000..6deb669176e
--- /dev/null
+++
b/parser/sql/statement/src/main/java/org/apache/shardingsphere/sql/parser/sql/common/segment/dml/expr/UnaryOperationExpression.java
@@ -0,0 +1,41 @@
+/*
+ * 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.sql.parser.sql.common.segment.dml.expr;
+
+import lombok.Getter;
+import lombok.RequiredArgsConstructor;
+import lombok.Setter;
+
+/**
+ * Unary operation expression.
+ */
+@RequiredArgsConstructor
+@Getter
+@Setter
+public final class UnaryOperationExpression implements ExpressionSegment {
+
+ private final int startIndex;
+
+ private final int stopIndex;
+
+ private final ExpressionSegment expression;
+
+ private final String operator;
+
+ private final String text;
+}
diff --git
a/test/it/optimizer/src/test/resources/converter/select-expression.xml
b/test/it/optimizer/src/test/resources/converter/select-expression.xml
index 49de1f6ad52..86da2181105 100644
--- a/test/it/optimizer/src/test/resources/converter/select-expression.xml
+++ b/test/it/optimizer/src/test/resources/converter/select-expression.xml
@@ -49,6 +49,7 @@
<test-cases sql-case-id="select_where_with_predicate_with_in_subquery"
expected-sql="SELECT * FROM "t_order" WHERE
"t_order"."order_id" NOT IN (SELECT "order_id"
FROM "t_order_item" WHERE "status" > 1)"
db-types="PostgreSQL, openGauss" sql-case-types="LITERAL" />
<test-cases sql-case-id="select_where_with_predicate_with_in_subquery"
expected-sql="SELECT * FROM "t_order" WHERE
"t_order"."order_id" NOT IN (SELECT "order_id"
FROM "t_order_item" WHERE "status" > ?)"
db-types="PostgreSQL, openGauss" sql-case-types="PLACEHOLDER" />
<test-cases sql-case-id="select_where_with_simple_expr_with_collate"
expected-sql="SELECT * FROM `t_order` WHERE `order_id` COLLATE
'utf8mb4_0900_ai_ci'" db-types="MySQL" sql-case-types="LITERAL" />
+ <test-cases sql-case-id="select_where_with_simple_expr_with_tilde"
expected-sql="SELECT * FROM `t_order` WHERE ~ `t_order`.`order_id`"
db-types="MySQL" />
<test-cases
sql-case-id="select_where_with_simple_expr_with_odbc_escape_syntax"
expected-sql="SELECT * FROM `t_order` WHERE ?" db-types="MySQL"
sql-case-types="PLACEHOLDER" />
<test-cases
sql-case-id="select_where_with_simple_expr_with_odbc_escape_syntax"
expected-sql="SELECT * FROM `t_order` WHERE '1994-02-04 12:23:00'"
db-types="MySQL" sql-case-types="LITERAL" />
</sql-node-converter-test-cases>
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
index a5316dd8919..888c8a9a69f 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/asserts/segment/expression/ExpressionAssert.java
@@ -38,6 +38,7 @@ import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.Multiset
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.NotExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.TypeCastExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.ValuesExpression;
+import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.UnaryOperationExpression;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.CommonExpressionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.complex.ComplexExpressionSegment;
import
org.apache.shardingsphere.sql.parser.sql.common.segment.dml.expr.simple.ColumnWithJoinOperatorSegment;
@@ -76,6 +77,7 @@ import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.s
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedTypeCastExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedValuesExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedVariableSegment;
+import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.ExpectedUnaryOperationExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.complex.ExpectedCommonExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedLiteralExpression;
import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr.simple.ExpectedParameterMarkerExpression;
@@ -512,6 +514,24 @@ public final class ExpressionAssert {
assertThat(assertContext.getText("Multiset keyword assertion error:
"), actual.getKeyWord(), is(expected.getKeyWord()));
}
+ /**
+ * Assert unary operation expression.
+ * @param assertContext assert context
+ * @param actual actual unary operation expression
+ * @param expected expected unary operation expression
+ */
+ private static void assertUnaryOperationExpression(final
SQLCaseAssertContext assertContext, final UnaryOperationExpression actual,
final ExpectedUnaryOperationExpression expected) {
+ if (null == expected) {
+ assertNull(actual, assertContext.getText("Actual unary operation
expression should not exist."));
+ } else {
+ assertNotNull(actual, assertContext.getText("Actual unary
operation expression should exist."));
+ assertExpression(assertContext, actual.getExpression(),
expected.getExpr());
+ assertThat(assertContext.getText("Unary operation expression
operator assert error."),
+ actual.getOperator(), is(expected.getOperator()));
+ SQLSegmentAssert.assertIs(assertContext, actual, expected);
+ }
+ }
+
/**
* Assert expression by actual expression segment class type.
*
@@ -577,6 +597,8 @@ public final class ExpressionAssert {
assertIntervalExpression(assertContext,
(IntervalExpressionProjection) actual, expected.getIntervalExpression());
} else if (actual instanceof MultisetExpression) {
assertMultisetExpression(assertContext, (MultisetExpression)
actual, expected.getMultisetExpression());
+ } else if (actual instanceof UnaryOperationExpression) {
+ assertUnaryOperationExpression(assertContext,
(UnaryOperationExpression) actual, expected.getUnaryOperationExpression());
} else {
throw new UnsupportedOperationException(String.format("Unsupported
expression: %s", actual.getClass().getName()));
}
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
index 3789526410b..3d24a83d022 100644
---
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedExpression.java
@@ -113,4 +113,7 @@ public final class ExpectedExpression extends
AbstractExpectedSQLSegment {
@XmlElement(name = "multiset-expression")
private ExpectedMultisetExpression multisetExpression;
+
+ @XmlElement(name = "unary-operation-expression")
+ private ExpectedUnaryOperationExpression unaryOperationExpression;
}
diff --git
a/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedUnaryOperationExpression.java
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedUnaryOperationExpression.java
new file mode 100644
index 00000000000..c2e7c066ada
--- /dev/null
+++
b/test/it/parser/src/main/java/org/apache/shardingsphere/test/it/sql/parser/internal/cases/parser/jaxb/segment/impl/expr/ExpectedUnaryOperationExpression.java
@@ -0,0 +1,38 @@
+/*
+ * 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.test.it.sql.parser.internal.cases.parser.jaxb.segment.impl.expr;
+
+import lombok.Getter;
+import lombok.Setter;
+import
org.apache.shardingsphere.test.it.sql.parser.internal.cases.parser.jaxb.segment.AbstractExpectedSQLSegment;
+
+import javax.xml.bind.annotation.XmlElement;
+
+/**
+ * Expected binary operation expression.
+ */
+@Getter
+@Setter
+public class ExpectedUnaryOperationExpression extends
AbstractExpectedSQLSegment implements ExpectedExpressionSegment {
+
+ @XmlElement
+ private String operator;
+
+ @XmlElement
+ private ExpectedExpression expr;
+}
diff --git a/test/it/parser/src/main/resources/case/dml/select-expression.xml
b/test/it/parser/src/main/resources/case/dml/select-expression.xml
index d955db4258d..b1d9e8c7c27 100644
--- a/test/it/parser/src/main/resources/case/dml/select-expression.xml
+++ b/test/it/parser/src/main/resources/case/dml/select-expression.xml
@@ -1809,7 +1809,14 @@
</projections>
<where start-index="22" stop-index="44">
<expr>
- <common-expression text="~t_order.order_id" start-index="28"
stop-index="44" />
+ <unary-operation-expression text="~t_order.order_id"
start-index="28" stop-index="44">
+ <operator>~</operator>
+ <expr>
+ <column name="order_id" start-index="29"
stop-index="44">
+ <owner name="t_order" start-index="29"
stop-index="35" />
+ </column>
+ </expr>
+ </unary-operation-expression>
</expr>
</where>
</select>