2018-05-15 20:11:32 +00:00
|
|
|
package query
|
|
|
|
|
|
|
|
import (
|
|
|
|
"io"
|
|
|
|
|
2018-06-26 23:28:56 +00:00
|
|
|
"github.com/influxdata/platform/query/iocounter"
|
2018-05-21 23:02:42 +00:00
|
|
|
"github.com/influxdata/platform/query/values"
|
2018-05-15 20:11:32 +00:00
|
|
|
)
|
|
|
|
|
2018-05-21 23:02:42 +00:00
|
|
|
type Result interface {
|
2018-05-24 17:29:36 +00:00
|
|
|
Name() string
|
2018-07-10 23:33:00 +00:00
|
|
|
// Tables returns a TableIterator for iterating through results
|
|
|
|
Tables() TableIterator
|
2018-05-21 23:02:42 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 23:33:00 +00:00
|
|
|
type TableIterator interface {
|
|
|
|
Do(f func(Table) error) error
|
2018-05-21 23:02:42 +00:00
|
|
|
}
|
|
|
|
|
2018-07-10 23:33:00 +00:00
|
|
|
type Table interface {
|
2018-07-10 23:02:37 +00:00
|
|
|
Key() GroupKey
|
2018-05-21 23:02:42 +00:00
|
|
|
|
|
|
|
Cols() []ColMeta
|
|
|
|
|
2018-07-10 23:33:00 +00:00
|
|
|
// Do calls f to process the data contained within the table.
|
2018-05-21 23:02:42 +00:00
|
|
|
// The function f will be called zero or more times.
|
|
|
|
Do(f func(ColReader) error) error
|
|
|
|
|
2018-07-10 23:33:00 +00:00
|
|
|
// RefCount modifies the reference count on the table by n.
|
|
|
|
// When the RefCount goes to zero, the table is freed.
|
2018-05-21 23:02:42 +00:00
|
|
|
RefCount(n int)
|
2018-05-24 16:11:25 +00:00
|
|
|
|
2018-07-10 23:33:00 +00:00
|
|
|
// Empty returns whether the table contains no records.
|
2018-05-24 16:11:25 +00:00
|
|
|
Empty() bool
|
2018-05-21 23:02:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type ColMeta struct {
|
|
|
|
Label string
|
|
|
|
Type DataType
|
|
|
|
}
|
|
|
|
|
|
|
|
type DataType int
|
|
|
|
|
|
|
|
const (
|
|
|
|
TInvalid DataType = iota
|
|
|
|
TBool
|
|
|
|
TInt
|
|
|
|
TUInt
|
|
|
|
TFloat
|
|
|
|
TString
|
|
|
|
TTime
|
|
|
|
)
|
|
|
|
|
|
|
|
func (t DataType) String() string {
|
|
|
|
switch t {
|
|
|
|
case TInvalid:
|
|
|
|
return "invalid"
|
|
|
|
case TBool:
|
|
|
|
return "bool"
|
|
|
|
case TInt:
|
|
|
|
return "int"
|
|
|
|
case TUInt:
|
|
|
|
return "uint"
|
|
|
|
case TFloat:
|
|
|
|
return "float"
|
|
|
|
case TString:
|
|
|
|
return "string"
|
|
|
|
case TTime:
|
|
|
|
return "time"
|
|
|
|
default:
|
|
|
|
return "unknown"
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// ColReader allows access to reading slices of column data.
|
|
|
|
// All data the ColReader exposes is guaranteed to be in memory.
|
|
|
|
// Once a ColReader goes out of scope all slices are considered invalid.
|
|
|
|
type ColReader interface {
|
2018-07-10 23:02:37 +00:00
|
|
|
Key() GroupKey
|
2018-05-21 23:02:42 +00:00
|
|
|
// Cols returns a list of column metadata.
|
|
|
|
Cols() []ColMeta
|
|
|
|
// Len returns the length of the slices.
|
|
|
|
// All slices will have the same length.
|
|
|
|
Len() int
|
|
|
|
Bools(j int) []bool
|
|
|
|
Ints(j int) []int64
|
|
|
|
UInts(j int) []uint64
|
|
|
|
Floats(j int) []float64
|
|
|
|
Strings(j int) []string
|
|
|
|
Times(j int) []values.Time
|
|
|
|
}
|
|
|
|
|
2018-07-10 23:02:37 +00:00
|
|
|
type GroupKey interface {
|
2018-05-21 23:02:42 +00:00
|
|
|
Cols() []ColMeta
|
|
|
|
|
|
|
|
HasCol(label string) bool
|
2018-07-25 22:26:50 +00:00
|
|
|
LabelValue(label string) values.Value
|
2018-05-21 23:02:42 +00:00
|
|
|
|
|
|
|
ValueBool(j int) bool
|
|
|
|
ValueUInt(j int) uint64
|
|
|
|
ValueInt(j int) int64
|
|
|
|
ValueFloat(j int) float64
|
|
|
|
ValueString(j int) string
|
|
|
|
ValueDuration(j int) values.Duration
|
|
|
|
ValueTime(j int) values.Time
|
2018-05-24 15:08:32 +00:00
|
|
|
Value(j int) values.Value
|
2018-05-21 23:02:42 +00:00
|
|
|
|
2018-07-10 23:02:37 +00:00
|
|
|
Equal(o GroupKey) bool
|
|
|
|
Less(o GroupKey) bool
|
2018-05-21 23:02:42 +00:00
|
|
|
String() string
|
|
|
|
}
|
|
|
|
|
2018-05-15 20:11:32 +00:00
|
|
|
// ResultDecoder can decode a result from a reader.
|
|
|
|
type ResultDecoder interface {
|
|
|
|
// Decode decodes data from r into a result.
|
2018-05-21 23:02:42 +00:00
|
|
|
Decode(r io.Reader) (Result, error)
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// ResultEncoder can encode a result into a writer.
|
|
|
|
type ResultEncoder interface {
|
|
|
|
// Encode encodes data from the result into w.
|
2018-06-26 23:28:56 +00:00
|
|
|
// Returns the number of bytes written to w and any error.
|
|
|
|
Encode(w io.Writer, result Result) (int64, error)
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MultiResultDecoder can decode multiple results from a reader.
|
|
|
|
type MultiResultDecoder interface {
|
|
|
|
// Decode decodes multiple results from r.
|
2018-05-25 20:03:52 +00:00
|
|
|
Decode(r io.ReadCloser) (ResultIterator, error)
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// MultiResultEncoder can encode multiple results into a writer.
|
|
|
|
type MultiResultEncoder interface {
|
|
|
|
// Encode writes multiple results from r into w.
|
2018-08-16 19:01:20 +00:00
|
|
|
// Returns the number of bytes written to w and any error resulting from the encoding process.
|
|
|
|
// Errors obtained from the results object should be encoded to w and then discarded.
|
2018-06-26 23:28:56 +00:00
|
|
|
Encode(w io.Writer, results ResultIterator) (int64, error)
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
|
2018-08-16 19:01:20 +00:00
|
|
|
type EncoderError struct {
|
|
|
|
msg string
|
|
|
|
}
|
|
|
|
|
|
|
|
func (err *EncoderError) Error() string {
|
|
|
|
return err.msg
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewEncoderError(msg string) *EncoderError {
|
|
|
|
return &EncoderError{
|
|
|
|
msg: msg,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-05-15 20:11:32 +00:00
|
|
|
// DelimitedMultiResultEncoder encodes multiple results using a trailing delimiter.
|
|
|
|
// The delimiter is written after every result.
|
2018-05-24 17:29:36 +00:00
|
|
|
//
|
2018-08-16 19:01:20 +00:00
|
|
|
// If an error is encountered when iterating and the error is of type
|
|
|
|
// EncoderError, the error will be returned. Otherwise, the error is assumed
|
|
|
|
// have arisen from query execution, and said error will be encoded with the
|
|
|
|
// EncodeError method of the Encoder field.
|
2018-05-24 17:29:36 +00:00
|
|
|
//
|
2018-05-15 20:11:32 +00:00
|
|
|
// If the io.Writer implements flusher, it will be flushed after each delimiter.
|
|
|
|
type DelimitedMultiResultEncoder struct {
|
|
|
|
Delimiter []byte
|
2018-05-24 17:29:36 +00:00
|
|
|
Encoder interface {
|
|
|
|
ResultEncoder
|
|
|
|
// EncodeError encodes an error on the writer.
|
|
|
|
EncodeError(w io.Writer, err error) error
|
|
|
|
}
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type flusher interface {
|
|
|
|
Flush()
|
|
|
|
}
|
|
|
|
|
2018-06-26 23:28:56 +00:00
|
|
|
func (e *DelimitedMultiResultEncoder) Encode(w io.Writer, results ResultIterator) (int64, error) {
|
|
|
|
wc := &iocounter.Writer{Writer: w}
|
2018-08-16 19:01:20 +00:00
|
|
|
|
2018-05-15 20:11:32 +00:00
|
|
|
for results.More() {
|
2018-05-24 17:29:36 +00:00
|
|
|
result := results.Next()
|
2018-06-26 23:28:56 +00:00
|
|
|
if _, err := e.Encoder.Encode(wc, result); err != nil {
|
2018-08-16 19:01:20 +00:00
|
|
|
// If we have an error that's from
|
|
|
|
// encoding specifically, return it
|
|
|
|
if _, ok := err.(*EncoderError); ok {
|
|
|
|
return wc.Count(), err
|
|
|
|
}
|
|
|
|
// Otherwise, the error is from query execution,
|
|
|
|
// so we encode it instead.
|
2018-08-16 21:23:17 +00:00
|
|
|
err := e.Encoder.EncodeError(wc, err)
|
|
|
|
return wc.Count(), err
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
2018-06-26 23:28:56 +00:00
|
|
|
if _, err := wc.Write(e.Delimiter); err != nil {
|
|
|
|
return wc.Count(), err
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|
|
|
|
// Flush the writer after each result
|
|
|
|
if f, ok := w.(flusher); ok {
|
|
|
|
f.Flush()
|
|
|
|
}
|
|
|
|
}
|
2018-08-16 19:01:20 +00:00
|
|
|
// If we have any outlying errors in results, encode them
|
2018-05-24 17:29:36 +00:00
|
|
|
err := results.Err()
|
|
|
|
if err != nil {
|
2018-06-26 23:28:56 +00:00
|
|
|
err := e.Encoder.EncodeError(wc, err)
|
|
|
|
return wc.Count(), err
|
2018-05-24 17:29:36 +00:00
|
|
|
}
|
2018-06-26 23:28:56 +00:00
|
|
|
return wc.Count(), nil
|
2018-05-15 20:11:32 +00:00
|
|
|
}
|