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

Reply via email to