diff --git a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc index d4dda5556b3b..f82ff6749c26 100644 --- a/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc +++ b/cpp/src/arrow/compute/kernels/scalar_string_ascii.cc @@ -889,6 +889,12 @@ void AddAsciiStringLength(FunctionRegistry* registry) { ty); DCHECK_OK(func->AddKernel({ty}, int64(), std::move(exec))); } + // View element length is int32-sized, so both view types emit int32. + for (const auto& ty : BinaryViewTypes()) { + auto exec = GenerateVarBinaryViewBase(*ty); + DCHECK_OK(func->AddKernel({ty}, int32(), std::move(exec))); + } DCHECK_OK(func->AddKernel({InputType(Type::FIXED_SIZE_BINARY)}, int32(), BinaryLength::FixedSizeExec)); DCHECK_OK(registry->AddFunction(std::move(func))); @@ -1337,27 +1343,47 @@ struct RegexSubstringMatcher { template struct MatchSubstringImpl { - using offset_type = typename Type::offset_type; - static Status Exec(KernelContext* ctx, const ExecSpan& batch, ExecResult* out, const Matcher* matcher) { - StringBoolTransform( - ctx, batch, - [&matcher](const void* raw_offsets, const uint8_t* data, int64_t length, - int64_t output_offset, uint8_t* output) { - const offset_type* offsets = reinterpret_cast(raw_offsets); - FirstTimeBitmapWriter bitmap_writer(output, output_offset, length); - for (int64_t i = 0; i < length; ++i) { - const char* current_data = reinterpret_cast(data + offsets[i]); - int64_t current_length = offsets[i + 1] - offsets[i]; - if (matcher->Match(std::string_view(current_data, current_length))) { + if constexpr (is_binary_view_like_type::value) { + // Views have no packed offset buffer, so evaluate per element. Null slots are + // skipped: a view's null header is not validated and may carry a bogus + // buffer_index/offset that decoding would dereference. + const ArraySpan& input = batch[0].array; + ArraySpan* out_arr = out->array_span_mutable(); + FirstTimeBitmapWriter bitmap_writer(out_arr->buffers[1].data, out_arr->offset, + input.length); + VisitArrayValuesInline( + input, + [&](std::string_view val) { + if (matcher->Match(val)) { bitmap_writer.Set(); } bitmap_writer.Next(); - } - bitmap_writer.Finish(); - }, - out); + }, + [&]() { bitmap_writer.Next(); }); + bitmap_writer.Finish(); + } else { + using offset_type = typename Type::offset_type; + StringBoolTransform( + ctx, batch, + [&matcher](const void* raw_offsets, const uint8_t* data, int64_t length, + int64_t output_offset, uint8_t* output) { + const offset_type* offsets = + reinterpret_cast(raw_offsets); + FirstTimeBitmapWriter bitmap_writer(output, output_offset, length); + for (int64_t i = 0; i < length; ++i) { + const char* current_data = reinterpret_cast(data + offsets[i]); + int64_t current_length = offsets[i + 1] - offsets[i]; + if (matcher->Match(std::string_view(current_data, current_length))) { + bitmap_writer.Set(); + } + bitmap_writer.Next(); + } + bitmap_writer.Finish(); + }, + out); + } return Status::OK(); } }; @@ -1611,6 +1637,19 @@ const FunctionDoc match_like_doc( {"strings"}, "MatchSubstringOptions", /*options_required=*/true); #endif +// Register the view kernels for a match-substring-style predicate. Registered per +// view type (not via GenerateVarBinaryViewBase) so utf8_view -> StringViewType keeps +// the is_utf8 distinction used by ignore_case/regex folding. +template