// createVarRefSeriesIterator creates an iterator for a variable reference for a series. func (e *Engine) createVarRefSeriesIterator(ref *influxql.VarRef, mm *tsdb.Measurement, seriesKey string, t *influxql.TagSet, filter influxql.Expr, conditionFields []influxql.VarRef, opt influxql.IteratorOptions) (influxql.Iterator, error) { tags := influxql.NewTags(e.index.TagsForSeries(seriesKey).Map()) // Create options specific for this series. itrOpt := opt itrOpt.Condition = filter // Build auxilary cursors. // Tag values should be returned if the field doesn't exist. var aux []cursorAt if len(opt.Aux) > 0 { aux = make([]cursorAt, len(opt.Aux)) for i, ref := range opt.Aux { // Create cursor from field if a tag wasn't requested. if ref.Type != influxql.Tag { cur := e.buildCursor(mm.Name, seriesKey, &ref, opt) if cur != nil { aux[i] = newBufCursor(cur, opt.Ascending) continue } // If a field was requested, use a nil cursor of the requested type. switch ref.Type { case influxql.Float, influxql.AnyField: aux[i] = &floatNilLiteralCursor{} continue case influxql.Integer: aux[i] = &integerNilLiteralCursor{} continue case influxql.String: aux[i] = &stringNilLiteralCursor{} continue case influxql.Boolean: aux[i] = &booleanNilLiteralCursor{} continue } } // If field doesn't exist, use the tag value. if v := tags.Value(ref.Val); v == "" { // However, if the tag value is blank then return a null. aux[i] = &stringNilLiteralCursor{} } else { aux[i] = &stringLiteralCursor{value: v} } } } // Build conditional field cursors. // If a conditional field doesn't exist then ignore the series. var conds []cursorAt if len(conditionFields) > 0 { conds = make([]cursorAt, len(conditionFields)) for i, ref := range conditionFields { // Create cursor from field if a tag wasn't requested. if ref.Type != influxql.Tag { cur := e.buildCursor(mm.Name, seriesKey, &ref, opt) if cur != nil { conds[i] = newBufCursor(cur, opt.Ascending) continue } // If a field was requested, use a nil cursor of the requested type. switch ref.Type { case influxql.Float, influxql.AnyField: conds[i] = &floatNilLiteralCursor{} continue case influxql.Integer: conds[i] = &integerNilLiteralCursor{} continue case influxql.String: conds[i] = &stringNilLiteralCursor{} continue case influxql.Boolean: conds[i] = &booleanNilLiteralCursor{} continue } } // If field doesn't exist, use the tag value. if v := tags.Value(ref.Val); v == "" { // However, if the tag value is blank then return a null. conds[i] = &stringNilLiteralCursor{} } else { conds[i] = &stringLiteralCursor{value: v} } } } condNames := influxql.VarRefs(conditionFields).Strings() // Limit tags to only the dimensions selected. tags = tags.Subset(opt.Dimensions) // If it's only auxiliary fields then it doesn't matter what type of iterator we use. if ref == nil { return newFloatIterator(mm.Name, tags, itrOpt, nil, aux, conds, condNames), nil } // Build main cursor. cur := e.buildCursor(mm.Name, seriesKey, ref, opt) // If the field doesn't exist then don't build an iterator. if cur == nil { return nil, nil } switch cur := cur.(type) { case floatCursor: return newFloatIterator(mm.Name, tags, itrOpt, cur, aux, conds, condNames), nil case integerCursor: return newIntegerIterator(mm.Name, tags, itrOpt, cur, aux, conds, condNames), nil case stringCursor: return newStringIterator(mm.Name, tags, itrOpt, cur, aux, conds, condNames), nil case booleanCursor: return newBooleanIterator(mm.Name, tags, itrOpt, cur, aux, conds, condNames), nil default: panic("unreachable") } }
// NewTagValuesIterator returns a new instance of TagValuesIterator. func NewTagValuesIterator(sh *Shard, opt influxql.IteratorOptions) (influxql.Iterator, error) { if opt.Condition == nil { return nil, errors.New("a condition is required") } measurementExpr := influxql.CloneExpr(opt.Condition) measurementExpr = influxql.Reduce(influxql.RewriteExpr(measurementExpr, func(e influxql.Expr) influxql.Expr { switch e := e.(type) { case *influxql.BinaryExpr: switch e.Op { case influxql.EQ, influxql.NEQ, influxql.EQREGEX, influxql.NEQREGEX: tag, ok := e.LHS.(*influxql.VarRef) if !ok || tag.Val != "_name" { return nil } } } return e }), nil) mms, ok, err := sh.index.measurementsByExpr(measurementExpr) if err != nil { return nil, err } else if !ok { mms = sh.index.Measurements() sort.Sort(mms) } // If there are no measurements, return immediately. if len(mms) == 0 { return &tagValuesIterator{}, nil } filterExpr := influxql.CloneExpr(opt.Condition) filterExpr = influxql.Reduce(influxql.RewriteExpr(filterExpr, func(e influxql.Expr) influxql.Expr { switch e := e.(type) { case *influxql.BinaryExpr: switch e.Op { case influxql.EQ, influxql.NEQ, influxql.EQREGEX, influxql.NEQREGEX: tag, ok := e.LHS.(*influxql.VarRef) if !ok || strings.HasPrefix(tag.Val, "_") { return nil } } } return e }), nil) var series []*Series keys := newStringSet() for _, mm := range mms { ss, ok, err := mm.TagKeysByExpr(opt.Condition) if err != nil { return nil, err } else if !ok { keys.add(mm.TagKeys()...) } else { keys = keys.union(ss) } ids, err := mm.seriesIDsAllOrByExpr(filterExpr) if err != nil { return nil, err } for _, id := range ids { series = append(series, mm.SeriesByID(id)) } } return &tagValuesIterator{ series: series, keys: keys.list(), fields: influxql.VarRefs(opt.Aux).Strings(), }, nil }