Merge pull request #6284 from influxdata/js-3371-where-clause-compare-tags-and-fields

Enhance comparing tags and fields in the where clause
pull/6090/merge
Jonathan A. Sternberg 2016-04-12 11:45:54 -04:00
commit 60282cf52d
5 changed files with 62 additions and 19 deletions

View File

@ -4577,6 +4577,18 @@ func TestServer_Query_Where_With_Tags(t *testing.T) {
command: `show series where data-center = 'foo'`,
exp: `{"error":"error parsing query: found DATA, expected identifier, string, number, bool at line 1, char 19"}`,
},
&Query{
name: "where comparing tag and field",
params: url.Values{"db": []string{"db0"}},
command: `select foo from where_events where tennant != foo`,
exp: `{"results":[{"series":[{"name":"where_events","columns":["time","foo"],"values":[["2009-11-10T23:00:02Z","bar"],["2009-11-10T23:00:03Z","baz"],["2009-11-10T23:00:04Z","bat"],["2009-11-10T23:00:05Z","bar"],["2009-11-10T23:00:06Z","bap"]]}]}]}`,
},
&Query{
name: "where comparing tag and tag",
params: url.Values{"db": []string{"db0"}},
command: `select foo from where_events where tennant = tennant`,
exp: `{"results":[{"series":[{"name":"where_events","columns":["time","foo"],"values":[["2009-11-10T23:00:02Z","bar"],["2009-11-10T23:00:03Z","baz"],["2009-11-10T23:00:04Z","bat"],["2009-11-10T23:00:05Z","bar"],["2009-11-10T23:00:06Z","bap"]]}]}]}`,
},
}...)
for i, query := range test.queries {

View File

@ -806,10 +806,8 @@ func (e *Engine) createVarRefIterator(opt influxql.IteratorOptions) ([]influxql.
if t.Filters[i] != nil {
// Retrieve non-time fields from this series filter and filter out tags.
for _, f := range influxql.ExprNames(t.Filters[i]) {
if mm.HasField(f) {
conditionFields[fields] = f
fields++
}
conditionFields[fields] = f
fields++
}
}
@ -865,15 +863,23 @@ func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, mm *tsdb.Measu
// Build conditional field cursors.
// If a conditional field doesn't exist then ignore the series.
var conds []*bufCursor
var conds []cursorAt
if len(conditionFields) > 0 {
conds = make([]*bufCursor, len(conditionFields))
conds = make([]cursorAt, len(conditionFields))
for i := range conds {
cur := e.buildCursor(mm.Name, seriesKey, conditionFields[i], opt)
if cur == nil {
return nil, nil
if cur != nil {
conds[i] = newBufCursor(cur, opt.Ascending)
continue
}
// If field doesn't exist, use the tag value.
// However, if the tag value is blank then return a null.
if v := tags.Value(conditionFields[i]); v == "" {
conds[i] = &stringNilLiteralCursor{}
} else {
conds[i] = &stringLiteralCursor{value: v}
}
conds[i] = newBufCursor(cur, opt.Ascending)
}
}

View File

@ -112,7 +112,7 @@ type floatIterator struct {
aux []cursorAt
conds struct {
names []string
curs []*bufCursor
curs []cursorAt
}
opt influxql.IteratorOptions
@ -124,7 +124,7 @@ type floatIterator struct {
statsBuf influxql.IteratorStats
}
func newFloatIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur floatCursor, aux []cursorAt, conds []*bufCursor, condNames []string) *floatIterator {
func newFloatIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur floatCursor, aux []cursorAt, conds []cursorAt, condNames []string) *floatIterator {
itr := &floatIterator{
cur: cur,
aux: aux,
@ -486,7 +486,7 @@ type integerIterator struct {
aux []cursorAt
conds struct {
names []string
curs []*bufCursor
curs []cursorAt
}
opt influxql.IteratorOptions
@ -498,7 +498,7 @@ type integerIterator struct {
statsBuf influxql.IteratorStats
}
func newIntegerIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur integerCursor, aux []cursorAt, conds []*bufCursor, condNames []string) *integerIterator {
func newIntegerIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur integerCursor, aux []cursorAt, conds []cursorAt, condNames []string) *integerIterator {
itr := &integerIterator{
cur: cur,
aux: aux,
@ -860,7 +860,7 @@ type stringIterator struct {
aux []cursorAt
conds struct {
names []string
curs []*bufCursor
curs []cursorAt
}
opt influxql.IteratorOptions
@ -872,7 +872,7 @@ type stringIterator struct {
statsBuf influxql.IteratorStats
}
func newStringIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur stringCursor, aux []cursorAt, conds []*bufCursor, condNames []string) *stringIterator {
func newStringIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur stringCursor, aux []cursorAt, conds []cursorAt, condNames []string) *stringIterator {
itr := &stringIterator{
cur: cur,
aux: aux,
@ -1234,7 +1234,7 @@ type booleanIterator struct {
aux []cursorAt
conds struct {
names []string
curs []*bufCursor
curs []cursorAt
}
opt influxql.IteratorOptions
@ -1246,7 +1246,7 @@ type booleanIterator struct {
statsBuf influxql.IteratorStats
}
func newBooleanIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur booleanCursor, aux []cursorAt, conds []*bufCursor, condNames []string) *booleanIterator {
func newBooleanIterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur booleanCursor, aux []cursorAt, conds []cursorAt, condNames []string) *booleanIterator {
itr := &booleanIterator{
cur: cur,
aux: aux,

View File

@ -108,7 +108,7 @@ type {{.name}}Iterator struct {
aux []cursorAt
conds struct {
names []string
curs []*bufCursor
curs []cursorAt
}
opt influxql.IteratorOptions
@ -120,7 +120,7 @@ type {{.name}}Iterator struct {
statsBuf influxql.IteratorStats
}
func new{{.Name}}Iterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur {{.name}}Cursor, aux []cursorAt, conds []*bufCursor, condNames []string) *{{.name}}Iterator {
func new{{.Name}}Iterator(name string, tags influxql.Tags, opt influxql.IteratorOptions, cur {{.name}}Cursor, aux []cursorAt, conds []cursorAt, condNames []string) *{{.name}}Iterator {
itr := &{{.name}}Iterator{
cur: cur,
aux: aux,

View File

@ -761,6 +761,11 @@ func (m *Measurement) idsForExpr(n *influxql.BinaryExpr) (SeriesIDs, influxql.Ex
// the expression passed in, as the filter.
if name.Val != "_name" && m.hasField(name.Val) {
return m.seriesIDs, n, nil
} else if value, ok := value.(*influxql.VarRef); ok {
// Check if the RHS is a variable and if it is a field.
if value.Val != "_name" && m.hasField(value.Val) {
return m.seriesIDs, n, nil
}
}
// Retrieve list of series with this tag key.
@ -850,6 +855,26 @@ func (m *Measurement) idsForExpr(n *influxql.BinaryExpr) (SeriesIDs, influxql.Ex
return ids, &influxql.BooleanLiteral{Val: true}, nil
}
// compare tag values
if ref, ok := value.(*influxql.VarRef); ok {
var ids SeriesIDs
if n.Op == influxql.NEQ {
ids = m.seriesIDs
}
rhsTagVals := m.seriesByTagKeyValue[ref.Val]
for k := range tagVals {
tags := tagVals[k].Intersect(rhsTagVals[k])
if n.Op == influxql.EQ {
ids = ids.Union(tags)
} else if n.Op == influxql.NEQ {
ids = ids.Reject(tags)
}
}
return ids, &influxql.BooleanLiteral{Val: true}, nil
}
if n.Op == influxql.NEQ || n.Op == influxql.NEQREGEX {
return m.seriesIDs, &influxql.BooleanLiteral{Val: true}, nil
}