2017-10-24 01:42:53 +00:00
|
|
|
package storage_test
|
|
|
|
|
|
|
|
import (
|
|
|
|
"testing"
|
|
|
|
|
|
|
|
"github.com/influxdata/influxdb/pkg/testing/assert"
|
|
|
|
"github.com/influxdata/influxdb/services/storage"
|
2017-10-30 21:40:26 +00:00
|
|
|
"github.com/influxdata/influxql"
|
2017-10-24 01:42:53 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func TestPredicateToExprString(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
n string
|
|
|
|
r *storage.Predicate
|
|
|
|
e string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
n: "returns [none] for nil",
|
|
|
|
r: nil,
|
|
|
|
e: "[none]",
|
|
|
|
},
|
|
|
|
{
|
|
|
|
n: "logical AND",
|
|
|
|
r: &storage.Predicate{
|
|
|
|
Root: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeLogicalExpression,
|
|
|
|
Value: &storage.Node_Logical_{Logical: storage.LogicalAnd},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "host"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_StringValue{StringValue: "host1"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonRegex},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "region"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_RegexValue{RegexValue: "^us-west"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
e: `'host' = "host1" AND 'region' =~ /^us-west/`,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.n, func(t *testing.T) {
|
|
|
|
assert.Equal(t, storage.PredicateToExprString(tc.r), tc.e)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func TestNodeToExpr(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
n string
|
|
|
|
r *storage.Node
|
2018-03-23 03:38:44 +00:00
|
|
|
m map[string]string
|
2017-10-24 01:42:53 +00:00
|
|
|
e string
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
n: "simple expression",
|
|
|
|
r: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "host"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_StringValue{StringValue: "host1"}},
|
|
|
|
},
|
|
|
|
},
|
2018-09-25 22:36:24 +00:00
|
|
|
e: `host::tag = 'host1'`,
|
2017-10-24 01:42:53 +00:00
|
|
|
},
|
|
|
|
{
|
2018-03-23 03:38:44 +00:00
|
|
|
n: "logical AND with regex",
|
2017-10-24 01:42:53 +00:00
|
|
|
r: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeLogicalExpression,
|
|
|
|
Value: &storage.Node_Logical_{Logical: storage.LogicalAnd},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "host"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_StringValue{StringValue: "host1"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonRegex},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "region"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_RegexValue{RegexValue: "^us-west"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2018-09-25 22:36:24 +00:00
|
|
|
e: `host::tag = 'host1' AND region::tag =~ /^us-west/`,
|
2017-10-24 01:42:53 +00:00
|
|
|
},
|
2018-06-22 17:59:41 +00:00
|
|
|
{
|
|
|
|
n: "optimisable regex",
|
|
|
|
r: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonRegex},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "region"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_RegexValue{RegexValue: "^us-east$"}},
|
|
|
|
},
|
|
|
|
},
|
2018-09-25 22:36:24 +00:00
|
|
|
e: `region::tag = 'us-east'`,
|
2018-06-22 17:59:41 +00:00
|
|
|
},
|
|
|
|
{
|
|
|
|
n: "optimisable regex with or",
|
|
|
|
r: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonRegex},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "region"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_RegexValue{RegexValue: "^(us-east|us-west)$"}},
|
|
|
|
},
|
|
|
|
},
|
2018-09-25 22:36:24 +00:00
|
|
|
e: `region::tag = 'us-east' OR region::tag = 'us-west'`,
|
2018-06-22 17:59:41 +00:00
|
|
|
},
|
2018-03-23 03:38:44 +00:00
|
|
|
{
|
|
|
|
n: "remap _measurement -> _name",
|
|
|
|
r: &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "_measurement"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_StringValue{StringValue: "foo"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
m: map[string]string{"_measurement": "_name"},
|
2018-09-25 22:36:24 +00:00
|
|
|
e: `_name::tag = 'foo'`,
|
2018-03-23 03:38:44 +00:00
|
|
|
},
|
2017-10-24 01:42:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
t.Run(tc.n, func(t *testing.T) {
|
2018-03-23 03:38:44 +00:00
|
|
|
expr, err := storage.NodeToExpr(tc.r, tc.m)
|
2017-10-24 01:42:53 +00:00
|
|
|
assert.NoError(t, err)
|
|
|
|
assert.Equal(t, expr.String(), tc.e)
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-13 18:05:59 +00:00
|
|
|
func TestHasSingleMeasurementNoOR(t *testing.T) {
|
|
|
|
cases := []struct {
|
|
|
|
expr influxql.Expr
|
|
|
|
name string
|
|
|
|
ok bool
|
|
|
|
}{
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_name = 'm0'`),
|
|
|
|
name: "m0",
|
|
|
|
ok: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_something = 'f' AND _name = 'm0'`),
|
|
|
|
name: "m0",
|
|
|
|
ok: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_something = 'f' AND (a =~ /x0/ AND _name = 'm0')`),
|
|
|
|
name: "m0",
|
|
|
|
ok: true,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`tag1 != 'foo'`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_name = 'm0' OR tag1 != 'foo'`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_name = 'm0' AND tag1 != 'foo' AND _name = 'other'`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_name = 'm0' AND tag1 != 'foo' OR _name = 'other'`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`_name = 'm0' AND (tag1 != 'foo' OR tag2 = 'other')`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
{
|
|
|
|
expr: influxql.MustParseExpr(`(tag1 != 'foo' OR tag2 = 'other') OR _name = 'm0'`),
|
|
|
|
ok: false,
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, tc := range cases {
|
|
|
|
name, ok := storage.HasSingleMeasurementNoOR(tc.expr)
|
|
|
|
if ok != tc.ok {
|
|
|
|
t.Fatalf("got %q, %v for expression %q, expected %q, %v", name, ok, tc.expr, tc.name, tc.ok)
|
|
|
|
}
|
|
|
|
|
|
|
|
if ok && name != tc.name {
|
|
|
|
t.Fatalf("got %q, %v for expression %q, expected %q, %v", name, ok, tc.expr, tc.name, tc.ok)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-10-24 01:42:53 +00:00
|
|
|
func TestRewriteExprRemoveFieldKeyAndValue(t *testing.T) {
|
|
|
|
node := &storage.Node{
|
|
|
|
NodeType: storage.NodeTypeLogicalExpression,
|
|
|
|
Value: &storage.Node_Logical_{Logical: storage.LogicalAnd},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "host"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_StringValue{StringValue: "host1"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonRegex},
|
|
|
|
Children: []*storage.Node{
|
|
|
|
{NodeType: storage.NodeTypeTagRef, Value: &storage.Node_TagRefValue{TagRefValue: "_field"}},
|
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_RegexValue{RegexValue: "^us-west"}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
{
|
|
|
|
NodeType: storage.NodeTypeComparisonExpression,
|
|
|
|
Value: &storage.Node_Comparison_{Comparison: storage.ComparisonEqual},
|
|
|
|
Children: []*storage.Node{
|
2018-09-25 22:36:24 +00:00
|
|
|
{NodeType: storage.NodeTypeFieldRef, Value: &storage.Node_FieldRefValue{FieldRefValue: "$"}},
|
2017-10-24 01:42:53 +00:00
|
|
|
{NodeType: storage.NodeTypeLiteral, Value: &storage.Node_FloatValue{FloatValue: 0.5}},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
|
2018-03-23 03:38:44 +00:00
|
|
|
expr, err := storage.NodeToExpr(node, nil)
|
2017-10-24 01:42:53 +00:00
|
|
|
assert.NoError(t, err, "NodeToExpr failed")
|
2018-09-25 22:36:24 +00:00
|
|
|
assert.Equal(t, expr.String(), `host::tag = 'host1' AND _field::tag =~ /^us-west/ AND "$" = 0.500`)
|
2017-10-24 01:42:53 +00:00
|
|
|
|
|
|
|
expr = storage.RewriteExprRemoveFieldKeyAndValue(expr)
|
2018-09-25 22:36:24 +00:00
|
|
|
assert.Equal(t, expr.String(), `host::tag = 'host1' AND true AND true`)
|
2017-10-24 01:42:53 +00:00
|
|
|
|
|
|
|
expr = influxql.Reduce(expr, mapValuer{"host": "host1"})
|
|
|
|
assert.Equal(t, expr.String(), `true`)
|
|
|
|
}
|
|
|
|
|
|
|
|
type mapValuer map[string]string
|
|
|
|
|
|
|
|
var _ influxql.Valuer = mapValuer(nil)
|
|
|
|
|
|
|
|
func (vs mapValuer) Value(key string) (interface{}, bool) {
|
|
|
|
v, ok := vs[key]
|
|
|
|
return v, ok
|
|
|
|
}
|