Skip to content

[C++] Acero produces unexpected output type for add function on decimals #35843

Description

@agoncharuk

Describe the bug, including details regarding any error messages, version, and platform.

According to compute functions documentation, the add function result precision and scale are computed as

scale = max(s1, s2)
precision = max(p1-s1, p2-s2) + 1 + scale

For some reason, this inference produces an incorrect result for decimal(10, 1) and decimal(10, 2) types when using acero streaming engine, namely:

add(decimal(10, 1), decimal(10, 2)) -> decimal(11, 1); // Unexpected
add(decimal(10, 2), decimal(10, 1)) -> decimal(12, 2); // Ok

Full test:

 auto t0 = std::static_pointer_cast<arrow::DecimalType>(*arrow::DecimalType::Make(arrow::Type::DECIMAL128, 10, 1));
auto t1 = std::static_pointer_cast<arrow::DecimalType>(*arrow::DecimalType::Make(arrow::Type::DECIMAL128, 10, 2));
arrow::Decimal128Builder b0(t0);
arrow::Decimal128Builder b1(t1);
for (int i = 0; i < 10; ++i) {
EXPECT_TRUE(b0.Append(i * 10).ok());
EXPECT_TRUE(b1.Append((i + 1) * 100).ok());
}
auto batch = arrow::compute::ExecBatch::Make({*b0.Finish(), *b1.Finish()}, 10).ValueOrDie();
auto gen = arrow::MakeVectorGenerator(std::vector{std::make_optional(std::move(batch))});
auto schema = arrow::schema({arrow::field("c0", t0), arrow::field("c1", t1)});
arrow::acero::Declaration source{"source", arrow::acero::SourceNodeOptions{schema, std::move(gen)}};
arrow::compute::Expression p0 = cp::call("add", {arrow::compute::field_ref("c0"), arrow::compute::field_ref("c1")});
arrow::compute::Expression p1 = cp::call("add", {arrow::compute::field_ref("c1"), arrow::compute::field_ref("c0")});
arrow::acero::Declaration project{
"project", {std::move(source)}, arrow::acero::ProjectNodeOptions({p0, p1})};
auto responseTable = arrow::acero::DeclarationToTable(std::move(project)).ValueOrDie();
auto outSchema = responseTable->schema();
auto scale = std::max(t0->scale(), t1->scale());
auto precision = std::max(t0->precision() - t0->scale(), t1->precision() - t1->scale()) + 1 + scale;
auto expectedOutType = *arrow::DecimalType::Make(arrow::Type::DECIMAL128, precision, scale);
for (int c = 0; c < outSchema->num_fields(); ++c) {
EXPECT_TRUE(expectedOutType->Equals(outSchema->field(c)->type())) << "Failed for " << c << ": " << outSchema->field(c)->type()->ToString();
}

If I call arrow::compute::Add() directly on Datums, the expected types are correct regardless of the order.

Component(s)

C++

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions