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


##########
be/src/format_v2/orc/orc_reader.cpp:
##########
@@ -882,6 +886,150 @@ struct OrcReaderScanState {
     bool row_reader_created = false;
 };
 
+// Dictionary rejection is independent of SARG min/max pruning: an absent 
value can lie
+// between both bounds. Keep residual predicates intact; this callback only 
rejects stripes.
+class OrcReader::StringDictFilterImpl final : public ::orc::StringDictFilter {
+public:
+    explicit StringDictFilterImpl(OrcReader* reader) : _reader(reader) {
+        const auto& request = *_reader->_request;
+        // Phase-two fetches must materialize every requested physical row.
+        if (request.row_ids.has_value()) {
+            return;
+        }
+        const auto safe_count =
+                std::min(request.metadata_pruning_safe_conjunct_count, 
request.conjuncts.size());
+        for (size_t i = 0; i < safe_count; ++i) {
+            _add_predicate(request.conjuncts[i]);
+        }
+    }
+
+    bool empty() const { return _columns.empty(); }
+
+    void fillDictFilterColumnNames(std::unique_ptr<::orc::StripeInformation>,
+                                   std::list<std::string>& names) const 
override {
+        for (const auto& [name, column] : _columns) {
+            names.push_back(name);
+        }
+    }
+
+    void onStringDictsLoaded(
+            std::unordered_map<std::string, ::orc::StringDictionary*>& 
dictionaries,
+            bool* stripe_filtered) const override {
+        
SCOPED_RAW_TIMER(&_reader->_reader_statistics.dict_filter_rewrite_time);
+        *stripe_filtered = false;
+        for (const auto& [name, column] : _columns) {
+            const auto it = dictionaries.find(name);
+            // A later stripe may use direct encoding for a column that 
previously had a dictionary.
+            if (it == dictionaries.end()) {
+                continue;
+            }
+            bool has_match = false;
+            THROW_IF_ERROR(_has_match(column, *it->second, &has_match));
+            if (!has_match) {
+                *stripe_filtered = true;
+                if (_reader->_profile != nullptr) {
+                    
COUNTER_UPDATE(_reader->_orc_profile.dictionary_stripes_filtered, 1);
+                }
+                return;
+            }
+        }
+    }
+
+private:
+    struct DictionaryColumn {
+        size_t position = 0;
+        DataTypePtr type;
+        VExprContextSPtrs conjuncts;
+    };
+
+    void _add_predicate(const VExprContextSPtr& conjunct) {
+        const auto& root = conjunct->root();
+        const auto& children = root->children();
+        // Only direct slot/literal comparisons and IN lists are stable 
dictionary predicates.
+        // Casts, multi-column expressions and mutable runtime filters retain 
row-level evaluation.
+        if ((root->node_type() != TExprNodeType::BINARY_PRED &&
+             root->node_type() != TExprNodeType::IN_PRED) ||
+            root->is_rf_wrapper() || children.size() < 2 || 
!children[0]->is_slot_ref() ||
+            !std::ranges::all_of(children.begin() + 1, children.end(),
+                                 [](const auto& child) { return 
child->is_literal(); })) {
+            return;
+        }
+        const auto* slot = assert_cast<const VSlotRef*>(children[0].get());
+        const auto& request = *_reader->_request;
+        const auto column = std::ranges::find_if(request.local_positions, 
[&](const auto& entry) {
+            return static_cast<int64_t>(entry.second.value()) == 
slot->column_id();
+        });
+        if (column == request.local_positions.end() || 
is_virtual_column(column->first)) {
+            return;
+        }
+        const auto id = column->first.value();
+        const auto& type = *_reader->_state->root_type->getSubtype(id);
+        // CHAR padding and binary logical annotations need their own 
physical-to-value rules.
+        if (type.getKind() != ::orc::STRING && type.getKind() != 
::orc::VARCHAR) {
+            return;
+        }
+        auto& target = _columns[_reader->_state->root_type->getFieldName(id)];

Review Comment:
   [P2] Reject ambiguous SDK dictionary names before pruning stripes
   
   For a valid ORC schema with root fields `a.b:STRING` followed by 
`a:STRUCT<b:STRING>`, this raw name is ambiguous: the [pinned SDK's dot-path 
map](https://github.com/apache/doris-thirdparty/blob/5860f94768b94406f31698ac66f4cc3d2a781324/c%2B%2B/src/Reader.cc#L488-L518)
 overwrites root `a.b` with nested `a.b`. Project both roots, give the root 
dictionary `{'hit'}` and the nested dictionary `{'miss'}`, and disable min/max 
and lazy filtering. Then ``SELECT `a.b`, a FROM t WHERE `a.b` = 'hit'`` 
resolves this callback's dictionary request to nested `b`, evaluates the root 
predicate against `miss`/NULL, and drops the matching stripe. Numeric root 
projection read this correctly before the callback was added. Verify that SDK 
name lookup resolves to the intended physical type ID, or skip ambiguous names, 
and cover this collision.



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