github-actions[bot] commented on code in PR #65219:
URL: https://github.com/apache/doris/pull/65219#discussion_r3627566479
##########
fe/fe-core/src/test/java/org/apache/doris/catalog/DynamicPartitionTableTest.java:
##########
@@ -2219,19 +2318,177 @@ public void testTimeStampTzDynamicPartitionHourUnit()
throws Exception {
Assert.assertEquals("Hour partition name length: " +
partitionName,
11, partitionName.length());
- // Verify range validity and UTC boundaries
+ // Verify range validity
Range<PartitionKey> range = item.getItems();
Assert.assertTrue("lower must be < upper",
range.lowerEndpoint().compareTo(range.upperEndpoint())
< 0);
- // With time_zone = "+00:00", partition boundaries should be
UTC timestamps
List<LiteralExpr> lowerKeys = range.lowerEndpoint().getKeys();
Assert.assertEquals(1, lowerKeys.size());
String lowerStr = lowerKeys.get(0).getStringValue();
Assert.assertTrue("Lower key must have +00:00 suffix: " +
lowerStr,
lowerStr.contains("+00:00"));
+
+ List<LiteralExpr> upperKeys = range.upperEndpoint().getKeys();
+ Assert.assertEquals(1, upperKeys.size());
+ String upperStr = upperKeys.get(0).getStringValue();
+ Assert.assertTrue("Upper key must have +00:00 suffix: " +
upperStr,
+ upperStr.contains("+00:00"));
+
+ // Partition boundaries must be at whole UTC hours
(minute=second=00).
+ // A configured timezone with a fractional offset
(Asia/Kathmandu,
+ // UTC+05:45) would produce boundaries with non-zero minutes
if the
+ // old configured-timezone flooring were used instead of
UTC-first.
+ String lowerMinutes = lowerStr.substring(14, 16);
+ String lowerSeconds = lowerStr.substring(17, 19);
+ Assert.assertEquals("Lower bound minutes must be 00: " +
lowerStr,
+ "00", lowerMinutes);
+ Assert.assertEquals("Lower bound seconds must be 00: " +
lowerStr,
+ "00", lowerSeconds);
+ String upperMinutes = upperStr.substring(14, 16);
+ String upperSeconds = upperStr.substring(17, 19);
+ Assert.assertEquals("Upper bound minutes must be 00: " +
upperStr,
+ "00", upperMinutes);
+ Assert.assertEquals("Upper bound seconds must be 00: " +
upperStr,
+ "00", upperSeconds);
+
+ // Verify adjacency using full timestamps (handles midnight
crossing)
+ if (prevLower != null) {
+ ZonedDateTime expectedNext = prevLower.plusHours(1);
+ ZonedDateTime actual = ZonedDateTime.parse(lowerStr,
+ DateTimeFormatter.ofPattern("yyyy-MM-dd
HH:mm:ssXXX"));
+ Assert.assertEquals("Adjacent partitions' lower bounds
must differ by 1 hour",
+ expectedNext, actual);
+ ZonedDateTime expectedUpper = prevUpper.plusHours(1);
+ ZonedDateTime actualUpper = ZonedDateTime.parse(upperStr,
+ DateTimeFormatter.ofPattern("yyyy-MM-dd
HH:mm:ssXXX"));
+ Assert.assertEquals("Adjacent partitions' upper bounds
must differ by 1 hour",
+ expectedUpper, actualUpper);
+ }
+ prevLower = ZonedDateTime.parse(lowerStr,
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssXXX"));
+ prevUpper = ZonedDateTime.parse(upperStr,
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssXXX"));
+ }
+
+ // Identify the current partition (idx=0) by its stored range.
+ // start=-3,end=3 → idx=0 is at index 3.
+ RangePartitionItem currentItem = (RangePartitionItem)
sortedEntries.get(3).getValue();
+ String currentLowerStr =
currentItem.getItems().lowerEndpoint().getKeys().get(0)
+ .getStringValue();
+ ZonedDateTime currentLower = ZonedDateTime.parse(currentLowerStr,
+ DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ssXXX"));
+ String expectedCurrentName = "p"
+ +
DateTimeFormatter.ofPattern("yyyyMMddHH").format(currentLower);
+ String actualCurrentName =
table.getPartition(sortedEntries.get(3).getKey()).getName();
+ Assert.assertEquals("Current partition (idx=0) hour name must
match its UTC lower bound",
+ expectedCurrentName, actualCurrentName);
+ // With a fractional-offset timezone, only the UTC-first approach
+ // guarantees minute=second=00 on every bound.
+ Assert.assertEquals("Current partition lower bound must end
:00:00: " + currentLowerStr,
+ "00", currentLowerStr.substring(14, 16)); // minutes
+ Assert.assertEquals("Current partition lower bound must end
:00:00: " + currentLowerStr,
+ "00", currentLowerStr.substring(17, 19)); // seconds
+ } finally {
+ connectContext.getSessionVariable().setTimeZone(originalTimeZone);
+ }
+ }
+
+ @Test
+ public void testTimeStampTzDynamicPartitionDropCutoffAligned() throws
Exception {
+ // With time_zone = "Asia/Shanghai", the old drop-path code computed
+ // the reserved range lower bound at the configured timezone's midnight
+ // (16:00 UTC) instead of UTC midnight (00:00). This caused partitions
+ // just before UTC midnight to intersect the shifted reserved range and
+ // not be dropped. Verify the drop cutoff now aligns with the add path.
+ String originalTimeZone =
connectContext.getSessionVariable().getTimeZone();
+ try {
+ connectContext.getSessionVariable().setTimeZone("America/Chicago");
+
+ String createOlapTblStmt = "CREATE TABLE test.`tstz_drop_cutoff`
(\n"
+ + " `k1` TIMESTAMPTZ NULL COMMENT \"\",\n"
+ + " `k2` int NULL COMMENT \"\"\n"
+ + ") ENGINE=OLAP\n"
+ + "DUPLICATE KEY(`k1`, `k2`)\n"
+ + "PARTITION BY RANGE(`k1`)\n"
+ + "()\n"
+ + "DISTRIBUTED BY HASH(`k2`) BUCKETS 3\n"
+ + "PROPERTIES (\n"
+ + "\"replication_num\" = \"1\",\n"
+ + "\"dynamic_partition.enable\" = \"true\",\n"
+ + "\"dynamic_partition.start\" = \"-1\",\n"
+ + "\"dynamic_partition.end\" = \"1\",\n"
+ + "\"dynamic_partition.create_history_partition\" =
\"false\",\n"
+ + "\"dynamic_partition.time_unit\" = \"day\",\n"
+ + "\"dynamic_partition.prefix\" = \"p\",\n"
+ + "\"dynamic_partition.buckets\" = \"1\",\n"
+ + "\"dynamic_partition.time_zone\" = \"Asia/Shanghai\"\n"
+ + ");";
+ createTable(createOlapTblStmt);
+
+ Database db =
Env.getCurrentInternalCatalog().getDbOrAnalysisException("test");
+ OlapTable table = (OlapTable)
db.getTableOrAnalysisException("tstz_drop_cutoff");
+
+ // Inject a fixed clock so the test is deterministic regardless of
+ // wall-clock time. Choose 2026-07-21 08:00:00Z when Asia/Shanghai
+ // is at 16:00 (same calendar day as UTC). At this instant:
+ //
+ // UTC now = 2026-07-21 08:00Z
+ // start=-1 reserved lower (new, UTC) = 2026-07-20 00:00Z
+ // start=-1 reserved lower (old, +08:00) = 2026-07-19 16:00Z
+ //
+ // p_old = [2026-07-19 00:00Z, 2026-07-20 00:00Z)
+ //
+ // New code: reserved [2026-07-20 00:00Z, ∞) → no intersect →
DROP
+ // Old code: reserved [2026-07-19 16:00Z, ∞) → intersect → KEEP
+ //
+ // The assertion below therefore always fails on the old
+ // implementation, not just for 16 hours of the day.
+ ZonedDateTime fixedNow = ZonedDateTime.of(
+ 2026, 7, 21, 8, 0, 0, 0, ZoneOffset.UTC);
+ DynamicPartitionScheduler.testNow = fixedNow;
Review Comment:
[P1] Install the fixed clock before creating the table
`createTable()` reaches `InternalCatalog.createOlapTable()`, which invokes
`executeDynamicPartitionFirstTime()` before this assignment. Thus the table is
already seeded from the real clock. On 2026-07-22, CREATE adds the 07-22 and
07-23 ranges; the fixed 2026-07-21 pass then adds 07-21 but keeps both future
ranges, so the final `size() == 2` assertion sees three partitions. Set
`testNow` before `createTable(...)` so both scheduling passes use the fixture
instant.
--
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.
To unsubscribe, e-mail: [email protected]
For queries about this service, please contact Infrastructure at:
[email protected]
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]