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


##########
be/src/format_v2/parquet/reader/native/column_chunk_reader.cpp:
##########
@@ -804,6 +825,85 @@ class FixedWidthPredicateConsumer final : public 
ParquetFixedValueConsumer {
     int _column_id;
     IColumn::Filter* _matches;
     IColumn* _projected_column;
+    IColumn::Filter* _conversion_nulls;
+};
+
+class BinaryPredicateConsumer final : public ParquetFixedValueConsumer,
+                                      public ParquetBinaryValueConsumer {
+public:
+    BinaryPredicateConsumer(const VExprSPtrs& conjuncts, DataTypePtr 
data_type, int column_id,
+                            IColumn::Filter* matches, IColumn* 
projected_column,
+                            std::vector<StringRef>* refs, 
std::vector<StringRef>* projected_refs)
+            : _conjuncts(conjuncts),
+              _data_type(std::move(data_type)),
+              _column_id(column_id),
+              _matches(matches),
+              _projected_column(projected_column),
+              _refs(refs),
+              _projected_refs(projected_refs) {
+        DORIS_CHECK(_matches != nullptr);
+        DORIS_CHECK(_refs != nullptr);
+        DORIS_CHECK(_projected_refs != nullptr);
+    }
+
+    Status consume(const uint8_t* values, size_t num_values, size_t 
value_width) override {
+        _refs->resize(num_values);
+        for (size_t row = 0; row < num_values; ++row) {
+            (*_refs)[row] = StringRef(reinterpret_cast<const char*>(values + 
row * value_width),
+                                      value_width);
+        }
+        return consume(_refs->data(), _refs->size());
+    }
+
+    Status consume_plain_byte_array(
+            const char* encoded_data, const uint32_t* payload_offsets,
+            const uint32_t* value_offsets, size_t num_values,
+            const std::vector<ParquetSelectionRange>& value_spans) override {
+        _refs->resize(num_values);
+        size_t covered = 0;
+        for (const auto& span : value_spans) {
+            DORIS_CHECK_EQ(span.first, covered);
+            for (size_t row = span.first; row < span.first + span.count; 
++row) {
+                (*_refs)[row] = StringRef(encoded_data + payload_offsets[row],
+                                          value_offsets[row + 1] - 
value_offsets[row]);
+            }
+            covered += span.count;
+        }
+        DORIS_CHECK_EQ(covered, num_values);
+        return consume(_refs->data(), _refs->size());
+    }
+
+    Status consume(const StringRef* values, size_t num_values) override {
+        const size_t old_size = _matches->size();
+        _matches->resize_fill(old_size + num_values, 1);
+        for (const auto& conjunct : _conjuncts) {
+            RETURN_IF_ERROR(conjunct->execute_on_raw_binary_values(
+                    values, num_values, _data_type, _column_id, 
_matches->data() + old_size));
+        }
+        if (_projected_column != nullptr) {
+            _projected_refs->clear();
+            _projected_refs->reserve(num_values);
+            for (size_t row = 0; row < num_values; ++row) {
+                if ((*_matches)[old_size + row] != 0) {
+                    _projected_refs->push_back(values[row]);
+                }
+            }
+            if (!_projected_refs->empty()) {
+                _projected_column->insert_many_strings(_projected_refs->data(),

Review Comment:
   [P1] Preserve non-NULL empty strings in direct projection
   
   `DELTA_BYTE_ARRAY` selected decode represents an empty but physically 
present value as `StringRef(nullptr, 0)`. Passing that survivor to a nullable 
output column here makes `ColumnNullable::insert_many_strings()` set the 
null-map bit, so a projected `''` becomes SQL NULL. This path is reachable 
because raw-binary filtering admits `DELTA_BYTE_ARRAY` and projected predicate 
columns pass the nullable file-block column. Please insert into the nested 
string column while appending zero null bits (or otherwise normalize the empty 
ref), and add projected empty-value coverage.



##########
be/src/exprs/vtopn_pred.h:
##########
@@ -121,14 +121,64 @@ class VTopNPred : public VExpr {
         RETURN_IF_ERROR(_function->execute(nullptr, temp_block, arguments,
                                            num_columns_without_result, 
temp_block.rows()));
         result_column = 
std::move(temp_block.get_by_position(num_columns_without_result).column);
-        if (is_nullable() && _predicate->nulls_first()) {
-            // null values ​​are always not filtered
-            result_column = change_null_to_true(std::move(result_column));
+        if (auto mutable_result = IColumn::mutate(std::move(result_column));

Review Comment:
   [P1] Collapse NULL inside constant TopN results
   
   When partition-only TopN runs on an external partition value, both operands 
are constants, so the comparison result is 
`ColumnConst(ColumnNullable(UInt8))`. This branch only recognizes an outer 
`ColumnNullable`; the NULL result survives, and `execute_filter(..., 
accept_null=false)` treats it as false, allowing a NULL partition to be pruned 
even with `NULLS FIRST`. The removed `change_null_to_true()` helper recursed 
through `ColumnConst`. Please unwrap/materialize the constant (or recurse and 
rewrap it with the original row count) and cover this case.



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