diff --git a/cpp/src/arrow/array/array_test.cc b/cpp/src/arrow/array/array_test.cc index f96b1c18bb6e..3fa4f16e85b6 100644 --- a/cpp/src/arrow/array/array_test.cc +++ b/cpp/src/arrow/array/array_test.cc @@ -3909,6 +3909,7 @@ class TestArrayDataStatistics : public ::testing::Test { public: void SetUp() { valids_ = {1, 0, 1, 1}; + row_count_ = static_cast(valids_.size()); null_count_ = std::count(valids_.begin(), valids_.end(), 0); distinct_count_ = 3.0; max_byte_width_ = 4.0; @@ -3921,6 +3922,7 @@ class TestArrayDataStatistics : public ::testing::Test { data_ = ArrayData::Make(int32(), values_.size(), {null_buffer_, values_buffer_}, null_count_); data_->statistics = std::make_shared(); + data_->statistics->row_count = row_count_; data_->statistics->null_count = null_count_; data_->statistics->distinct_count = distinct_count_; data_->statistics->max_byte_width = max_byte_width_; @@ -3934,6 +3936,7 @@ class TestArrayDataStatistics : public ::testing::Test { protected: std::vector valids_; + int64_t row_count_; int64_t null_count_; double distinct_count_; double max_byte_width_; @@ -3950,6 +3953,9 @@ TEST_F(TestArrayDataStatistics, MoveConstructor) { ArrayData copied_data(*data_); ArrayData moved_data(std::move(copied_data)); + ASSERT_TRUE(moved_data.statistics->row_count.has_value()); + ASSERT_EQ(row_count_, std::get(moved_data.statistics->row_count.value())); + ASSERT_TRUE(moved_data.statistics->null_count.has_value()); ASSERT_EQ(null_count_, std::get(moved_data.statistics->null_count.value())); @@ -3980,6 +3986,9 @@ TEST_F(TestArrayDataStatistics, MoveConstructor) { TEST_F(TestArrayDataStatistics, CopyConstructor) { ArrayData copied_data(*data_); + ASSERT_TRUE(copied_data.statistics->row_count.has_value()); + ASSERT_EQ(row_count_, std::get(copied_data.statistics->row_count.value())); + ASSERT_TRUE(copied_data.statistics->null_count.has_value()); ASSERT_EQ(null_count_, std::get(copied_data.statistics->null_count.value())); @@ -4012,6 +4021,9 @@ TEST_F(TestArrayDataStatistics, MoveAssignment) { ArrayData moved_data; moved_data = std::move(copied_data); + ASSERT_TRUE(moved_data.statistics->row_count.has_value()); + ASSERT_EQ(row_count_, std::get(moved_data.statistics->row_count.value())); + ASSERT_TRUE(moved_data.statistics->null_count.has_value()); ASSERT_EQ(null_count_, std::get(moved_data.statistics->null_count.value())); @@ -4043,6 +4055,9 @@ TEST_F(TestArrayDataStatistics, CopyAssignment) { ArrayData copied_data; copied_data = *data_; + ASSERT_TRUE(copied_data.statistics->row_count.has_value()); + ASSERT_EQ(row_count_, std::get(copied_data.statistics->row_count.value())); + ASSERT_TRUE(copied_data.statistics->null_count.has_value()); ASSERT_EQ(null_count_, std::get(copied_data.statistics->null_count.value())); @@ -4074,6 +4089,9 @@ TEST_F(TestArrayDataStatistics, CopyTo) { ASSERT_OK_AND_ASSIGN(auto copied_data, data_->CopyTo(arrow::default_cpu_memory_manager())); + ASSERT_TRUE(copied_data->statistics->row_count.has_value()); + ASSERT_EQ(row_count_, std::get(copied_data->statistics->row_count.value())); + ASSERT_TRUE(copied_data->statistics->null_count.has_value()); ASSERT_EQ(null_count_, std::get(copied_data->statistics->null_count.value())); diff --git a/cpp/src/arrow/array/statistics.h b/cpp/src/arrow/array/statistics.h index 7ed0b8a009ef..ae78dca0b0c6 100644 --- a/cpp/src/arrow/array/statistics.h +++ b/cpp/src/arrow/array/statistics.h @@ -75,6 +75,12 @@ struct ARROW_EXPORT ArrayStatistics { return std::visit(visitor, value.value()); } + /// \brief The number of rows, may not be set + /// Note: when set to `int64_t`, it represents `exact_row_count`, + /// and when set to `double`, it represents `approximate_row_count`. + /// Note: this value is not used by \ref arrow::RecordBatch::MakeStatisticsArray. + std::optional row_count = std::nullopt; + /// \brief The number of null values, may not be set /// Note: when set to `int64_t`, it represents `exact_null_count`, /// and when set to `double`, it represents `approximate_null_count`. diff --git a/cpp/src/arrow/array/statistics_test.cc b/cpp/src/arrow/array/statistics_test.cc index fba3545dabe1..62e1ddf831de 100644 --- a/cpp/src/arrow/array/statistics_test.cc +++ b/cpp/src/arrow/array/statistics_test.cc @@ -25,6 +25,22 @@ namespace arrow { +TEST(TestArrayStatistics, RowCountExact) { + ArrayStatistics statistics; + ASSERT_FALSE(statistics.row_count.has_value()); + statistics.row_count = 45; + ASSERT_TRUE(statistics.row_count.has_value()); + ASSERT_EQ(45, std::get(statistics.row_count.value())); +} + +TEST(TestArrayStatistics, RowCountApproximate) { + ArrayStatistics statistics; + ASSERT_FALSE(statistics.row_count.has_value()); + statistics.row_count = 45.0; + ASSERT_TRUE(statistics.row_count.has_value()); + ASSERT_DOUBLE_EQ(45.0, std::get(statistics.row_count.value())); +} + TEST(TestArrayStatistics, NullCountExact) { ArrayStatistics statistics; ASSERT_FALSE(statistics.null_count.has_value()); @@ -114,6 +130,18 @@ TEST(TestArrayStatistics, Equals) { ASSERT_EQ(statistics1, statistics2); + // Test ROW_COUNT_EXACT + statistics1.row_count = 45; + ASSERT_NE(statistics1, statistics2); + statistics2.row_count = 45; + ASSERT_EQ(statistics1, statistics2); + + // Test ROW_COUNT_APPROXIMATE + statistics1.row_count = 45.0; + ASSERT_NE(statistics1, statistics2); + statistics2.row_count = 45.0; + ASSERT_EQ(statistics1, statistics2); + // Test NULL_COUNT_EXACT statistics1.null_count = 29; ASSERT_NE(statistics1, statistics2); diff --git a/cpp/src/arrow/compare.cc b/cpp/src/arrow/compare.cc index e7d4f400fb6f..b515fdd165db 100644 --- a/cpp/src/arrow/compare.cc +++ b/cpp/src/arrow/compare.cc @@ -1563,7 +1563,9 @@ bool ArrayStatisticsOptionalValueEquals(const std::optional& left, bool ArrayStatisticsEqualsImpl(const ArrayStatistics& left, const ArrayStatistics& right, const EqualOptions& equal_options) { - return ArrayStatisticsOptionalValueEquals(left.null_count, right.null_count, + return ArrayStatisticsOptionalValueEquals(left.row_count, right.row_count, + equal_options) && + ArrayStatisticsOptionalValueEquals(left.null_count, right.null_count, equal_options) && ArrayStatisticsOptionalValueEquals(left.distinct_count, right.distinct_count, equal_options) &&