mirror of https://github.com/grafana/loki
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
773 lines
23 KiB
773 lines
23 KiB
package executor
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/stretchr/testify/require"
|
|
|
|
"github.com/grafana/loki/v3/pkg/dataobj/sections/logs"
|
|
"github.com/grafana/loki/v3/pkg/engine/internal/types"
|
|
"github.com/grafana/loki/v3/pkg/engine/planner/physical"
|
|
)
|
|
|
|
var (
|
|
testOpenStart = time.Unix(0, math.MinInt64).UTC()
|
|
testOpenEnd = time.Unix(0, math.MaxInt64).UTC()
|
|
)
|
|
|
|
func newColumnExpr(column string, ty types.ColumnType) *physical.ColumnExpr {
|
|
return &physical.ColumnExpr{
|
|
Ref: types.ColumnRef{
|
|
Column: column,
|
|
Type: ty,
|
|
},
|
|
}
|
|
}
|
|
|
|
func tsColExpr() *physical.ColumnExpr {
|
|
return newColumnExpr(types.ColumnNameBuiltinTimestamp, types.ColumnTypeBuiltin)
|
|
}
|
|
|
|
func TestMapTimestampPredicate(t *testing.T) {
|
|
time100 := time.Unix(0, 100).UTC()
|
|
time200 := time.Unix(0, 200).UTC()
|
|
time300 := time.Unix(0, 300).UTC()
|
|
|
|
for _, tc := range []struct {
|
|
desc string
|
|
expr physical.Expression
|
|
want logs.TimeRangeRowPredicate
|
|
errMatch string
|
|
}{
|
|
{
|
|
desc: "timestamp == 100",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp > 100",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: testOpenEnd,
|
|
IncludeStart: false,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp >= 100",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: testOpenEnd,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp < 100",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: testOpenStart,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp <= 100",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: testOpenStart,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp > (timestamp < 100) - now invalid",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
errMatch: "invalid RHS for comparison: expected literal timestamp, got *physical.BinaryExpr",
|
|
},
|
|
{
|
|
desc: "timestamp == (timestamp >= (timestamp <= 200)) - now invalid",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGte,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLte,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
},
|
|
errMatch: "invalid RHS for comparison: expected literal timestamp, got *physical.BinaryExpr",
|
|
},
|
|
{
|
|
desc: "input is not BinaryExpr",
|
|
expr: physical.NewLiteral(time100),
|
|
errMatch: "unsupported expression type for timestamp predicate: *physical.LiteralExpr, expected *physical.BinaryExpr",
|
|
},
|
|
{
|
|
desc: "LHS of BinaryExpr is not ColumnExpr",
|
|
expr: &physical.BinaryExpr{
|
|
Left: physical.NewLiteral(time100),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
errMatch: "invalid LHS for comparison: expected timestamp column, got 1970-01-01T00:00:00.0000001Z",
|
|
},
|
|
{
|
|
desc: "LHS column is not timestamp",
|
|
expr: &physical.BinaryExpr{
|
|
Left: newColumnExpr("other_col", types.ColumnTypeBuiltin),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
errMatch: "invalid LHS for comparison: expected timestamp column, got builtin.other_col",
|
|
},
|
|
{
|
|
desc: "RHS Literal is not a timestamp type",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral("not_a_timestamp"),
|
|
},
|
|
errMatch: "unsupported literal type for RHS: string, expected timestamp",
|
|
},
|
|
{
|
|
desc: "RHS is an unsupported type (ColumnExpr)",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: newColumnExpr("another_ts", types.ColumnTypeBuiltin),
|
|
},
|
|
errMatch: "invalid RHS for comparison: expected literal timestamp, got *physical.ColumnExpr",
|
|
},
|
|
{
|
|
desc: "Unsupported operator (AND) used as a simple comparison",
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpAnd,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
errMatch: "invalid left operand for AND: unsupported expression type for timestamp predicate: *physical.ColumnExpr, expected *physical.BinaryExpr",
|
|
},
|
|
{
|
|
desc: "Unsupported operator (OR) from outer op in nested scenario", // OR is still unsupported directly
|
|
expr: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpOr,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
errMatch: "unsupported operator for timestamp predicate: OR",
|
|
},
|
|
{
|
|
desc: "timestamp > 100 AND timestamp < 200",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: time200,
|
|
IncludeStart: false,
|
|
IncludeEnd: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp >= 100 AND timestamp <= 200",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLte,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: time200,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp >= 100 AND timestamp < 100 (point exclusive)", // leads to impossible range
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
errMatch: "impossible time range: start_time (1970-01-01 00:00:00.0000001 +0000 UTC) equals end_time (1970-01-01 00:00:00.0000001 +0000 UTC) but the range is exclusive",
|
|
},
|
|
{
|
|
desc: "timestamp > 100 AND timestamp <= 100 (point exclusive)", // leads to impossible range
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
errMatch: "impossible time range: start_time (1970-01-01 00:00:00.0000001 +0000 UTC) equals end_time (1970-01-01 00:00:00.0000001 +0000 UTC) but the range is exclusive",
|
|
},
|
|
{
|
|
desc: "timestamp >= 100 AND timestamp <= 100 (point inclusive)",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLte,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time100,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp == 100 AND timestamp == 200", // impossible
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
errMatch: "impossible time range: start_time (1970-01-01 00:00:00.0000002 +0000 UTC) is after end_time (1970-01-01 00:00:00.0000001 +0000 UTC)",
|
|
},
|
|
{
|
|
desc: "timestamp < 100 AND timestamp > 200", // impossible
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
errMatch: "impossible time range: start_time (1970-01-01 00:00:00.0000002 +0000 UTC) is after end_time (1970-01-01 00:00:00.0000001 +0000 UTC)",
|
|
},
|
|
{
|
|
desc: "(timestamp > 100 AND timestamp < 300) AND timestamp == 200",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time300),
|
|
},
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpEq,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: time200,
|
|
EndTime: time200,
|
|
IncludeStart: true,
|
|
IncludeEnd: true,
|
|
},
|
|
},
|
|
{
|
|
desc: "AND with invalid left operand",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{ // Invalid: LHS not timestamp column
|
|
Left: newColumnExpr("not_ts", types.ColumnTypeBuiltin),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
errMatch: "invalid left operand for AND: invalid LHS for comparison: expected timestamp column, got builtin.not_ts",
|
|
},
|
|
{
|
|
desc: "AND with invalid right operand (RHS literal type)",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpGt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{ // Invalid: RHS literal not timestamp
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral("not-a-time"),
|
|
},
|
|
},
|
|
errMatch: "invalid right operand for AND: unsupported literal type for RHS: string, expected timestamp",
|
|
},
|
|
{
|
|
desc: "timestamp < 100 AND timestamp < 200 (should be ts < 100)",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: testOpenStart,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: false,
|
|
},
|
|
},
|
|
{
|
|
desc: "timestamp < 200 AND timestamp < 100 (should be ts < 100)",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time200),
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
Right: &physical.BinaryExpr{
|
|
Left: tsColExpr(),
|
|
Op: types.BinaryOpLt,
|
|
Right: physical.NewLiteral(time100),
|
|
},
|
|
},
|
|
want: logs.TimeRangeRowPredicate{
|
|
StartTime: testOpenStart,
|
|
EndTime: time100,
|
|
IncludeStart: true,
|
|
IncludeEnd: false,
|
|
},
|
|
},
|
|
} {
|
|
t.Run(tc.desc, func(t *testing.T) {
|
|
got, err := mapTimestampPredicate(tc.expr)
|
|
if tc.errMatch != "" {
|
|
require.ErrorContains(t, err, tc.errMatch)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.want, got)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMapMetadataPredicate(t *testing.T) {
|
|
tests := []struct {
|
|
name string
|
|
expr physical.Expression
|
|
expectedPred logs.RowPredicate
|
|
expectedErr bool
|
|
expectedErrAs any // For errors.As checks
|
|
}{
|
|
{
|
|
name: "simple metadata matcher",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
expectedPred: logs.MetadataMatcherRowPredicate{Key: "foo", Value: "bar"},
|
|
expectedErr: false,
|
|
},
|
|
{
|
|
name: "AND predicate",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Right: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "baz", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("qux"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
},
|
|
expectedPred: logs.AndRowPredicate{
|
|
Left: logs.MetadataMatcherRowPredicate{Key: "foo", Value: "bar"},
|
|
Right: logs.MetadataMatcherRowPredicate{Key: "baz", Value: "qux"},
|
|
},
|
|
expectedErr: false,
|
|
},
|
|
{
|
|
name: "OR predicate",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Right: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "baz", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("qux"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Op: types.BinaryOpOr,
|
|
},
|
|
expectedPred: logs.OrRowPredicate{
|
|
Left: logs.MetadataMatcherRowPredicate{Key: "foo", Value: "bar"},
|
|
Right: logs.MetadataMatcherRowPredicate{Key: "baz", Value: "qux"},
|
|
},
|
|
expectedErr: false,
|
|
},
|
|
{
|
|
name: "NOT predicate",
|
|
expr: &physical.UnaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Op: types.UnaryOpNot,
|
|
},
|
|
expectedPred: logs.NotRowPredicate{
|
|
Inner: logs.MetadataMatcherRowPredicate{Key: "foo", Value: "bar"},
|
|
},
|
|
expectedErr: false,
|
|
},
|
|
{
|
|
name: "nested AND OR predicate",
|
|
expr: &physical.BinaryExpr{ // AND
|
|
Left: &physical.BinaryExpr{ // foo == "bar"
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Right: &physical.BinaryExpr{ // OR
|
|
Left: &physical.BinaryExpr{ // baz == "qux"
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "baz", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("qux"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Right: &physical.BinaryExpr{ // faz == "fuzz"
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "faz", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("fuzz"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
Op: types.BinaryOpOr,
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
},
|
|
expectedPred: logs.AndRowPredicate{
|
|
Left: logs.MetadataMatcherRowPredicate{Key: "foo", Value: "bar"},
|
|
Right: logs.OrRowPredicate{
|
|
Left: logs.MetadataMatcherRowPredicate{Key: "baz", Value: "qux"},
|
|
Right: logs.MetadataMatcherRowPredicate{Key: "faz", Value: "fuzz"},
|
|
},
|
|
},
|
|
expectedErr: false,
|
|
},
|
|
{
|
|
name: "error: unsupported binary operator",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpGt, // GT is not supported for metadata
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: unsupported unary operator",
|
|
expr: &physical.UnaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Op: types.UnaryOpAbs, // ABS is not supported
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: LHS not column expr in binary expr",
|
|
expr: &physical.BinaryExpr{
|
|
Left: physical.NewLiteral("foo"),
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: LHS column not metadata type",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeBuiltin}}, // Not metadata
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: RHS not literal for EQ",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "bar", Type: types.ColumnTypeMetadata}}, // Not literal
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: RHS literal not string for EQ",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "foo", Type: types.ColumnTypeMetadata}},
|
|
Right: physical.NewLiteral(123), // Not string
|
|
Op: types.BinaryOpEq,
|
|
},
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
{
|
|
name: "error: unsupported expression type (LiteralExpr)",
|
|
expr: physical.NewLiteral("just a string"),
|
|
expectedPred: nil,
|
|
expectedErr: true,
|
|
},
|
|
}
|
|
|
|
for _, tc := range tests {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
pred, err := mapMetadataPredicate(tc.expr)
|
|
|
|
if tc.expectedErr {
|
|
require.Error(t, err)
|
|
if tc.expectedErrAs != nil {
|
|
require.ErrorAs(t, err, tc.expectedErrAs)
|
|
}
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.expectedPred, pred)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestMapMessagePredicate(t *testing.T) {
|
|
for _, tc := range []struct {
|
|
name string
|
|
expr physical.Expression
|
|
expectedErr string
|
|
expectedType string
|
|
}{
|
|
{
|
|
name: "string match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("dataobjscan"),
|
|
Op: types.BinaryOpMatchSubstr,
|
|
},
|
|
expectedType: "logs.LogMessageFilterRowPredicate",
|
|
},
|
|
{
|
|
name: "not string match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("dataobjscan"),
|
|
Op: types.BinaryOpNotMatchSubstr,
|
|
},
|
|
expectedType: "logs.LogMessageFilterRowPredicate",
|
|
},
|
|
{
|
|
name: "regex match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral(`\d{4}-\d{2}-\d{2}`),
|
|
Op: types.BinaryOpMatchRe,
|
|
},
|
|
expectedType: "logs.LogMessageFilterRowPredicate",
|
|
},
|
|
{
|
|
name: "not regex match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral(`\d{4}-\d{2}-\d{2}`),
|
|
Op: types.BinaryOpNotMatchRe,
|
|
},
|
|
expectedType: "logs.LogMessageFilterRowPredicate",
|
|
},
|
|
{
|
|
name: "pattern match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("<_> dataobj <_>"),
|
|
Op: types.BinaryOpMatchPattern,
|
|
},
|
|
expectedErr: "unsupported binary operator (MATCH_PAT) for log message predicate",
|
|
},
|
|
{
|
|
name: "not pattern match filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("<_> dataobj <_>"),
|
|
Op: types.BinaryOpNotMatchPattern,
|
|
},
|
|
expectedErr: "unsupported binary operator (NOT_MATCH_PAT) for log message predicate",
|
|
},
|
|
{
|
|
name: "and filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("foo"),
|
|
Op: types.BinaryOpMatchSubstr,
|
|
},
|
|
Right: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpNotMatchSubstr,
|
|
},
|
|
Op: types.BinaryOpAnd,
|
|
},
|
|
expectedType: "logs.AndRowPredicate",
|
|
},
|
|
{
|
|
name: "or filter",
|
|
expr: &physical.BinaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("foo"),
|
|
Op: types.BinaryOpMatchSubstr,
|
|
},
|
|
Right: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("bar"),
|
|
Op: types.BinaryOpNotMatchSubstr,
|
|
},
|
|
Op: types.BinaryOpOr,
|
|
},
|
|
expectedType: "logs.OrRowPredicate",
|
|
},
|
|
{
|
|
name: "not filter",
|
|
expr: &physical.UnaryExpr{
|
|
Left: &physical.BinaryExpr{
|
|
Left: &physical.ColumnExpr{Ref: types.ColumnRef{Column: "message", Type: types.ColumnTypeBuiltin}},
|
|
Right: physical.NewLiteral("foo"),
|
|
Op: types.BinaryOpMatchSubstr,
|
|
},
|
|
Op: types.UnaryOpNot,
|
|
},
|
|
expectedType: "logs.NotRowPredicate",
|
|
},
|
|
} {
|
|
t.Run(tc.name, func(t *testing.T) {
|
|
t.Logf("%s", tc.expr)
|
|
got, err := mapMessagePredicate(tc.expr)
|
|
if tc.expectedErr != "" {
|
|
require.ErrorContains(t, err, tc.expectedErr)
|
|
} else {
|
|
require.NoError(t, err)
|
|
require.Equal(t, tc.expectedType, fmt.Sprintf("%T", got))
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|