diff --git a/cpp/src/arrow/table.cc b/cpp/src/arrow/table.cc index 7a7168e93128..a8acdfd0914a 100644 --- a/cpp/src/arrow/table.cc +++ b/cpp/src/arrow/table.cc @@ -101,7 +101,7 @@ class SimpleTable : public Table { std::shared_ptr Slice(int64_t offset, int64_t length) const override { auto sliced = columns_; - int64_t num_rows = length; + int64_t num_rows = std::max(0, std::min(length, this->num_rows() - offset)); for (auto& column : sliced) { column = column->Slice(offset, length); num_rows = column->length(); diff --git a/cpp/src/arrow/table_test.cc b/cpp/src/arrow/table_test.cc index 6d60b6bda58f..d2023723142e 100644 --- a/cpp/src/arrow/table_test.cc +++ b/cpp/src/arrow/table_test.cc @@ -1319,6 +1319,24 @@ TEST_F(TestTable, Slice) { *three->Slice(length + length / 3, 2 * (length - length / 3))); } +TEST_F(TestTable, SliceZeroColumns) { + const int64_t length = 10; + auto empty_columns_table = Table::Make( + ::arrow::schema({}), std::vector>{}, length); + ASSERT_EQ(empty_columns_table->num_rows(), length); + ASSERT_EQ(empty_columns_table->Slice(3)->num_rows(), length - 3); + ASSERT_EQ(empty_columns_table->Slice(0)->num_rows(), length); + ASSERT_EQ(empty_columns_table->Slice(3, 100)->num_rows(), length - 3); + ASSERT_EQ(empty_columns_table->Slice(3, 4)->num_rows(), 4); + ASSERT_EQ(empty_columns_table->Slice(length + 5)->num_rows(), 0); + + MakeExample1(length); + auto table = Table::Make(schema_, columns_); + ASSERT_OK_AND_ASSIGN(auto no_columns, table->SelectColumns({})); + ASSERT_EQ(no_columns->Slice(1)->num_rows(), table->Slice(1)->num_rows()); + ASSERT_EQ(no_columns->Slice(1, 4)->num_rows(), 4); +} + TEST_F(TestTable, RemoveColumn) { const int64_t length = 10; MakeExample1(length); diff --git a/python/pyarrow/tests/test_table.py b/python/pyarrow/tests/test_table.py index cb010f4387b6..d26629fd8ef9 100644 --- a/python/pyarrow/tests/test_table.py +++ b/python/pyarrow/tests/test_table.py @@ -1361,6 +1361,22 @@ def test_table_slice_getitem(): return _table_like_slice_tests(pa.table) +def test_table_slice_no_columns(): + table = pa.table({'col': range(3)}) + empty = table.select([]) + assert empty.num_rows == 3 + + # slice(offset) clamps to the remaining rows + assert empty.slice(1).num_rows == 2 + assert empty.slice(0).num_rows == 3 + # slice(offset, length) must not exceed the remaining rows + assert empty.slice(1, 4).num_rows == 2 + # consistent with __getitem__ slicing, which already worked + assert empty[1:].num_rows == 2 + # offset past the end yields an empty table + assert empty.slice(5).num_rows == 0 + + @pytest.mark.pandas def test_slice_zero_length_table(): # ARROW-7907: a segfault on this code was fixed after 0.16.0