github-actions[bot] commented on code in PR #69163:
URL: https://github.com/apache/doris/pull/69163#discussion_r4292145653


##########
be/src/format_v2/orc/orc_reader.cpp:
##########
@@ -1866,24 +2001,104 @@ Status 
OrcReader::_select_stripe_ranges_by_statistics() {
     return Status::OK();
 }
 
-void OrcReader::_apply_current_stripe_range() {
-    if (!_state->stripe_pruning_applied || 
_state->selected_stripe_ranges.empty()) {
-        return;
+Status OrcReader::_prepare_timestamp_stripe_ranges() {
+    if (!_state->timestamp_plan.requires_stripe_reader()) {
+        return Status::OK();
+    }
+    std::vector<uint64_t> stripes;
+    std::set<uint64_t> unsafe_date_stripes;
+    if (_state->stripe_ranges_applied) {
+        for (const auto& range : _state->selected_stripe_ranges) {
+            for (auto stripe = range.first_stripe; stripe < range.last_stripe; 
++stripe) {
+                stripes.push_back(stripe);
+                if (range.disable_sarg) {
+                    unsafe_date_stripes.insert(stripe);
+                }
+            }
+        }
+    } else {
+        RETURN_IF_ERROR(_collect_split_stripes(&stripes));
+    }
+    _state->selected_stripe_ranges.clear();
+    _state->stripe_ranges_applied = true;
+    _reader_statistics.read_row_groups = cast_set<int32_t>(stripes.size());
+    if (stripes.empty()) {
+        return Status::OK();
+    }
+    try {
+        uint64_t first_row = 0;
+        size_t selected = 0;
+        std::string previous_timezone;
+        for (uint64_t index = 0; index <= stripes.back(); ++index) {
+            const auto stripe = _state->reader->getStripe(index);
+            const auto end_row = first_row + stripe->getNumberOfRows();
+            if (index == stripes[selected]) {
+                const auto& name = stripe->getWriterTimezone();

Review Comment:
   [P2] Avoid eagerly reading every stripe footer
   
   In the pinned SDK, `getWriterTimezone()` loads and parses the stripe footer, 
and each `getStripe()` creates a fresh object whose parsed footer is discarded 
here. A large cold S3/HDFS scan with a NANOS sibling and any projected plain 
timestamp therefore performs a synchronous footer read for every selected 
stripe before its first row, even for `LIMIT 1` or row IDs confined to one 
stripe. Physical splitting also opens the parent reader first. Discover 
timezone runs incrementally or retain reusable footer metadata so unvisited 
stripes do not determine startup cost.



##########
be/src/format_v2/orc/orc_reader.cpp:
##########
@@ -1152,7 +1255,12 @@ DataTypePtr OrcReader::_convert_to_doris_type(const 
::orc::Type& type) const {
         data_type = std::make_shared<DataTypeDateV2>();
         break;
     case ::orc::TypeKind::TIMESTAMP:
-        data_type = std::make_shared<DataTypeDateTimeV2>(6);
+        if (type.hasAttributeKey("iceberg.timestamp-unit") &&
+            type.getAttributeValue("iceberg.timestamp-unit") == "NANOS") {
+            data_type = std::make_shared<DataTypeTimeStampNs>();

Review Comment:
   [P2] Preserve nanos range validation in metadata COUNT
   
   For an Iceberg v3 table with an optional `timestamp_ns` column backed by an 
externally supplied annotated ORC file, a non-null civil value such as 
`1500-01-01` is rejected by the new nanos SerDe. However, `SELECT COUNT(ts)` 
with V2 aggregate pushdown uses a trivial same-type mapping and reaches 
`get_aggregate_result`, which validates only DATE leaves before returning 
`getNumberOfValues()`. It therefore succeeds where scanning the argument 
reports `DataQualityError`. Extend the existing COUNT validation/fallback to 
NANOS timestamp leaves, including nested arguments, while keeping `COUNT(*)` 
metadata-only.



##########
fe/fe-core/src/main/java/org/apache/doris/datasource/iceberg/source/IcebergScanNode.java:
##########
@@ -2407,11 +2409,12 @@ protected List<FileScanTask> 
loadFileScanTasksWithManifestCache(
         }
         ExternalTable targetExternalTable = (ExternalTable) 
source.getTargetTable();
         Schema scanSchema = scan.schema();
+        Set<Integer> unsafeNanosFields = 
IcebergTimestampUtils.unsafeNanosFields(icebergTable, scanSchema);

Review Comment:
   [P1] Preserve equality deletes after DATE-to-nanos promotion
   
   With `meta.cache.iceberg.manifest.enable=true`, the new unsafe-field set 
only disables query pruning. In an unpartitioned v3 table, let an old required 
`DATE ts` file contain `2024-01-02` (four-byte bounds `19724`), then promote 
`ts` to `timestamp_ns` and add a later equality delete for that midnight 
(bounds `1704153600000000000`). This planner's `DeleteFileIndex` uses the 
latest field type: `Conversions.fromByteBuffer` widens the DATE bounds to 
`19724L`, `rangesOverlap` returns false, and the delete is omitted, so `SELECT` 
returns the deleted row even without a `ts` predicate. Apply the retained-DATE 
safeguard to equality-delete applicability too, or decode historical bounds 
into the promoted unit. This promotion and the historical bound representation 
are defined by the [Iceberg 
specification](https://iceberg.apache.org/spec/#schema-evolution).



-- 
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]

Reply via email to