Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions cpp/src/arrow/adapters/orc/adapter_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -658,6 +658,37 @@ TEST(TestAdapterReadWrite, ThrowWhenTZDBUnavaiable) {
Raises(StatusCode::Invalid, testing::HasSubstr(expect_str)));
}

// An out-of-range DECIMAL precision/scale from a malformed footer must return an error
// Status, not abort the process via decimal128()'s ARROW_CHECK.
TEST(TestAdapterRead, GetArrowTypeRejectsOutOfRangeDecimal) {
namespace orc_adapter = adapters::orc;

EXPECT_THAT(orc_adapter::GetArrowType(
liborc::createDecimalType(Decimal128Type::kMaxPrecision + 1, 2).get()),
Raises(StatusCode::TypeError, testing::HasSubstr("decimal precision")));
// Above INT_MAX: rejected on the raw uint64, not wrapped into range by static_cast<int>.
EXPECT_THAT(
orc_adapter::GetArrowType(liborc::createDecimalType(uint64_t{1} << 40, 2).get()),
Raises(StatusCode::TypeError, testing::HasSubstr("decimal precision")));
EXPECT_THAT(orc_adapter::GetArrowType(liborc::createDecimalType(10, 20).get()),
Raises(StatusCode::TypeError, testing::HasSubstr("decimal scale")));

// precision == 0 is the legacy HIVE 0.11/0.12 "max precision" sentinel.
ASSERT_OK_AND_ASSIGN(auto hive_sentinel,
orc_adapter::GetArrowType(liborc::createDecimalType(0, 0).get()));
AssertTypeEqual(*decimal128(38, 6), *hive_sentinel);

ASSERT_OK_AND_ASSIGN(auto ok_mid,
orc_adapter::GetArrowType(liborc::createDecimalType(18, 4).get()));
AssertTypeEqual(*decimal128(18, 4), *ok_mid);
ASSERT_OK_AND_ASSIGN(
auto ok_max,
orc_adapter::GetArrowType(liborc::createDecimalType(Decimal128Type::kMaxPrecision,
Decimal128Type::kMaxPrecision)
.get()));
AssertTypeEqual(*decimal128(38, 38), *ok_max);
}

// Trivial

class TestORCWriterTrivialNoWrite : public ::testing::Test {};
Expand Down
16 changes: 13 additions & 3 deletions cpp/src/arrow/adapters/orc/util.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1197,13 +1197,23 @@ Result<std::shared_ptr<DataType>> GetArrowType(const liborc::Type* type) {
case liborc::DATE:
return date32();
case liborc::DECIMAL: {
const int precision = static_cast<int>(type->getPrecision());
const int scale = static_cast<int>(type->getScale());
// decimal128() aborts via ARROW_CHECK when precision is out of [1, 38], so validate
// the untrusted footer values (as raw uint64, before the narrowing cast) first.
const uint64_t precision = type->getPrecision();
const uint64_t scale = type->getScale();
if (precision == 0) {
// In HIVE 0.11/0.12 precision is set as 0, but means max precision
return decimal128(38, 6);
}
return decimal128(precision, scale);
if (precision > static_cast<uint64_t>(Decimal128Type::kMaxPrecision)) {
return Status::TypeError("Invalid ORC decimal precision ", precision,
": must be in [1, ", Decimal128Type::kMaxPrecision, "]");
}
if (scale > precision) {
return Status::TypeError("Invalid ORC decimal scale ", scale,
": must be in [0, precision=", precision, "]");
}
return decimal128(static_cast<int>(precision), static_cast<int>(scale));
}
case liborc::LIST: {
if (subtype_count != 1) {
Expand Down
Loading