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)

Reply via email to