github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/cursor.go (about)

     1  package query
     2  
     3  import (
     4  	"math"
     5  	"time"
     6  
     7  	"github.com/influxdata/influxql"
     8  )
     9  
    10  var NullFloat interface{} = (*float64)(nil)
    11  
    12  // Series represents the metadata about a series.
    13  type Series struct {
    14  	// Name is the measurement name.
    15  	Name string
    16  
    17  	// Tags for the series.
    18  	Tags Tags
    19  
    20  	// This is an internal id used to easily compare if a series is the
    21  	// same as another series. Whenever the internal cursor changes
    22  	// to a new series, this id gets incremented. It is not exposed to
    23  	// the user so we can implement this in whatever way we want.
    24  	// If a series is not generated by a cursor, this id is zero and
    25  	// it will instead attempt to compare the name and tags.
    26  	id uint64
    27  }
    28  
    29  // SameSeries checks if this is the same series as another one.
    30  // It does not necessarily check for equality so this is different from
    31  // checking to see if the name and tags are the same. It checks whether
    32  // the two are part of the same series in the response.
    33  func (s Series) SameSeries(other Series) bool {
    34  	if s.id != 0 && other.id != 0 {
    35  		return s.id == other.id
    36  	}
    37  	return s.Name == other.Name && s.Tags.ID() == other.Tags.ID()
    38  }
    39  
    40  // Equal checks to see if the Series are identical.
    41  func (s Series) Equal(other Series) bool {
    42  	if s.id != 0 && other.id != 0 {
    43  		// If the ids are the same, then we can short-circuit and assume they
    44  		// are the same. If they are not the same, do the long check since
    45  		// they may still be identical, but not necessarily generated from
    46  		// the same cursor.
    47  		if s.id == other.id {
    48  			return true
    49  		}
    50  	}
    51  	return s.Name == other.Name && s.Tags.ID() == other.Tags.ID()
    52  }
    53  
    54  // Row represents a single row returned by the query engine.
    55  type Row struct {
    56  	// Time returns the time for this row. If the cursor was created to
    57  	// return time as one of the values, the time will also be included as
    58  	// a time.Time in the appropriate column within Values.
    59  	// This ensures that time is always present in the Row structure
    60  	// even if it hasn't been requested in the output.
    61  	Time int64
    62  
    63  	// Series contains the series metadata for this row.
    64  	Series Series
    65  
    66  	// Values contains the values within the current row.
    67  	Values []interface{}
    68  }
    69  
    70  type Cursor interface {
    71  	// Scan will retrieve the next row and assign the result to
    72  	// the passed in Row. If the Row has not been initialized, the Cursor
    73  	// will initialize the Row.
    74  	// To increase speed and memory usage, the same Row can be used and
    75  	// the previous values will be overwritten while using the same memory.
    76  	Scan(row *Row) bool
    77  
    78  	// Stats returns the IteratorStats from the underlying iterators.
    79  	Stats() IteratorStats
    80  
    81  	// Err returns any errors that were encountered from scanning the rows.
    82  	Err() error
    83  
    84  	// Columns returns the column names and types.
    85  	Columns() []influxql.VarRef
    86  
    87  	// Close closes the underlying resources that the cursor is using.
    88  	Close() error
    89  }
    90  
    91  // RowCursor returns a Cursor that iterates over Rows.
    92  func RowCursor(rows []Row, columns []influxql.VarRef) Cursor {
    93  	return &rowCursor{
    94  		rows:    rows,
    95  		columns: columns,
    96  	}
    97  }
    98  
    99  type rowCursor struct {
   100  	rows    []Row
   101  	columns []influxql.VarRef
   102  
   103  	series Series
   104  }
   105  
   106  func (cur *rowCursor) Scan(row *Row) bool {
   107  	if len(cur.rows) == 0 {
   108  		return false
   109  	}
   110  
   111  	*row = cur.rows[0]
   112  	if row.Series.Name != cur.series.Name || !row.Series.Tags.Equals(&cur.series.Tags) {
   113  		cur.series.Name = row.Series.Name
   114  		cur.series.Tags = row.Series.Tags
   115  		cur.series.id++
   116  	}
   117  	cur.rows = cur.rows[1:]
   118  	return true
   119  }
   120  
   121  func (cur *rowCursor) Stats() IteratorStats {
   122  	return IteratorStats{}
   123  }
   124  
   125  func (cur *rowCursor) Err() error {
   126  	return nil
   127  }
   128  
   129  func (cur *rowCursor) Columns() []influxql.VarRef {
   130  	return cur.columns
   131  }
   132  
   133  func (cur *rowCursor) Close() error {
   134  	return nil
   135  }
   136  
   137  type scannerFunc func(m map[string]interface{}) (int64, string, Tags)
   138  
   139  type scannerCursorBase struct {
   140  	fields []influxql.Expr
   141  	m      map[string]interface{}
   142  
   143  	series  Series
   144  	columns []influxql.VarRef
   145  	loc     *time.Location
   146  
   147  	scan   scannerFunc
   148  	valuer influxql.ValuerEval
   149  }
   150  
   151  func newScannerCursorBase(scan scannerFunc, fields []*influxql.Field, loc *time.Location) scannerCursorBase {
   152  	typmap := FunctionTypeMapper{}
   153  	exprs := make([]influxql.Expr, len(fields))
   154  	columns := make([]influxql.VarRef, len(fields))
   155  	for i, f := range fields {
   156  		exprs[i] = f.Expr
   157  		columns[i] = influxql.VarRef{
   158  			Val:  f.Name(),
   159  			Type: influxql.EvalType(f.Expr, nil, typmap),
   160  		}
   161  	}
   162  	if loc == nil {
   163  		loc = time.UTC
   164  	}
   165  
   166  	m := make(map[string]interface{})
   167  	return scannerCursorBase{
   168  		fields:  exprs,
   169  		m:       m,
   170  		columns: columns,
   171  		loc:     loc,
   172  		scan:    scan,
   173  		valuer: influxql.ValuerEval{
   174  			Valuer: influxql.MultiValuer(
   175  				MathValuer{},
   176  				influxql.MapValuer(m),
   177  			),
   178  			IntegerFloatDivision: true,
   179  		},
   180  	}
   181  }
   182  
   183  func (cur *scannerCursorBase) Scan(row *Row) bool {
   184  	ts, name, tags := cur.scan(cur.m)
   185  	if ts == ZeroTime {
   186  		return false
   187  	}
   188  
   189  	row.Time = ts
   190  	if name != cur.series.Name || tags.ID() != cur.series.Tags.ID() {
   191  		cur.series.Name = name
   192  		cur.series.Tags = tags
   193  		cur.series.id++
   194  	}
   195  	row.Series = cur.series
   196  
   197  	if len(cur.columns) > len(row.Values) {
   198  		row.Values = make([]interface{}, len(cur.columns))
   199  	}
   200  
   201  	for i, expr := range cur.fields {
   202  		// A special case if the field is time to reduce memory allocations.
   203  		if ref, ok := expr.(*influxql.VarRef); ok && ref.Val == "time" {
   204  			row.Values[i] = time.Unix(0, row.Time).In(cur.loc)
   205  			continue
   206  		}
   207  		v := cur.valuer.Eval(expr)
   208  		if fv, ok := v.(float64); ok && math.IsNaN(fv) {
   209  			// If the float value is NaN, convert it to a null float
   210  			// so this can be serialized correctly, but not mistaken for
   211  			// a null value that needs to be filled.
   212  			v = NullFloat
   213  		}
   214  		row.Values[i] = v
   215  	}
   216  	return true
   217  }
   218  
   219  func (cur *scannerCursorBase) Columns() []influxql.VarRef {
   220  	return cur.columns
   221  }
   222  
   223  func (cur *scannerCursorBase) clear(m map[string]interface{}) {
   224  	for k := range m {
   225  		delete(m, k)
   226  	}
   227  }
   228  
   229  var _ Cursor = (*scannerCursor)(nil)
   230  
   231  type scannerCursor struct {
   232  	scanner IteratorScanner
   233  	scannerCursorBase
   234  }
   235  
   236  func newScannerCursor(s IteratorScanner, fields []*influxql.Field, opt IteratorOptions) *scannerCursor {
   237  	cur := &scannerCursor{scanner: s}
   238  	cur.scannerCursorBase = newScannerCursorBase(cur.scan, fields, opt.Location)
   239  	return cur
   240  }
   241  
   242  func (s *scannerCursor) scan(m map[string]interface{}) (int64, string, Tags) {
   243  	ts, name, tags := s.scanner.Peek()
   244  	// if a new series, clear the map of previous values
   245  	if name != s.series.Name || tags.ID() != s.series.Tags.ID() {
   246  		s.clear(m)
   247  	}
   248  	if ts == ZeroTime {
   249  		return ts, name, tags
   250  	}
   251  	s.scanner.ScanAt(ts, name, tags, m)
   252  	return ts, name, tags
   253  }
   254  
   255  func (cur *scannerCursor) Stats() IteratorStats {
   256  	return cur.scanner.Stats()
   257  }
   258  
   259  func (cur *scannerCursor) Err() error {
   260  	return cur.scanner.Err()
   261  }
   262  
   263  func (cur *scannerCursor) Close() error {
   264  	return cur.scanner.Close()
   265  }
   266  
   267  var _ Cursor = (*multiScannerCursor)(nil)
   268  
   269  type multiScannerCursor struct {
   270  	scanners  []IteratorScanner
   271  	err       error
   272  	ascending bool
   273  	scannerCursorBase
   274  }
   275  
   276  func newMultiScannerCursor(scanners []IteratorScanner, fields []*influxql.Field, opt IteratorOptions) *multiScannerCursor {
   277  	cur := &multiScannerCursor{
   278  		scanners:  scanners,
   279  		ascending: opt.Ascending,
   280  	}
   281  	cur.scannerCursorBase = newScannerCursorBase(cur.scan, fields, opt.Location)
   282  	return cur
   283  }
   284  
   285  func (cur *multiScannerCursor) scan(m map[string]interface{}) (ts int64, name string, tags Tags) {
   286  	ts = ZeroTime
   287  	for _, s := range cur.scanners {
   288  		curTime, curName, curTags := s.Peek()
   289  		if curTime == ZeroTime {
   290  			if err := s.Err(); err != nil {
   291  				cur.err = err
   292  				return ZeroTime, "", Tags{}
   293  			}
   294  			continue
   295  		}
   296  
   297  		if ts == ZeroTime {
   298  			ts, name, tags = curTime, curName, curTags
   299  			continue
   300  		}
   301  
   302  		if cur.ascending {
   303  			if (curName < name) || (curName == name && curTags.ID() < tags.ID()) || (curName == name && curTags.ID() == tags.ID() && curTime < ts) {
   304  				ts, name, tags = curTime, curName, curTags
   305  			}
   306  			continue
   307  		}
   308  
   309  		if (curName > name) || (curName == name && curTags.ID() > tags.ID()) || (curName == name && curTags.ID() == tags.ID() && curTime > ts) {
   310  			ts, name, tags = curTime, curName, curTags
   311  		}
   312  	}
   313  
   314  	if ts == ZeroTime {
   315  		return ts, name, tags
   316  	}
   317  	// if a new series, clear the map of previous values
   318  	if name != cur.series.Name || tags.ID() != cur.series.Tags.ID() {
   319  		cur.clear(m)
   320  	}
   321  	for _, s := range cur.scanners {
   322  		s.ScanAt(ts, name, tags, m)
   323  	}
   324  	return ts, name, tags
   325  }
   326  
   327  func (cur *multiScannerCursor) Stats() IteratorStats {
   328  	var stats IteratorStats
   329  	for _, s := range cur.scanners {
   330  		stats.Add(s.Stats())
   331  	}
   332  	return stats
   333  }
   334  
   335  func (cur *multiScannerCursor) Err() error {
   336  	return cur.err
   337  }
   338  
   339  func (cur *multiScannerCursor) Close() error {
   340  	var err error
   341  	for _, s := range cur.scanners {
   342  		if e := s.Close(); e != nil && err == nil {
   343  			err = e
   344  		}
   345  	}
   346  	return err
   347  }
   348  
   349  type filterCursor struct {
   350  	Cursor
   351  	// fields holds the mapping of field names to the index in the row
   352  	// based off of the column metadata. This only contains the fields
   353  	// we need and will exclude the ones we do not.
   354  	fields map[string]IteratorMap
   355  	filter influxql.Expr
   356  	m      map[string]interface{}
   357  	valuer influxql.ValuerEval
   358  }
   359  
   360  func newFilterCursor(cur Cursor, filter influxql.Expr) *filterCursor {
   361  	fields := make(map[string]IteratorMap)
   362  	for _, name := range influxql.ExprNames(filter) {
   363  		for i, col := range cur.Columns() {
   364  			if name.Val == col.Val {
   365  				fields[name.Val] = FieldMap{
   366  					Index: i,
   367  					Type:  name.Type,
   368  				}
   369  				break
   370  			}
   371  		}
   372  
   373  		// If the field is not a column, assume it is a tag value.
   374  		// We do not know what the tag values will be, but there really
   375  		// isn't any different between NullMap and a TagMap that's pointed
   376  		// at the wrong location for the purposes described here.
   377  		if _, ok := fields[name.Val]; !ok {
   378  			fields[name.Val] = TagMap(name.Val)
   379  		}
   380  	}
   381  	m := make(map[string]interface{})
   382  	return &filterCursor{
   383  		Cursor: cur,
   384  		fields: fields,
   385  		filter: filter,
   386  		m:      m,
   387  		valuer: influxql.ValuerEval{Valuer: influxql.MapValuer(m)},
   388  	}
   389  }
   390  
   391  func (cur *filterCursor) Scan(row *Row) bool {
   392  	for cur.Cursor.Scan(row) {
   393  		// Use the field mappings to prepare the map for the valuer.
   394  		for name, f := range cur.fields {
   395  			cur.m[name] = f.Value(row)
   396  		}
   397  
   398  		if cur.valuer.EvalBool(cur.filter) {
   399  			// Passes the filter! Return true. We no longer need to
   400  			// search for a suitable value.
   401  			return true
   402  		}
   403  	}
   404  	return false
   405  }
   406  
   407  type nullCursor struct {
   408  	columns []influxql.VarRef
   409  }
   410  
   411  func newNullCursor(fields []*influxql.Field) *nullCursor {
   412  	columns := make([]influxql.VarRef, len(fields))
   413  	for i, f := range fields {
   414  		columns[i].Val = f.Name()
   415  	}
   416  	return &nullCursor{columns: columns}
   417  }
   418  
   419  func (cur *nullCursor) Scan(row *Row) bool {
   420  	return false
   421  }
   422  
   423  func (cur *nullCursor) Stats() IteratorStats {
   424  	return IteratorStats{}
   425  }
   426  
   427  func (cur *nullCursor) Err() error {
   428  	return nil
   429  }
   430  
   431  func (cur *nullCursor) Columns() []influxql.VarRef {
   432  	return cur.columns
   433  }
   434  
   435  func (cur *nullCursor) Close() error {
   436  	return nil
   437  }
   438  
   439  // DrainCursor will read and discard all values from a Cursor and return the error
   440  // if one happens.
   441  func DrainCursor(cur Cursor) error {
   442  	var row Row
   443  	for cur.Scan(&row) {
   444  		// Do nothing with the result.
   445  	}
   446  	return cur.Err()
   447  }