This is an automated email from the ASF dual-hosted git repository.
chengzhang 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 d3287462b5d Add UnaryOperationExpressionBinder in
ExpressionSegmentBinder (#37905)
d3287462b5d is described below
commit d3287462b5d454aa2e253e2b7fffdf633ed71dc4
Author: Zhengqiang Duan <[email protected]>
AuthorDate: Fri Jan 30 18:35:22 2026 +0800
Add UnaryOperationExpressionBinder in ExpressionSegmentBinder (#37905)
---
.../dml/expression/ExpressionSegmentBinder.java | 5 ++
.../type/UnaryOperationExpressionBinder.java | 53 +++++++++++++++++++
.../type/UnaryOperationExpressionBinderTest.java | 60 ++++++++++++++++++++++
.../statement/core/extractor/ColumnExtractor.java | 6 ++-
4 files changed, 123 insertions(+), 1 deletion(-)
diff --git
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/ExpressionSegmentBinder.java
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/ExpressionSegmentBinder.java
index e864546a39f..39609173725 100644
---
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/ExpressionSegmentBinder.java
+++
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/ExpressionSegmentBinder.java
@@ -37,6 +37,7 @@ import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.type
import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.type.QuantifySubqueryExpressionBinder;
import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.type.RowExpressionBinder;
import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.type.SubquerySegmentBinder;
+import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.type.UnaryOperationExpressionBinder;
import
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.TableSegmentBinderContext;
import
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
@@ -50,6 +51,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.InEx
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.NotExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.QuantifySubqueryExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.RowExpression;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.UnaryOperationExpression;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.subquery.SubqueryExpressionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationDistinctProjectionSegment;
import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
@@ -122,6 +124,9 @@ public final class ExpressionSegmentBinder {
if (segment instanceof RowExpression) {
return RowExpressionBinder.bind((RowExpression) segment,
parentSegmentType, binderContext, tableBinderContexts,
outerTableBinderContexts);
}
+ if (segment instanceof UnaryOperationExpression) {
+ return
UnaryOperationExpressionBinder.bind((UnaryOperationExpression) segment,
parentSegmentType, binderContext, tableBinderContexts,
outerTableBinderContexts);
+ }
// TODO support more ExpressionSegment bound
return segment;
}
diff --git
a/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinder.java
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinder.java
new file mode 100644
index 00000000000..643a84ee9ae
--- /dev/null
+++
b/infra/binder/core/src/main/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinder.java
@@ -0,0 +1,53 @@
+/*
+ * 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.infra.binder.engine.segment.dml.expression.type;
+
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.Multimap;
+import lombok.AccessLevel;
+import lombok.NoArgsConstructor;
+import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
+import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.ExpressionSegmentBinder;
+import
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.TableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.UnaryOperationExpression;
+
+/**
+ * Unary operation expression binder.
+ */
+@NoArgsConstructor(access = AccessLevel.PRIVATE)
+public final class UnaryOperationExpressionBinder {
+
+ /**
+ * Bind unary operation expression segment.
+ *
+ * @param segment unary operation expression
+ * @param parentSegmentType parent segment type
+ * @param binderContext SQL statement binder context
+ * @param tableBinderContexts table binder contexts
+ * @param outerTableBinderContexts outer table binder contexts
+ * @return bound unary operation expression
+ */
+ public static UnaryOperationExpression bind(final UnaryOperationExpression
segment, final SegmentType parentSegmentType,
+ final
SQLStatementBinderContext binderContext, final Multimap<CaseInsensitiveString,
TableSegmentBinderContext> tableBinderContexts,
+ final
Multimap<CaseInsensitiveString, TableSegmentBinderContext>
outerTableBinderContexts) {
+ ExpressionSegment boundExpression =
ExpressionSegmentBinder.bind(segment.getExpression(), parentSegmentType,
binderContext, tableBinderContexts, outerTableBinderContexts);
+ return new UnaryOperationExpression(segment.getStartIndex(),
segment.getStopIndex(), boundExpression, segment.getOperator(),
segment.getText());
+ }
+}
diff --git
a/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinderTest.java
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinderTest.java
new file mode 100644
index 00000000000..3d4931de081
--- /dev/null
+++
b/infra/binder/core/src/test/java/org/apache/shardingsphere/infra/binder/engine/segment/dml/expression/type/UnaryOperationExpressionBinderTest.java
@@ -0,0 +1,60 @@
+/*
+ * 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.infra.binder.engine.segment.dml.expression.type;
+
+import com.cedarsoftware.util.CaseInsensitiveMap.CaseInsensitiveString;
+import com.google.common.collect.LinkedHashMultimap;
+import com.google.common.collect.Multimap;
+import org.apache.shardingsphere.infra.binder.engine.segment.SegmentType;
+import
org.apache.shardingsphere.infra.binder.engine.segment.dml.expression.ExpressionSegmentBinder;
+import
org.apache.shardingsphere.infra.binder.engine.segment.dml.from.context.TableSegmentBinderContext;
+import
org.apache.shardingsphere.infra.binder.engine.statement.SQLStatementBinderContext;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.ExpressionSegment;
+import
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.expr.UnaryOperationExpression;
+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 static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+@ExtendWith(AutoMockExtension.class)
+@StaticMockSettings(ExpressionSegmentBinder.class)
+class UnaryOperationExpressionBinderTest {
+
+ @Test
+ void assertBind() {
+ ExpressionSegment innerSegment = mock(ExpressionSegment.class);
+ UnaryOperationExpression segment = new UnaryOperationExpression(0, 8,
innerSegment, "+", "+user_id");
+ ExpressionSegment boundInnerSegment = mock(ExpressionSegment.class);
+ SQLStatementBinderContext binderContext =
mock(SQLStatementBinderContext.class);
+ Multimap<CaseInsensitiveString, TableSegmentBinderContext>
tableBinderContexts = LinkedHashMultimap.create();
+ Multimap<CaseInsensitiveString, TableSegmentBinderContext>
outerTableBinderContexts = LinkedHashMultimap.create();
+ when(ExpressionSegmentBinder.bind(innerSegment,
SegmentType.PROJECTION, binderContext, tableBinderContexts,
outerTableBinderContexts))
+ .thenReturn(boundInnerSegment);
+ UnaryOperationExpression actual =
UnaryOperationExpressionBinder.bind(segment, SegmentType.PROJECTION,
binderContext, tableBinderContexts, outerTableBinderContexts);
+ assertThat(actual.getStartIndex(), is(0));
+ assertThat(actual.getStopIndex(), is(8));
+ assertThat(actual.getExpression(), is(boundInnerSegment));
+ assertThat(actual.getOperator(), is("+"));
+ assertThat(actual.getText(), is("+user_id"));
+ }
+}
diff --git
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/extractor/ColumnExtractor.java
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/extractor/ColumnExtractor.java
index 37f11534473..513684908eb 100644
---
a/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/extractor/ColumnExtractor.java
+++
b/parser/sql/statement/core/src/main/java/org/apache/shardingsphere/sql/parser/statement/core/extractor/ColumnExtractor.java
@@ -49,6 +49,7 @@ import
org.apache.shardingsphere.sql.parser.statement.core.segment.generic.table
import
org.apache.shardingsphere.sql.parser.statement.core.statement.type.dml.SelectStatement;
import java.util.Collection;
+import java.util.LinkedHashSet;
import java.util.LinkedList;
/**
@@ -64,7 +65,10 @@ public final class ColumnExtractor {
* @return column segments
*/
public static Collection<ColumnSegment> extract(final ExpressionSegment
expression) {
- Collection<ColumnSegment> result = new LinkedList<>();
+ Collection<ColumnSegment> result = new LinkedHashSet<>();
+ if (expression instanceof ColumnSegment) {
+ result.add((ColumnSegment) expression);
+ }
if (expression instanceof BinaryOperationExpression) {
extractColumnsInBinaryOperationExpression((BinaryOperationExpression)
expression, result);
}