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