You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@arrow.apache.org by ze...@apache.org on 2026/08/12 17:44:34 UTC

(arrow-go) branch main updated: fix(compute): reject non-array-like filters (#1135)

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 <vu...@gmail.com>
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)