Skip to content

[C++][Compute] Binary kernels should consider decimal scale constraints when matching #47287

Description

@zanmato1984

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

This is revealed by a regressed test in #47284. I did some trace back and put my finding here.

The issue

There was a reported issue #40126. In short, an expression add(decimal128(30, 3), decimal128(20, 9)) fires some internal DCHECK.

The root cause

The DispatchExact of function add considers the kernel with signature add(decimal128(*), decimal128(*)) as a match, ignoring the precision and scale "constraint" for this kernel. Later when the kernel's Init method is invoked, it complains that scale of the first argument (3) is not the same as the second (9) - the "constraint".

The fix (#40223)

  • Before: Binding a function call expression will first do DispatchExact, then fail-over to DispatchBest if an exact match isn't found. (As the root cause says, DispatchExact did find an exact match for this case.)
  • After: When an exact match is found, also try to invoke the kernel's Init method. And if that fails, fail-over to DispatchBest. Given that our arithmetic function does decent precision and scale promotion in DispatchBest (which is nice), proper implicit casts are applied to the arguments and the execution is fine.

What's not right

  • The fix is essentially to tolerate the error in Init and to fail-over to DispatchBest. This may discard the real error thrown in Init - though it is likely that the error would be thrown again after DispatchBest, other error may happen subsequently and hides the original one. UT in GH-47268: [C++][Compute] Fix discarded bad status for call binding #47284 is an example.
  • Ideally we should let DispatchExact fail immediately as long as the arguments don't qualify the constraint other than merely type checks, i.e., the precision/scale equality "constraint". This way, the binding naturally fails over to DispatchBest, without having to try to invoke the Init ahead. As a result, the error thrown in Init is properly preserved and propagated.

What's hard

It's currently a fundamental limitation in our kernel matching mechanism to apply extra constraints other than doing simply type checks. That prevents us from being able to fail DispatchExact immediately. This is also common for most parametric types like decimals. Related issue:

Component(s)

C++

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions