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 5f63eba4553 Fix INTERVAL sharding on one-sided range outside datetime
bounds (#39862)
5f63eba4553 is described below
commit 5f63eba4553684a547867c325a985ca08b87f4bb
Author: Eunbin Son <[email protected]>
AuthorDate: Tue Sep 22 23:14:14 2026 +0900
Fix INTERVAL sharding on one-sided range outside datetime bounds (#39862)
Co-authored-by: Liang Zhang <[email protected]>
---
RELEASE-NOTES.md | 1 +
.../datetime/IntervalShardingAlgorithm.java | 26 +++++++++++++---------
.../datetime/IntervalShardingAlgorithmTest.java | 23 +++++++++++++++++++
3 files changed, 40 insertions(+), 10 deletions(-)
diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md
index e767b69854d..fc22e16bf0b 100644
--- a/RELEASE-NOTES.md
+++ b/RELEASE-NOTES.md
@@ -86,6 +86,7 @@
1. Sharding: Compute the Snowflake key generator epoch in UTC instead of the
JVM default timezone -
[#38932](https://github.com/apache/shardingsphere/pull/38932)
1. Sharding: Fix order-dependent data source intersection in Cartesian routing
- [#39407](https://github.com/apache/shardingsphere/pull/39407)
1. Sharding: Fix incorrect AVG(DISTINCT) merge result across shards -
[#39429](https://github.com/apache/shardingsphere/pull/39429)
+1. Sharding: Fix INTERVAL sharding on one-sided range outside datetime bounds
- [#39862](https://github.com/apache/shardingsphere/pull/39862)
1. Sharding: Fix GROUP_CONCAT merge result when all values are NULL -
[#39860](https://github.com/apache/shardingsphere/pull/39860)
1. Sharding: Fix swapped start and stop offset in sharding value offset error
message - [#39858](https://github.com/apache/shardingsphere/pull/39858)
1. Sharding: Fix sharding constraint reviser removing every actual table
suffix - [#39868](https://github.com/apache/shardingsphere/pull/39868)
diff --git
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
index e87ba16e81a..66d8bfd6a06 100644
---
a/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
+++
b/features/sharding/core/src/main/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithm.java
@@ -17,7 +17,6 @@
package org.apache.shardingsphere.sharding.algorithm.sharding.datetime;
-import com.google.common.collect.BoundType;
import com.google.common.collect.Range;
import
org.apache.shardingsphere.infra.algorithm.core.exception.AlgorithmInitializationException;
import org.apache.shardingsphere.infra.exception.ShardingSpherePreconditions;
@@ -141,10 +140,9 @@ public final class IntervalShardingAlgorithm implements
StandardShardingAlgorith
Collection<String> result = new HashSet<>();
TemporalHandler<T> temporalHandler =
TemporalHandlerFactory.newInstance(dateTimeLower);
T dateTimeUpper = temporalHandler.convertTo(this.dateTimeUpper);
- T dateTimeLower = temporalHandler.convertTo(this.dateTimeLower);
T calculateTimeAsView = temporalHandler.convertTo(this.dateTimeLower);
while (!temporalHandler.isAfter(calculateTimeAsView, dateTimeUpper,
stepAmount)) {
- if (hasIntersection(Range.closedOpen(calculateTimeAsView,
temporalHandler.add(calculateTimeAsView, stepAmount, stepUnit)), range,
dateTimeLower, dateTimeUpper, temporalHandler)) {
+ if (hasIntersection(Range.closedOpen(calculateTimeAsView,
temporalHandler.add(calculateTimeAsView, stepAmount, stepUnit)), range,
temporalHandler)) {
result.addAll(getMatchedTables(calculateTimeAsView,
availableTargetNames, temporalHandler));
}
calculateTimeAsView = temporalHandler.add(calculateTimeAsView,
stepAmount, stepUnit);
@@ -157,16 +155,24 @@ public final class IntervalShardingAlgorithm implements
StandardShardingAlgorith
return availableTargetNames.parallelStream().filter(each ->
each.endsWith(tableSuffixPattern.format(temporalHandler.convertTo(calculateTimeAsView)))).collect(Collectors.toSet());
}
- private <T extends TemporalAccessor & Comparable<?>> boolean
hasIntersection(final Range<T> calculateRange, final Range<Comparable<?>> range,
-
final T temporalLower, final T temporalUpper, final TemporalHandler<T>
temporalHandler) {
- T lower = range.hasLowerBound() ? parseTemporal(range.lowerEndpoint(),
temporalHandler) : temporalLower;
- T upper = range.hasUpperBound() ? parseTemporal(range.upperEndpoint(),
temporalHandler) : temporalUpper;
- BoundType lowerBoundType = range.hasLowerBound() ?
range.lowerBoundType() : BoundType.CLOSED;
- BoundType upperBoundType = range.hasUpperBound() ?
range.upperBoundType() : BoundType.CLOSED;
- Range<T> dateTimeRange = Range.range(lower, lowerBoundType, upper,
upperBoundType);
+ private <T extends TemporalAccessor & Comparable<?>> boolean
hasIntersection(final Range<T> calculateRange, final Range<Comparable<?>>
range, final TemporalHandler<T> temporalHandler) {
+ Range<T> dateTimeRange = convertToTemporalRange(range,
temporalHandler);
return calculateRange.isConnected(dateTimeRange) &&
!calculateRange.intersection(dateTimeRange).isEmpty();
}
+ private <T extends TemporalAccessor & Comparable<?>> Range<T>
convertToTemporalRange(final Range<Comparable<?>> range, final
TemporalHandler<T> temporalHandler) {
+ if (range.hasLowerBound() && range.hasUpperBound()) {
+ return Range.range(parseTemporal(range.lowerEndpoint(),
temporalHandler), range.lowerBoundType(), parseTemporal(range.upperEndpoint(),
temporalHandler), range.upperBoundType());
+ }
+ if (range.hasLowerBound()) {
+ return Range.downTo(parseTemporal(range.lowerEndpoint(),
temporalHandler), range.lowerBoundType());
+ }
+ if (range.hasUpperBound()) {
+ return Range.upTo(parseTemporal(range.upperEndpoint(),
temporalHandler), range.upperBoundType());
+ }
+ return Range.all();
+ }
+
private <T extends TemporalAccessor> T parseTemporal(final Comparable<?>
endpoint, final TemporalHandler<T> temporalHandler) {
String dateTimeText = getDateTimeText(endpoint);
return dateTimeText.length() >= dateTimePatternLength
diff --git
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
index 5e71b52c1c9..00f74ca2584 100644
---
a/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
+++
b/features/sharding/core/src/test/java/org/apache/shardingsphere/sharding/algorithm/sharding/datetime/IntervalShardingAlgorithmTest.java
@@ -45,6 +45,7 @@ import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.UnsupportedTemporalTypeException;
import java.util.Collection;
+import java.util.Collections;
import java.util.Date;
import java.util.LinkedList;
import java.util.Properties;
@@ -53,6 +54,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.is;
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
+import static org.junit.jupiter.api.Assertions.assertTrue;
class IntervalShardingAlgorithmTest {
@@ -170,6 +172,27 @@ class IntervalShardingAlgorithmTest {
assertThat(actual.size(), is(31));
}
+ @Test
+ void assertUpperHalfRangeDoShardingBeforeDateTimeLower() {
+ Collection<String> actual =
shardingAlgorithmByDay.doSharding(availableTablesForDayDataSources,
+ new RangeShardingValue<>("t_order", "create_time",
DATA_NODE_INFO, Range.atMost("2021-05-01 00:00:00")));
+ assertTrue(actual.isEmpty());
+ }
+
+ @Test
+ void assertLowerHalfRangeDoShardingAfterDateTimeUpper() {
+ Collection<String> actual =
shardingAlgorithmByDay.doSharding(availableTablesForDayDataSources,
+ new RangeShardingValue<>("t_order", "create_time",
DATA_NODE_INFO, Range.atLeast("2021-08-02 00:00:00")));
+ assertTrue(actual.isEmpty());
+ }
+
+ @Test
+ void assertLowerHalfRangeDoShardingFromDateTimeUpper() {
+ Collection<String> actual =
shardingAlgorithmByDay.doSharding(availableTablesForDayDataSources,
+ new RangeShardingValue<>("t_order", "create_time",
DATA_NODE_INFO, Range.greaterThan("2021-07-31 00:00:00")));
+ assertThat(actual, is(Collections.singleton("t_order_20210731")));
+ }
+
@Test
void assertPreciseDoShardingByDay() {
assertThat(shardingAlgorithmByDay.doSharding(availableTablesForDayDataSources,