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

terrymanu 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 96e16fd12fe Support ORDER BY MySQL VARBINARY column in sharding result 
merge (#38699)
96e16fd12fe is described below

commit 96e16fd12fe6c530943619081b778aaf7beaa198
Author: Lyphixia Wang <[email protected]>
AuthorDate: Thu May 28 16:15:48 2026 +0800

    Support ORDER BY MySQL VARBINARY column in sharding result merge (#38699)
    
    * Support ORDER BY MySQL VARBINARY column by wrapping byte[] in a 
Comparable adapter
    
    * Add release notes entry for #38699
    
    * Extend byte[] normalization to group-by and distinct merge paths
    
    Address review feedback by extending the ComparableByteArray wrapper from 
the
    plain ORDER BY path to the adjacent GROUP BY and DISTINCT merge paths so 
that
    byte[] values from VARBINARY columns are merged by content rather than by
    reference identity across QueryResult instances from different shards.
    
    - Move ComparableByteArray from merge.dql.orderby to merge.dql so it can be
      reused by both orderby and groupby subpackages.
    - Apply the wrapper inside GroupByValue.getGroupByValues so group keys 
produce
      content-stable equals and hashCode via lombok @EqualsAndHashCode.
    - Apply the wrapper inside GroupByRowComparator.compare so byte[] order-by
      values are accepted by the Comparable precondition.
    - Add multi-shard end-to-end tests for plain ORDER BY, GROUP BY ... ORDER 
BY,
      and DISTINCT ... ORDER BY with equal byte contents coming from different
      QueryResult instances; add unit coverage for GroupByValue.equals/hashCode 
and
      GroupByRowComparator with byte[] values.
    
    * Remove redundant OrderByValue VARBINARY direct test now that the same 
path is exercised end-to-end through OrderByStreamMergedResultTest
---
 RELEASE-NOTES.md                                   |  1 +
 .../sharding/merge/dql/ComparableByteArray.java    | 49 ++++++++++++++
 .../merge/dql/groupby/GroupByRowComparator.java    | 20 ++++--
 .../sharding/merge/dql/groupby/GroupByValue.java   |  9 ++-
 .../sharding/merge/dql/orderby/OrderByValue.java   | 15 +++-
 .../merge/dql/ComparableByteArrayTest.java         | 56 +++++++++++++++
 .../dql/groupby/GroupByMemoryMergedResultTest.java | 79 ++++++++++++++++++++++
 .../dql/groupby/GroupByRowComparatorTest.java      | 17 +++++
 .../merge/dql/groupby/GroupByValueTest.java        | 32 ++++++++-
 .../dql/orderby/OrderByStreamMergedResultTest.java | 29 ++++++++
 10 files changed, 296 insertions(+), 11 deletions(-)

diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index 4401ad72277..b608a42fb20 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -22,6 +22,7 @@
 1. Mode: Fix rule metadata not removed from memory after dropping rules in 
Etcd cluster mode - 
[#38561](https://github.com/apache/shardingsphere/pull/38561)
 1. Pipeline: Fix MySQL JSON literal decoding in migration - 
[#38622](https://github.com/apache/shardingsphere/pull/38622)
 1. Pipeline: Fix MySQL zero-value temporal binlog decoding with fractional 
precision in migration - 
[#35531](https://github.com/apache/shardingsphere/issues/35531)
+1. Sharding: Support ORDER BY MySQL VARBINARY column by wrapping byte[] values 
in a Comparable adapter - 
[#38699](https://github.com/apache/shardingsphere/pull/38699)
 
 ### Enhancements
 
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArray.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArray.java
new file mode 100644
index 00000000000..ea5273d5be3
--- /dev/null
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArray.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sharding.merge.dql;
+
+import lombok.EqualsAndHashCode;
+import lombok.RequiredArgsConstructor;
+
+/**
+ * Comparable wrapper for byte arrays ordered by unsigned lexicographic 
comparison, matching MySQL VARBINARY collation.
+ *
+ * <p>Used by {@code OrderByValue}, {@code GroupByValue}, and {@code 
GroupByRowComparator} so that {@code byte[]} values
+ * from VARBINARY columns sort, group and de-duplicate by content rather than 
reference identity across {@code QueryResult}
+ * instances coming from different shards. Declared {@code public} because 
Java packages are flat: a package-private type
+ * placed in {@code merge.dql} would be invisible to its {@code 
merge.dql.orderby} and {@code merge.dql.groupby}
+ * subpackages, which is the only reason this class is not package-private.</p>
+ */
+@RequiredArgsConstructor
+@EqualsAndHashCode
+public final class ComparableByteArray implements 
Comparable<ComparableByteArray> {
+    
+    private final byte[] value;
+    
+    @Override
+    public int compareTo(final ComparableByteArray other) {
+        int minLength = Math.min(value.length, other.value.length);
+        for (int index = 0; index < minLength; index++) {
+            int diff = (value[index] & 0xFF) - (other.value[index] & 0xFF);
+            if (0 != diff) {
+                return diff;
+            }
+        }
+        return value.length - other.value.length;
+    }
+}
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparator.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparator.java
index a69d47341c0..a93f5bda843 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparator.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparator.java
@@ -23,6 +23,7 @@ import 
org.apache.shardingsphere.infra.binder.context.statement.type.dml.SelectS
 import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
 import 
org.apache.shardingsphere.infra.merge.result.impl.memory.MemoryQueryResultRow;
 import 
org.apache.shardingsphere.sharding.exception.data.NotImplementComparableValueException;
+import org.apache.shardingsphere.sharding.merge.dql.ComparableByteArray;
 import org.apache.shardingsphere.sharding.merge.dql.orderby.CompareUtils;
 
 import java.util.Collection;
@@ -50,11 +51,9 @@ public final class GroupByRowComparator implements 
Comparator<MemoryQueryResultR
     @SuppressWarnings("rawtypes")
     private int compare(final MemoryQueryResultRow o1, final 
MemoryQueryResultRow o2, final Collection<OrderByItem> orderByItems) {
         for (OrderByItem each : orderByItems) {
-            Object orderValue1 = o1.getCell(each.getIndex());
-            ShardingSpherePreconditions.checkState(null == orderValue1 || 
orderValue1 instanceof Comparable, () -> new 
NotImplementComparableValueException("Order by", orderValue1));
-            Object orderValue2 = o2.getCell(each.getIndex());
-            ShardingSpherePreconditions.checkState(null == orderValue2 || 
orderValue2 instanceof Comparable, () -> new 
NotImplementComparableValueException("Order by", orderValue2));
-            int result = CompareUtils.compareTo((Comparable) orderValue1, 
(Comparable) orderValue2, each.getSegment().getOrderDirection(),
+            Comparable orderValue1 = toComparable(o1.getCell(each.getIndex()));
+            Comparable orderValue2 = toComparable(o2.getCell(each.getIndex()));
+            int result = CompareUtils.compareTo(orderValue1, orderValue2, 
each.getSegment().getOrderDirection(),
                     
each.getSegment().getNullsOrderType(selectStatementContext.getSqlStatement().getDatabaseType()),
 valueCaseSensitive.get(each.getIndex()));
             if (0 != result) {
                 return result;
@@ -62,4 +61,15 @@ public final class GroupByRowComparator implements 
Comparator<MemoryQueryResultR
         }
         return 0;
     }
+    
+    private Comparable<?> toComparable(final Object value) {
+        if (null == value) {
+            return null;
+        }
+        if (value instanceof byte[]) {
+            return new ComparableByteArray((byte[]) value);
+        }
+        ShardingSpherePreconditions.checkState(value instanceof Comparable, () 
-> new NotImplementComparableValueException("Order by", value));
+        return (Comparable<?>) value;
+    }
 }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValue.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValue.java
index c51890f5055..88941f1ce62 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValue.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValue.java
@@ -19,8 +19,9 @@ package org.apache.shardingsphere.sharding.merge.dql.groupby;
 
 import lombok.EqualsAndHashCode;
 import lombok.Getter;
-import 
org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
 import 
org.apache.shardingsphere.infra.binder.context.segment.select.orderby.OrderByItem;
+import 
org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryResult;
+import org.apache.shardingsphere.sharding.merge.dql.ComparableByteArray;
 
 import java.sql.SQLException;
 import java.util.ArrayList;
@@ -43,8 +44,12 @@ public final class GroupByValue {
     private List<?> getGroupByValues(final QueryResult queryResult, final 
Collection<OrderByItem> groupByItems) throws SQLException {
         List<Object> result = new ArrayList<>(groupByItems.size());
         for (OrderByItem each : groupByItems) {
-            result.add(queryResult.getValue(each.getIndex(), Object.class));
+            
result.add(normalizeForEquality(queryResult.getValue(each.getIndex(), 
Object.class)));
         }
         return result;
     }
+    
+    private static Object normalizeForEquality(final Object value) {
+        return value instanceof byte[] ? new ComparableByteArray((byte[]) 
value) : value;
+    }
 }
diff --git 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByValue.java
 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByValue.java
index 70ce4ef8b8a..bd206002946 100644
--- 
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByValue.java
+++ 
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByValue.java
@@ -25,6 +25,7 @@ import 
org.apache.shardingsphere.infra.executor.sql.execute.result.query.QueryRe
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereSchema;
 import 
org.apache.shardingsphere.infra.metadata.database.schema.model.ShardingSphereTable;
 import 
org.apache.shardingsphere.sharding.exception.data.NotImplementComparableValueException;
+import org.apache.shardingsphere.sharding.merge.dql.ComparableByteArray;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.ColumnOrderByItemSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.IndexOrderByItemSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.item.OrderByItemSegment;
@@ -108,12 +109,22 @@ public final class OrderByValue implements 
Comparable<OrderByValue> {
         List<Comparable<?>> result = new ArrayList<>(orderByItems.size());
         for (OrderByItem each : orderByItems) {
             Object value = queryResult.getValue(each.getIndex(), Object.class);
-            ShardingSpherePreconditions.checkState(null == value || value 
instanceof Comparable, () -> new NotImplementComparableValueException("Order 
by", value));
-            result.add((Comparable<?>) value);
+            result.add(toComparable(value));
         }
         return result;
     }
     
+    private static Comparable<?> toComparable(final Object value) {
+        if (null == value) {
+            return null;
+        }
+        if (value instanceof byte[]) {
+            return new ComparableByteArray((byte[]) value);
+        }
+        ShardingSpherePreconditions.checkState(value instanceof Comparable, () 
-> new NotImplementComparableValueException("Order by", value));
+        return (Comparable<?>) value;
+    }
+    
     @Override
     public int compareTo(final OrderByValue orderByValue) {
         int i = 0;
diff --git 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArrayTest.java
 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArrayTest.java
new file mode 100644
index 00000000000..134d6022aec
--- /dev/null
+++ 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/ComparableByteArrayTest.java
@@ -0,0 +1,56 @@
+/*
+ * 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.sharding.merge.dql;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.greaterThan;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.lessThan;
+
+class ComparableByteArrayTest {
+    
+    @Test
+    void assertCompareToEqual() {
+        assertThat(new ComparableByteArray(new byte[]{1, 2, 3}).compareTo(new 
ComparableByteArray(new byte[]{1, 2, 3})), is(0));
+    }
+    
+    @Test
+    void assertCompareToFirstByteDiffers() {
+        assertThat(new ComparableByteArray(new byte[]{1}).compareTo(new 
ComparableByteArray(new byte[]{2})), lessThan(0));
+        assertThat(new ComparableByteArray(new byte[]{2}).compareTo(new 
ComparableByteArray(new byte[]{1})), greaterThan(0));
+    }
+    
+    @Test
+    void assertCompareToUnsignedHighByteIsLarger() {
+        assertThat(new ComparableByteArray(new byte[]{(byte) 
0x80}).compareTo(new ComparableByteArray(new byte[]{(byte) 0x7F})), 
greaterThan(0));
+    }
+    
+    @Test
+    void assertCompareToShorterPrefixIsLess() {
+        assertThat(new ComparableByteArray(new byte[]{1, 2}).compareTo(new 
ComparableByteArray(new byte[]{1, 2, 3})), lessThan(0));
+        assertThat(new ComparableByteArray(new byte[]{1, 2, 3}).compareTo(new 
ComparableByteArray(new byte[]{1, 2})), greaterThan(0));
+    }
+    
+    @Test
+    void assertCompareToEmptyArrays() {
+        assertThat(new ComparableByteArray(new byte[0]).compareTo(new 
ComparableByteArray(new byte[0])), is(0));
+        assertThat(new ComparableByteArray(new byte[0]).compareTo(new 
ComparableByteArray(new byte[]{0})), lessThan(0));
+    }
+}
diff --git 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByMemoryMergedResultTest.java
 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByMemoryMergedResultTest.java
index 8fec2586301..9889238f049 100644
--- 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByMemoryMergedResultTest.java
+++ 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByMemoryMergedResultTest.java
@@ -31,7 +31,9 @@ import 
org.apache.shardingsphere.infra.spi.type.typed.TypedSPILoader;
 import org.apache.shardingsphere.sharding.merge.dql.ShardingDQLResultMerger;
 import 
org.apache.shardingsphere.sql.parser.statement.core.enums.AggregationType;
 import 
org.apache.shardingsphere.sql.parser.statement.core.enums.OrderDirection;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.column.ColumnSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.AggregationProjectionSegment;
+import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ColumnProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ProjectionsSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.item.ShorthandProjectionSegment;
 import 
org.apache.shardingsphere.sql.parser.statement.core.segment.dml.order.GroupBySegment;
@@ -270,4 +272,81 @@ class GroupByMemoryMergedResultTest {
         return new SelectStatementContext(
                 selectStatement, new 
ShardingSphereMetaData(Collections.singleton(database), mock(), mock(), 
mock()), "foo_db", Collections.emptyList());
     }
+    
+    @Test
+    void assertGroupByVarBinaryFromMultipleResults() throws SQLException {
+        when(database.getName()).thenReturn("db_schema");
+        QueryResult queryResult1 = createGroupByVarBinaryQueryResult();
+        when(queryResult1.next()).thenReturn(true, false);
+        when(queryResult1.getValue(1, Object.class)).thenReturn(1);
+        when(queryResult1.getValue(2, Object.class)).thenReturn(new 
byte[]{0x10});
+        QueryResult queryResult2 = createGroupByVarBinaryQueryResult();
+        when(queryResult2.next()).thenReturn(true, false);
+        when(queryResult2.getValue(1, Object.class)).thenReturn(1);
+        when(queryResult2.getValue(2, Object.class)).thenReturn(new 
byte[]{0x10});
+        QueryResult queryResult3 = createGroupByVarBinaryQueryResult();
+        when(queryResult3.next()).thenReturn(true, false);
+        when(queryResult3.getValue(1, Object.class)).thenReturn(1);
+        when(queryResult3.getValue(2, Object.class)).thenReturn(new 
byte[]{(byte) 0x80});
+        ShardingDQLResultMerger resultMerger = new 
ShardingDQLResultMerger(databaseType);
+        MergedResult actual = resultMerger.merge(Arrays.asList(queryResult1, 
queryResult2, queryResult3), createSelectStatementContextForCountGroupBy(), 
database, mock(ConnectionContext.class));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(2, Object.class), is(new 
byte[]{0x10}));
+        assertThat(actual.getValue(1, Object.class), is(new BigDecimal(2)));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(2, Object.class), is(new 
byte[]{(byte) 0x80}));
+        assertThat(actual.getValue(1, Object.class), is(new BigDecimal(1)));
+        assertFalse(actual.next());
+    }
+    
+    private QueryResult createGroupByVarBinaryQueryResult() throws 
SQLException {
+        QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
+        when(result.getMetaData().getColumnCount()).thenReturn(2);
+        when(result.getMetaData().getColumnLabel(1)).thenReturn("COUNT(*)");
+        
when(result.getMetaData().getColumnLabel(2)).thenReturn("varbinary_col");
+        return result;
+    }
+    
+    @Test
+    void assertDistinctVarBinaryFromMultipleResults() throws SQLException {
+        when(database.getName()).thenReturn("foo_db");
+        QueryResult queryResult1 = createDistinctVarBinaryQueryResult();
+        when(queryResult1.next()).thenReturn(true, false);
+        when(queryResult1.getValue(1, Object.class)).thenReturn(new 
byte[]{0x10});
+        QueryResult queryResult2 = createDistinctVarBinaryQueryResult();
+        when(queryResult2.next()).thenReturn(true, false);
+        when(queryResult2.getValue(1, Object.class)).thenReturn(new 
byte[]{0x10});
+        QueryResult queryResult3 = createDistinctVarBinaryQueryResult();
+        when(queryResult3.next()).thenReturn(true, false);
+        when(queryResult3.getValue(1, Object.class)).thenReturn(new 
byte[]{(byte) 0x80});
+        ShardingDQLResultMerger resultMerger = new 
ShardingDQLResultMerger(databaseType);
+        MergedResult actual = resultMerger.merge(
+                Arrays.asList(queryResult1, queryResult2, queryResult3), 
createDistinctVarBinaryContext(), database, mock(ConnectionContext.class));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(1, Object.class), is(new 
byte[]{0x10}));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(1, Object.class), is(new 
byte[]{(byte) 0x80}));
+        assertFalse(actual.next());
+    }
+    
+    private QueryResult createDistinctVarBinaryQueryResult() throws 
SQLException {
+        QueryResult result = mock(QueryResult.class, RETURNS_DEEP_STUBS);
+        when(result.getMetaData().getColumnCount()).thenReturn(1);
+        
when(result.getMetaData().getColumnLabel(1)).thenReturn("varbinary_col");
+        return result;
+    }
+    
+    private SelectStatementContext createDistinctVarBinaryContext() {
+        ProjectionsSegment projectionsSegment = new ProjectionsSegment(0, 0);
+        projectionsSegment.setDistinctRow(true);
+        projectionsSegment.getProjections().add(new 
ColumnProjectionSegment(new ColumnSegment(0, 0, new 
IdentifierValue("varbinary_col"))));
+        SelectStatement selectStatement = SelectStatement.builder()
+                .databaseType(databaseType)
+                .projections(projectionsSegment)
+                .orderBy(new OrderBySegment(0, 0, 
Collections.singletonList(new IndexOrderByItemSegment(0, 0, 1, 
OrderDirection.ASC, NullsOrderType.FIRST))))
+                .from(new SimpleTableSegment(new TableNameSegment(0, 0, new 
IdentifierValue("t_order"))))
+                .build();
+        return new SelectStatementContext(
+                selectStatement, new 
ShardingSphereMetaData(Collections.singleton(database), mock(), mock(), 
mock()), "foo_db", Collections.emptyList());
+    }
 }
diff --git 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparatorTest.java
 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparatorTest.java
index d6b06fd61f3..978596fba2c 100644
--- 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparatorTest.java
+++ 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByRowComparatorTest.java
@@ -162,6 +162,23 @@ class GroupByRowComparatorTest {
         assertThat(groupByRowComparator.compare(o1, o2), is(0));
     }
     
+    @Test
+    void assertCompareToForVarBinaryWithGroupByItems() throws SQLException {
+        GroupBySegment groupBy = new GroupBySegment(0, 0, 
Collections.singletonList(
+                new IndexOrderByItemSegment(0, 0, 1, OrderDirection.ASC, 
NullsOrderType.FIRST)));
+        SelectStatement selectStatement = createSelectStatement(groupBy, new 
OrderBySegment(0, 0, Collections.emptyList()));
+        ShardingSphereDatabase database = mock(ShardingSphereDatabase.class, 
RETURNS_DEEP_STUBS);
+        when(database.getName()).thenReturn("foo_db");
+        SelectStatementContext selectStatementContext = new 
SelectStatementContext(
+                selectStatement, createShardingSphereMetaData(database), 
"foo_db", Collections.emptyList());
+        GroupByRowComparator groupByRowComparator = new 
GroupByRowComparator(selectStatementContext, Arrays.asList(false, false));
+        MemoryQueryResultRow smaller = new 
MemoryQueryResultRow(mockQueryResult((Object) new byte[]{1, 2}));
+        MemoryQueryResultRow larger = new 
MemoryQueryResultRow(mockQueryResult((Object) new byte[]{(byte) 0x80}));
+        MemoryQueryResultRow equalToSmaller = new 
MemoryQueryResultRow(mockQueryResult((Object) new byte[]{1, 2}));
+        assertTrue(groupByRowComparator.compare(smaller, larger) < 0);
+        assertThat(groupByRowComparator.compare(smaller, equalToSmaller), 
is(0));
+    }
+    
     private QueryResult mockQueryResult(final Object... values) throws 
SQLException {
         ResultSet resultSet = mock(ResultSet.class);
         ResultSetMetaData resultSetMetaData = mock(ResultSetMetaData.class);
diff --git 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValueTest.java
 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValueTest.java
index 3e8457dd9ff..4957bfcfe19 100644
--- 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValueTest.java
+++ 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/groupby/GroupByValueTest.java
@@ -30,11 +30,14 @@ import org.mockito.junit.jupiter.MockitoExtension;
 
 import java.sql.SQLException;
 import java.util.Arrays;
+import java.util.Collections;
 import java.util.List;
 
 import static org.hamcrest.MatcherAssert.assertThat;
 import static org.hamcrest.Matchers.is;
 import static org.hamcrest.Matchers.not;
+import static org.mockito.Mockito.lenient;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
 
 @ExtendWith(MockitoExtension.class)
@@ -45,8 +48,8 @@ class GroupByValueTest {
     
     @BeforeEach
     void setUp() throws SQLException {
-        when(queryResult.getValue(1, Object.class)).thenReturn("1");
-        when(queryResult.getValue(3, Object.class)).thenReturn("3");
+        lenient().when(queryResult.getValue(1, Object.class)).thenReturn("1");
+        lenient().when(queryResult.getValue(3, Object.class)).thenReturn("3");
     }
     
     @Test
@@ -83,6 +86,31 @@ class GroupByValueTest {
         assertThat(groupByValue1.hashCode(), not(groupByValue2.hashCode()));
     }
     
+    @Test
+    void assertGroupByValueEqualsForVarBinary() throws SQLException {
+        QueryResult left = mock(QueryResult.class);
+        when(left.getValue(1, Object.class)).thenReturn(new byte[]{1, 2, 3});
+        QueryResult right = mock(QueryResult.class);
+        when(right.getValue(1, Object.class)).thenReturn(new byte[]{1, 2, 3});
+        OrderByItem item = createOrderByItem(new IndexOrderByItemSegment(0, 0, 
1, OrderDirection.ASC, NullsOrderType.FIRST));
+        GroupByValue groupByValue1 = new GroupByValue(left, 
Collections.singletonList(item));
+        GroupByValue groupByValue2 = new GroupByValue(right, 
Collections.singletonList(item));
+        assertThat(groupByValue1, is(groupByValue2));
+        assertThat(groupByValue1.hashCode(), is(groupByValue2.hashCode()));
+    }
+    
+    @Test
+    void assertGroupByValueNotEqualsForVarBinaryWithDifferentContent() throws 
SQLException {
+        QueryResult left = mock(QueryResult.class);
+        when(left.getValue(1, Object.class)).thenReturn(new byte[]{1, 2, 3});
+        QueryResult right = mock(QueryResult.class);
+        when(right.getValue(1, Object.class)).thenReturn(new byte[]{1, 2, 4});
+        OrderByItem item = createOrderByItem(new IndexOrderByItemSegment(0, 0, 
1, OrderDirection.ASC, NullsOrderType.FIRST));
+        GroupByValue groupByValue1 = new GroupByValue(left, 
Collections.singletonList(item));
+        GroupByValue groupByValue2 = new GroupByValue(right, 
Collections.singletonList(item));
+        assertThat(groupByValue1, not(groupByValue2));
+    }
+    
     private OrderByItem createOrderByItem(final IndexOrderByItemSegment 
indexOrderByItemSegment) {
         OrderByItem result = new OrderByItem(indexOrderByItemSegment);
         result.setIndex(indexOrderByItemSegment.getColumnIndex());
diff --git 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByStreamMergedResultTest.java
 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByStreamMergedResultTest.java
index 6710805c285..106a74e66df 100644
--- 
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByStreamMergedResultTest.java
+++ 
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/merge/dql/orderby/OrderByStreamMergedResultTest.java
@@ -204,6 +204,35 @@ class OrderByStreamMergedResultTest {
         assertFalse(actual.next());
     }
     
+    @Test
+    void assertNextForVarBinaryFromMultipleResults() throws SQLException {
+        List<QueryResult> queryResults = 
Arrays.asList(mock(QueryResult.class), mock(QueryResult.class), 
mock(QueryResult.class));
+        for (int i = 0; i < 3; i++) {
+            QueryResultMetaData metaData = mock(QueryResultMetaData.class);
+            when(queryResults.get(i).getMetaData()).thenReturn(metaData);
+            when(metaData.getColumnName(1)).thenReturn("col1");
+            when(metaData.getColumnName(2)).thenReturn("col2");
+        }
+        when(queryResults.get(0).next()).thenReturn(true, false);
+        when(queryResults.get(0).getValue(1, Object.class)).thenReturn(new 
byte[]{0x10});
+        when(queryResults.get(0).getValue(2, Object.class)).thenReturn(new 
byte[]{0x01});
+        when(queryResults.get(1).next()).thenReturn(true, false);
+        when(queryResults.get(1).getValue(1, Object.class)).thenReturn(new 
byte[]{0x10});
+        when(queryResults.get(1).getValue(2, Object.class)).thenReturn(new 
byte[]{0x02});
+        when(queryResults.get(2).next()).thenReturn(true, false);
+        when(queryResults.get(2).getValue(1, Object.class)).thenReturn(new 
byte[]{(byte) 0x80});
+        when(queryResults.get(2).getValue(2, Object.class)).thenReturn(new 
byte[]{0x03});
+        ShardingDQLResultMerger resultMerger = new 
ShardingDQLResultMerger(databaseType);
+        MergedResult actual = resultMerger.merge(queryResults, 
selectStatementContext, createDatabase(), mock(ConnectionContext.class));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(1, Object.class), is(new 
byte[]{0x10}));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(1, Object.class), is(new 
byte[]{0x10}));
+        assertTrue(actual.next());
+        assertThat((byte[]) actual.getValue(1, Object.class), is(new 
byte[]{(byte) 0x80}));
+        assertFalse(actual.next());
+    }
+    
     private ShardingSphereDatabase createDatabase() {
         ShardingSphereColumn column1 = new ShardingSphereColumn("col1", 0, 
false, false, true, true, false, false);
         ShardingSphereColumn column2 = new ShardingSphereColumn("col2", 0, 
false, false, false, true, false, false);

Reply via email to