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