This is an automated email from the ASF dual-hosted git repository.
zeroshade pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/arrow-go.git
The following commit(s) were added to refs/heads/main by this push:
new 924268aa fix(compute): reject non-array-like filters (#1135)
924268aa is described below
commit 924268aad586452d7d5afb0fcd7d7cf459ea38ec
Author: Minh Vu <[email protected]>
AuthorDate: Wed Aug 12 19:44:29 2026 +0200
fix(compute): reject non-array-like filters (#1135)
### Rationale for this change
The filter meta-function assumes the filter datum implements
ArrayLikeDatum before checking its kind. A record batch or table passed
as the filter therefore causes a panic instead of the existing
unsupported-type error.
### What changes are included in this PR?
Validate that the filter is array-like before reading its type. Keep
scalar boolean filters supported and add coverage for a record batch
used as the filter.
### Are these changes tested?
- `go test ./arrow/compute`
### Are there any user-facing changes?
Invalid record or table filters now return an error instead of
panicking. Valid array, chunked, and scalar boolean filters are
unchanged.
---
arrow/compute/selection.go | 7 ++++-
arrow/compute/vector_selection_test.go | 56 ++++++++++++++++++++++++++++++++++
2 files changed, 62 insertions(+), 1 deletion(-)
diff --git a/arrow/compute/selection.go b/arrow/compute/selection.go
index 0936122d..38d43728 100644
--- a/arrow/compute/selection.go
+++ b/arrow/compute/selection.go
@@ -40,7 +40,12 @@ are handled based on FilterOptions.`,
}
filterMetaFunc = NewMetaFunction("filter", Binary(), filterDoc,
func(ctx context.Context, opts FunctionOptions, args ...Datum)
(Datum, error) {
- if args[1].(ArrayLikeDatum).Type().ID() != arrow.BOOL {
+ filter, ok := args[1].(ArrayLikeDatum)
+ if !ok {
+ return nil, fmt.Errorf("%w: filter should be
array-like", arrow.ErrNotImplemented)
+ }
+
+ if filter.Type().ID() != arrow.BOOL {
return nil, fmt.Errorf("%w: filter argument
must be boolean type",
arrow.ErrNotImplemented)
}
diff --git a/arrow/compute/vector_selection_test.go
b/arrow/compute/vector_selection_test.go
index 6308231b..08d41bae 100644
--- a/arrow/compute/vector_selection_test.go
+++ b/arrow/compute/vector_selection_test.go
@@ -2366,6 +2366,62 @@ func BenchmarkTakeStringPartitionPattern(b *testing.B) {
b.ReportMetric(float64(numRows*b.N)/b.Elapsed().Seconds(), "rows/sec")
}
+func TestFilterRejectsNonArrayLikeFilters(t *testing.T) {
+ mem := memory.NewCheckedAllocator(memory.DefaultAllocator)
+ defer mem.AssertSize(t, 0)
+
+ values, _, err := array.FromJSON(mem, arrow.PrimitiveTypes.Int32,
strings.NewReader("[1]"))
+ require.NoError(t, err)
+ defer values.Release()
+
+ valuesDatum := compute.NewDatum(values)
+ defer valuesDatum.Release()
+ schema := arrow.NewSchema([]arrow.Field{{Name: "filter", Type:
arrow.PrimitiveTypes.Int32}}, nil)
+ filterRecord := array.NewRecordBatch(
+ schema,
+ []arrow.Array{values},
+ 1,
+ )
+ defer filterRecord.Release()
+ filterTable := array.NewTableFromRecords(schema,
[]arrow.RecordBatch{filterRecord})
+ defer filterTable.Release()
+
+ for _, tt := range []struct {
+ name string
+ filter interface{}
+ }{
+ {"record batch", filterRecord},
+ {"table", filterTable},
+ } {
+ t.Run(tt.name, func(t *testing.T) {
+ filterDatum := compute.NewDatum(tt.filter)
+ defer filterDatum.Release()
+
+ _, err := compute.Filter(context.Background(),
valuesDatum, filterDatum, compute.FilterOptions{})
+ require.ErrorIs(t, err, arrow.ErrNotImplemented)
+ })
+ }
+}
+
+func TestFilterAcceptsScalarBooleanFilter(t *testing.T) {
+ valuesDatum := compute.NewDatum(int32(1))
+ defer valuesDatum.Release()
+ filterDatum := compute.NewDatum(true)
+ defer filterDatum.Release()
+
+ result, err := compute.Filter(context.Background(), valuesDatum,
filterDatum, compute.FilterOptions{})
+ require.NoError(t, err)
+ defer result.Release()
+
+ expected, _, err := array.FromJSON(memory.DefaultAllocator,
arrow.PrimitiveTypes.Int32, strings.NewReader("[1]"))
+ require.NoError(t, err)
+ defer expected.Release()
+ actual := result.(*compute.ArrayDatum).MakeArray()
+ defer actual.Release()
+
+ require.True(t, array.Equal(expected, actual))
+}
+
func BenchmarkTakeMultiColumn(b *testing.B) {
// Benchmark Take on a record batch with multiple string columns
// to simulate real-world use cases (e.g., CloudFront logs with 20+
string columns)