Produce a bound Expression from unbound Call and bound arguments.
| 537 | |
| 538 | // Produce a bound Expression from unbound Call and bound arguments. |
| 539 | Result<Expression> BindNonRecursive(Expression::Call call, bool insert_implicit_casts, |
| 540 | compute::ExecContext* exec_context) { |
| 541 | DCHECK(std::all_of(call.arguments.begin(), call.arguments.end(), |
| 542 | [](const Expression& argument) { return argument.IsBound(); })); |
| 543 | |
| 544 | std::vector<TypeHolder> types = GetTypes(call.arguments); |
| 545 | ARROW_ASSIGN_OR_RAISE(call.function, GetFunction(call, exec_context)); |
| 546 | |
| 547 | // First try and bind exactly |
| 548 | Result<const Kernel*> maybe_exact_match = call.function->DispatchExact(types); |
| 549 | if (maybe_exact_match.ok()) { |
| 550 | call.kernel = *maybe_exact_match; |
| 551 | } else { |
| 552 | if (!insert_implicit_casts) { |
| 553 | return maybe_exact_match.status(); |
| 554 | } |
| 555 | |
| 556 | // If exact binding fails, and we are allowed to cast, then prefer casting literals |
| 557 | // first. Since DispatchBest generally prefers up-casting the best way to do this is |
| 558 | // first down-cast the literals as much as possible |
| 559 | types = GetTypesWithSmallestLiteralRepresentation(call.arguments); |
| 560 | ARROW_ASSIGN_OR_RAISE(call.kernel, call.function->DispatchBest(&types)); |
| 561 | |
| 562 | for (size_t i = 0; i < types.size(); ++i) { |
| 563 | if (types[i] == call.arguments[i].type()) continue; |
| 564 | |
| 565 | if (const Datum* lit = call.arguments[i].literal()) { |
| 566 | ARROW_ASSIGN_OR_RAISE(Datum new_lit, |
| 567 | compute::Cast(*lit, types[i].GetSharedPtr())); |
| 568 | call.arguments[i] = literal(std::move(new_lit)); |
| 569 | continue; |
| 570 | } |
| 571 | |
| 572 | // construct an implicit cast Expression with which to replace this argument |
| 573 | Expression::Call implicit_cast; |
| 574 | implicit_cast.function_name = "cast"; |
| 575 | implicit_cast.arguments = {std::move(call.arguments[i])}; |
| 576 | |
| 577 | // TODO(wesm): Use TypeHolder in options |
| 578 | implicit_cast.options = std::make_shared<compute::CastOptions>( |
| 579 | compute::CastOptions::Safe(types[i].GetSharedPtr())); |
| 580 | |
| 581 | ARROW_ASSIGN_OR_RAISE( |
| 582 | call.arguments[i], |
| 583 | BindNonRecursive(std::move(implicit_cast), |
| 584 | /*insert_implicit_casts=*/false, exec_context)); |
| 585 | } |
| 586 | } |
| 587 | |
| 588 | compute::KernelContext kernel_context(exec_context, call.kernel); |
| 589 | if (call.kernel->init) { |
| 590 | const FunctionOptions* options = |
| 591 | call.options ? call.options.get() : call.function->default_options(); |
| 592 | ARROW_ASSIGN_OR_RAISE( |
| 593 | call.kernel_state, |
| 594 | call.kernel->init(&kernel_context, {call.kernel, types, options})); |
| 595 | |
| 596 | kernel_context.SetState(call.kernel_state.get()); |
no test coverage detected