diff --git a/be/src/storage/iterator/vgeneric_iterators.cpp b/be/src/storage/iterator/vgeneric_iterators.cpp index b854776c6f8ed9..13821473b11803 100644 --- a/be/src/storage/iterator/vgeneric_iterators.cpp +++ b/be/src/storage/iterator/vgeneric_iterators.cpp @@ -80,8 +80,8 @@ Status VStatisticsIterator::next_batch(Block* block) { _schema.column(cid)->type() == FieldType::OLAP_FIELD_TYPE_CHAR) { auto col = columns[i]->clone_empty(); for (size_t j = 0; j < columns[i]->size(); ++j) { - const auto& ref = columns[i]->get_data_at(j).trim_tail_padding_zero(); - col->insert(Field::create_field(ref.to_string())); + const auto ref = columns[i]->get_data_at(j).trim_tail_padding_zero(); + col->insert_data(ref.data, ref.size); } columns[i].swap(col); } diff --git a/be/test/exec/scan/vgeneric_iterators_test.cpp b/be/test/exec/scan/vgeneric_iterators_test.cpp index f8e3e09401a96d..1f52d396103782 100644 --- a/be/test/exec/scan/vgeneric_iterators_test.cpp +++ b/be/test/exec/scan/vgeneric_iterators_test.cpp @@ -23,15 +23,23 @@ #include #include +#include "core/assert_cast.h" #include "core/block/column_with_type_and_name.h" #include "core/column/column.h" +#include "core/column/column_nullable.h" #include "core/data_type/data_type.h" #include "core/field.h" #include "gtest/gtest_pred_impl.h" +#include "io/fs/file_writer.h" +#include "io/fs/local_file_system.h" #include "storage/olap_common.h" +#include "storage/row_cursor.h" #include "storage/schema.h" #include "storage/segment/column_reader.h" +#include "storage/segment/segment.h" +#include "storage/segment/test_segment_writer.h" #include "storage/tablet/tablet_schema.h" +#include "storage/tablet/tablet_schema_helper.h" namespace doris { using namespace ErrorCode; @@ -107,6 +115,77 @@ TEST(VGenericIteratorsTest, AutoIncrement) { } } +TEST(VGenericIteratorsTest, StatisticsIteratorPreservesNullForNullableChar) { + constexpr auto test_dir = "./ut_dir/vgeneric_iterators_test"; + constexpr auto segment_path = "./ut_dir/vgeneric_iterators_test/nullable_char_segment.dat"; + constexpr auto row_count = 3; + + auto fs = io::global_local_filesystem(); + ASSERT_TRUE(fs->delete_directory(test_dir).ok()); + ASSERT_TRUE(fs->create_directory(test_dir).ok()); + + auto tablet_schema = std::make_shared(); + tablet_schema->append_column(*create_int_key(0, false)); + auto nullable_char = std::make_shared(); + nullable_char->set_unique_id(1); + nullable_char->set_name("1"); + nullable_char->set_type(FieldType::OLAP_FIELD_TYPE_CHAR); + nullable_char->set_is_nullable(true); + nullable_char->set_length(8); + nullable_char->set_index_length(8); + nullable_char->set_aggregation_method(FieldAggregationMethod::OLAP_FIELD_AGGREGATION_NONE); + tablet_schema->append_column(*nullable_char); + tablet_schema->set_storage_page_size(4096); + + io::FileWriterPtr file_writer; + ASSERT_TRUE(fs->create_file(segment_path, &file_writer).ok()); + SegmentWriterOptions writer_options; + writer_options.num_rows_per_block = 1024; + TestSegmentWriter writer(file_writer.get(), 0, tablet_schema, nullptr, nullptr, writer_options, + nullptr); + ASSERT_TRUE(writer.init().ok()); + + RowCursor row; + std::vector fields(tablet_schema->num_columns(), Field(PrimitiveType::TYPE_NULL)); + ASSERT_TRUE(row.init_scan_key(tablet_schema, std::move(fields)).ok()); + for (int i = 0; i < row_count; ++i) { + row.mutable_field(0) = Field::create_field(i); + ASSERT_TRUE(writer.append_row(row).ok()); + } + uint64_t file_size = 0; + uint64_t index_size = 0; + ASSERT_TRUE(writer.finalize(&file_size, &index_size).ok()); + ASSERT_TRUE(file_writer->close().ok()); + + std::shared_ptr segment; + ASSERT_TRUE(segment_v2::Segment::open(fs, segment_path, 100, 0, RowsetId {.version = 1}, + tablet_schema, io::FileReaderOptions {}, &segment) + .ok()); + + std::vector column_ids {0, 1}; + Schema schema(tablet_schema->columns(), column_ids); + VStatisticsIterator iterator(segment, schema); + StorageReadOptions read_options; + OlapReaderStatistics stats; + read_options.push_down_agg_type_opt = TPushAggOp::MINMAX; + read_options.stats = &stats; + read_options.tablet_schema = tablet_schema; + ASSERT_TRUE(iterator.init(read_options).ok()); + + Block block; + create_block(schema, block); + ASSERT_TRUE(iterator.next_batch(&block).ok()); + ASSERT_EQ(2, block.rows()); + + const auto& nullable_column = + assert_cast(*block.get_by_position(1).column); + EXPECT_TRUE(nullable_column.is_null_at(0)); + EXPECT_TRUE(nullable_column.is_null_at(1)); + ASSERT_TRUE(iterator.next_batch(&block).is()); + + ASSERT_TRUE(fs->delete_directory(test_dir).ok()); +} + TEST(VGenericIteratorsTest, Union) { auto schema = create_schema(); auto output_schema = std::make_shared(schema);