This is an automated email from the ASF dual-hosted git repository.
morningman pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/doris.git
The following commit(s) were added to refs/heads/master by this push:
new ca001776658 [fix](iceberg) Fix execute action validation gaps (#61381)
ca001776658 is described below
commit ca001776658094fed49dc020c1e717f3755a6c44
Author: Socrates <[email protected]>
AuthorDate: Thu Mar 26 06:46:14 2026 +0800
[fix](iceberg) Fix execute action validation gaps (#61381)
### What problem does this PR solve?
Problem Summary:
- Fix `rollback_to_timestamp` so epoch millis input is parsed correctly
instead of falling through to `rollbackToTime(-1)`.
- Reject invalid `rewrite_data_files` input when `min-file-size-bytes >
max-file-size-bytes` during FE validation.
- Add Iceberg regression coverage for the epoch-millis rollback path and
invalid rewrite_data_files file-size bounds.
---
.../action/IcebergRewriteDataFilesAction.java | 3 ++
.../action/IcebergRollbackToTimestampAction.java | 21 +++++++++++++-
.../action/test_iceberg_execute_actions.groovy | 32 +++++++++++++++++++++-
3 files changed, 54 insertions(+), 2 deletions(-)
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRewriteDataFilesAction.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRewriteDataFilesAction.java
index 885f15225b0..eb34eab0217 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRewriteDataFilesAction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRewriteDataFilesAction.java
@@ -161,6 +161,9 @@ public class IcebergRewriteDataFilesAction extends
BaseIcebergAction {
if (this.maxFileSizeBytes == 0) {
this.maxFileSizeBytes = (long) (targetFileSizeBytes * 1.8);
}
+ if (this.minFileSizeBytes > this.maxFileSizeBytes) {
+ throw new UserException("min-file-size-bytes must be less than or
equal to max-file-size-bytes");
+ }
validateNoPartitions();
}
diff --git
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRollbackToTimestampAction.java
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRollbackToTimestampAction.java
index be83f57ed13..f01367a85dc 100644
---
a/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRollbackToTimestampAction.java
+++
b/fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/action/IcebergRollbackToTimestampAction.java
@@ -36,6 +36,7 @@ import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.TimeZone;
/**
* Iceberg rollback to timestamp action implementation.
@@ -103,7 +104,7 @@ public class IcebergRollbackToTimestampAction extends
BaseIcebergAction {
Long previousSnapshotId = previousSnapshot != null ?
previousSnapshot.snapshotId() : null;
try {
- long targetTimestamp = TimeUtils.msTimeStringToLong(timestampStr,
TimeUtils.getTimeZone());
+ long targetTimestamp = parseTimestampMillis(timestampStr,
TimeUtils.getTimeZone());
icebergTable.manageSnapshots().rollbackToTime(targetTimestamp).commit();
Snapshot currentSnapshot = icebergTable.currentSnapshot();
@@ -133,4 +134,22 @@ public class IcebergRollbackToTimestampAction extends
BaseIcebergAction {
public String getDescription() {
return "Rollback Iceberg table to the snapshot that was current at a
specific timestamp";
}
+
+ static long parseTimestampMillis(String timestampStr, TimeZone timeZone) {
+ String trimmed = timestampStr.trim();
+ try {
+ long timestampMs = Long.parseLong(trimmed);
+ if (timestampMs < 0) {
+ throw new IllegalArgumentException("Timestamp must be
non-negative: " + timestampMs);
+ }
+ return timestampMs;
+ } catch (NumberFormatException e) {
+ long parsedTimestamp = TimeUtils.msTimeStringToLong(trimmed,
timeZone);
+ if (parsedTimestamp < 0) {
+ throw new IllegalArgumentException("Invalid timestamp format.
Expected ISO datetime "
+ + "(yyyy-MM-dd HH:mm:ss.SSS) or timestamp in
milliseconds: " + trimmed, e);
+ }
+ return parsedTimestamp;
+ }
+ }
}
diff --git
a/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
b/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
index b235fbbd23b..a4bcd1dd419 100644
---
a/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
+++
b/regression-test/suites/external_table_p0/iceberg/action/test_iceberg_execute_actions.groovy
@@ -264,6 +264,23 @@ suite("test_iceberg_optimize_actions_ddl", "p0,external") {
logger.info("Rollback timestamp result: ${rollbackTimestampResult}")
qt_after_rollback_to_timestamp """SELECT * FROM test_rollback_timestamp
ORDER BY id"""
+ String epochMillisSnapshotTime = String.valueOf(
+ dateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli())
+
+ List<List<Object>> rollbackTimestampEpochResult = sql """
+ ALTER TABLE ${catalog_name}.${db_name}.test_rollback_timestamp
+ EXECUTE rollback_to_timestamp("timestamp" =
"${epochMillisSnapshotTime}")
+ """
+ logger.info("Rollback epoch millis result:
${rollbackTimestampEpochResult}")
+
+ List<List<Object>> rowsAfterEpochRollback = sql """
+ SELECT id, version FROM test_rollback_timestamp ORDER BY id
+ """
+ assertTrue(rowsAfterEpochRollback.size() == 2,
+ "Expected rollback_to_timestamp with epoch millis to keep exactly
2 rows")
+ assertTrue(rowsAfterEpochRollback[0][0] == 1 &&
rowsAfterEpochRollback[1][0] == 2,
+ "Expected rollback_to_timestamp with epoch millis to restore the
first two snapshots")
+
//
=====================================================================================
// Test Case 3: set_current_snapshot action
@@ -484,6 +501,19 @@ suite("test_iceberg_optimize_actions_ddl", "p0,external") {
exception "Invalid target-file-size-bytes format: not-a-number"
}
+ // Test rewrite_data_files with invalid min/max file size relationship
+ test {
+ sql """
+ ALTER TABLE ${catalog_name}.${db_name}.${table_name} EXECUTE
rewrite_data_files
+ (
+ "target-file-size-bytes" = "536870912",
+ "min-file-size-bytes" = "1073741824",
+ "max-file-size-bytes" = "536870912"
+ )
+ """
+ exception "min-file-size-bytes must be less than or equal to
max-file-size-bytes"
+ }
+
// Test set_current_snapshot with both snapshot_id and ref
test {
sql """
@@ -631,4 +661,4 @@ test {
}
-}
\ No newline at end of file
+}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]