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,

Reply via email to