func NewCountAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function count() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function count() doesn't work with wildcards") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } if v.Elems[0].Type != parser.ValueSimpleName { innerName := strings.ToLower(v.Elems[0].Name) init := registeredAggregators[innerName] if init == nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", innerName)) } inner, err := init(q, v.Elems[0], defaultValue) if err != nil { return nil, err } return NewCompositeAggregator(&CountAggregator{AbstractAggregator{}, wrappedDefaultValue, v.Alias}, inner) } return &CountAggregator{AbstractAggregator{}, wrappedDefaultValue, v.Alias}, nil }
func NewTopOrBottomAggregator(name string, v *parser.Value, isTop bool, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, fmt.Sprintf("function %s() requires at exactly 2 arguments", name)) } if v.Elems[1].Type != parser.ValueInt { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("function %s() second parameter expect int", name)) } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } limit, err := strconv.ParseInt(v.Elems[1].Name, 10, 64) if err != nil { return nil, err } return &TopOrBottomAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, name: name, isTop: isTop, defaultValue: wrappedDefaultValue, alias: v.Alias, limit: limit}, nil }
func NewPercentileAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function percentile() requires exactly two arguments") } percentile, err := strconv.ParseFloat(value.Elems[1].Name, 64) if err != nil || percentile <= 0 || percentile >= 100 { return nil, common.NewQueryError(common.InvalidArgument, "function percentile() requires a numeric second argument between 0 and 100") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &PercentileAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, functionName: "percentile", percentile: percentile, float_values: make(map[string]map[interface{}][]float64), defaultValue: wrappedDefaultValue, }, nil }
func NewPercentileAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function percentile() requires exactly two arguments") } if value.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.WrongNumberOfArguments, "wildcard cannot be used with percentile") } percentile, err := strconv.ParseFloat(value.Elems[1].Name, 64) if err != nil || percentile <= 0 || percentile >= 100 { return nil, common.NewQueryError(common.InvalidArgument, "function percentile() requires a numeric second argument between 0 and 100") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } functionName := "percentile" if value.Alias != "" { functionName = value.Alias } return &PercentileAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, functionName: functionName, percentile: percentile, defaultValue: wrappedDefaultValue, }, nil }
func NewStandardDeviationAggregator(q *parser.Query, v *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function stddev() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function stddev() doesn't work with wildcards") } return &StandardDeviationAggregator{ fieldName: v.Elems[0].Name, running: make(map[string]map[interface{}]*StandardDeviationRunning), }, nil }
func NewDerivativeAggregator(q *parser.Query, v *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function derivative() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function derivative() doesn't work with wildcards") } return &DerivativeAggregator{ fieldName: v.Elems[0].Name, lastValues: make(map[string]map[interface{}]*protocol.Point), points: make(map[string]map[interface{}][]*protocol.FieldValue), }, nil }
func (self *QueryEngine) executeCountQueryWithGroupBy(query *parser.SelectQuery, yield func(*protocol.Series) error) error { self.aggregateYield = yield duration, err := query.GetGroupByClause().GetGroupByTime() if err != nil { return err } self.isAggregateQuery = true self.duration = duration self.aggregators = []Aggregator{} for _, value := range query.GetColumnNames() { if !value.IsFunctionCall() { continue } lowerCaseName := strings.ToLower(value.Name) initializer := registeredAggregators[lowerCaseName] if initializer == nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", value.Name)) } aggregator, err := initializer(query, value, query.GetGroupByClause().FillValue) if err != nil { return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("%s", err)) } self.aggregators = append(self.aggregators, aggregator) } for _, elem := range query.GetGroupByClause().Elems { if elem.IsFunctionCall() { continue } self.elems = append(self.elems, elem) } self.fillWithZero = query.GetGroupByClause().FillWithZero self.initializeFields() err = self.distributeQuery(query, func(series *protocol.Series) error { if len(series.Points) == 0 { return nil } return self.aggregateValuesForSeries(series) }) return err }
func NewMedianAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function median() requires exactly one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } functionName := "median" if value.Alias != "" { functionName = value.Alias } aggregator := &PercentileAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, functionName: functionName, percentile: 50.0, defaultValue: wrappedDefaultValue, alias: value.Alias, } return aggregator, nil }
func NewCumulativeArithmeticAggregator(name string, value *parser.Value, initialValue float64, defaultValue *parser.Value, operation Operation) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function max() requires only one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } if value.Alias != "" { name = value.Alias } return &CumulativeArithmeticAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, name: name, values: make(map[string]map[interface{}]float64), operation: operation, initialValue: initialValue, defaultValue: wrappedDefaultValue, }, nil }
func (self *QueryEngine) RunQuery(user common.User, database string, query string, yield func(*protocol.Series) error) (err error) { // don't let a panic pass beyond RunQuery defer func() { if err := recover(); err != nil { fmt.Fprintf(os.Stderr, "********************************BUG********************************\n") buf := make([]byte, 1024) n := runtime.Stack(buf, false) fmt.Fprintf(os.Stderr, "Database: %s\n", database) fmt.Fprintf(os.Stderr, "Query: [%s]\n", query) fmt.Fprintf(os.Stderr, "Error: %s. Stacktrace: %s\n", err, string(buf[:n])) err = common.NewQueryError(common.InternalError, "Internal Error") } }() q, err := parser.ParseQuery(query) if err != nil { return err } if isAggregateQuery(q) { return self.executeCountQueryWithGroupBy(user, database, q, yield) } else { return self.distributeQuery(user, database, q, yield) } return nil }
func NewModeAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() requires at least one argument") } // TODO: Mode can in fact take two argument, the second specifies // the "size", but it's not clear if size is set to 2 whether to // return at least 2 elements, or return the most common values and // the second most common values. The difference will be apparent if // the data set is multimodel and there are two most common // values. In the first case, the two most common values will be // returned, but in the second case the two most common values and // the second most common values will be returned if len(value.Elems) > 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() takes at most one arguments") } size := 1 if len(value.Elems) == 2 { switch value.Elems[1].Type { case parser.ValueInt: var err error size, err = strconv.Atoi(value.Elems[1].Name) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into an int", value.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a int", value.Elems[1].Name) } } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &ModeAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, defaultValue: wrappedDefaultValue, alias: value.Alias, size: size, }, nil }
func HashPassword(password string) ([]byte, error) { if length := len(password); length < 4 || length > 56 { return nil, common.NewQueryError(common.InvalidArgument, "Password must be more than 4 and less than 56 characters") } // The second arg is the cost of the hashing, higher is slower but makes it harder // to brute force, since it will be really slow and impractical return bcrypt.GenerateFromPassword([]byte(password), 10) }
func NewModeAggregator(_ *parser.Query, value *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() requires exactly one argument") } return &ModeAggregator{ fieldName: value.Elems[0].Name, counts: make(map[string]map[interface{}]map[float64]int), }, nil }
func (self *CumulativeArithmeticAggregator) InitializeFieldsMetadata(series *protocol.Series) error { for idx, field := range series.Fields { if field == self.fieldName { self.fieldIndex = idx return nil } } return common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown column name %s", self.fieldName)) }
func NewHistogramAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() requires at least one arguments") } if len(v.Elems) > 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() takes at most two arguments") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function histogram() doesn't work with wildcards") } bucketSize := 1.0 if len(v.Elems) == 2 { switch v.Elems[1].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketSize, err = strconv.ParseFloat(v.Elems[1].Name, 64) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } } columnNames := []string{"bucket_start", "count"} if v.Alias != "" { columnNames[0] = fmt.Sprintf("%s_bucket_start", v.Alias) columnNames[1] = fmt.Sprintf("%s_count", v.Alias) } return &HistogramAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, bucketSize: bucketSize, histograms: make(map[string]map[interface{}]map[int]int), columnNames: columnNames, }, nil }
func (self GroupByClause) GetGroupByTime() (*time.Duration, error) { for _, groupBy := range self { if groupBy.IsFunctionCall() { // TODO: check the number of arguments and return an error if len(groupBy.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "time function only accepts one argument") } // TODO: check the function name // TODO: error checking arg := groupBy.Elems[0].Name duration, err := time.ParseDuration(arg) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("invalid argument %s to the time function", arg)) } return &duration, nil } } return nil, nil }
func recoverFunc(database, query string) { if err := recover(); err != nil { fmt.Fprintf(os.Stderr, "********************************BUG********************************\n") buf := make([]byte, 1024) n := runtime.Stack(buf, false) fmt.Fprintf(os.Stderr, "Database: %s\n", database) fmt.Fprintf(os.Stderr, "Query: [%s]\n", query) fmt.Fprintf(os.Stderr, "Error: %s. Stacktrace: %s\n", err, string(buf[:n])) err = common.NewQueryError(common.InternalError, "Internal Error") } }
func NewMedianAggregator(_ *parser.Query, value *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function median() requires exactly one argument") } return &PercentileAggregator{ functionName: "median", fieldName: value.Elems[0].Name, percentile: 50.0, float_values: make(map[string]map[interface{}][]float64), }, nil }
func (self *CoordinatorImpl) readFromResposneChannels(processor cluster.QueryProcessor, writer SeriesWriter, isExplainQuery bool, errors chan<- error, channels <-chan (<-chan *protocol.Response)) { defer close(errors) for responseChan := range channels { for response := range responseChan { //log.Debug("GOT RESPONSE: ", response.Type, response.Series) log.Debug("GOT RESPONSE: ", response.Type) if *response.Type == endStreamResponse || *response.Type == accessDeniedResponse { if response.ErrorMessage == nil { break } err := common.NewQueryError(common.InvalidArgument, *response.ErrorMessage) log.Error("Error while executing query: %s", err) errors <- err return } if response.Series == nil || len(response.Series.Points) == 0 { log.Debug("Series has no points, continue") continue } // if we don't have a processor, yield the point to the writer // this happens if shard took care of the query // otherwise client will get points from passthrough engine if processor != nil { // if the data wasn't aggregated at the shard level, aggregate // the data here log.Debug("YIELDING: %d points with %d columns", len(response.Series.Points), len(response.Series.Fields)) processor.YieldSeries(response.Series) continue } // If we have EXPLAIN query, we don't write actual points (of // response.Type Query) to the client if !(*response.Type == queryResponse && isExplainQuery) { writer.Write(response.Series) } } // once we're done with a response channel signal queryShards to // start querying a new shard errors <- nil } return }
func NewStandardDeviationAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function stddev() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function stddev() doesn't work with wildcards") } value, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &StandardDeviationAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, defaultValue: value, alias: v.Alias, }, nil }
func (self *CoordinatorImpl) runQuerySpec(querySpec *parser.QuerySpec, seriesWriter SeriesWriter) error { shards, processor, seriesClosed, err := self.getShardsAndProcessor(querySpec, seriesWriter) if err != nil { return err } defer func() { if processor != nil { processor.Close() <-seriesClosed } else { seriesWriter.Close() } }() shardConcurrentLimit := self.config.ConcurrentShardQueryLimit if self.shouldQuerySequentially(shards, querySpec) { log.Debug("Querying shards sequentially") shardConcurrentLimit = 1 } log.Debug("Shard concurrent limit: ", shardConcurrentLimit) errors := make(chan error, shardConcurrentLimit) for i := 0; i < shardConcurrentLimit; i++ { errors <- nil } responseChannels := make(chan (<-chan *protocol.Response), shardConcurrentLimit) go self.readFromResposneChannels(processor, seriesWriter, querySpec.IsExplainQuery(), errors, responseChannels) err = self.queryShards(querySpec, shards, errors, responseChannels) // make sure we read the rest of the errors and responses for _err := range errors { if err == nil { err = _err } } for responsechan := range responseChannels { for response := range responsechan { if response.GetType() != endStreamResponse { continue } if response.ErrorMessage != nil && err == nil { err = common.NewQueryError(common.InvalidArgument, *response.ErrorMessage) } break } } return err }
func (self GroupByClause) GetGroupByTime() (*time.Duration, error) { for _, groupBy := range self.Elems { if groupBy.IsFunctionCall() && strings.ToLower(groupBy.Name) == "time" { // TODO: check the number of arguments and return an error if len(groupBy.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "time function only accepts one argument") } if groupBy.Elems[0].Type != ValueDuration { log.Debug("Get a time function without a duration argument %v", groupBy.Elems[0].Type) } arg := groupBy.Elems[0].Name durationInt, err := common.ParseTimeDuration(arg) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("invalid argument %s to the time function", arg)) } duration := time.Duration(durationInt) return &duration, nil } } return nil, nil }
func NewCumulativeArithmeticAggregator(name string, value *parser.Value, initialValue float64, operation Operation) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function max() requires only one argument") } return &CumulativeArithmeticAggregator{ name: name, fieldName: value.Elems[0].Name, values: make(map[string]map[interface{}]float64), operation: operation, initialValue: initialValue, }, nil }
func NewModeAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() requires at least one argument") } if len(value.Elems) > 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mode() takes at most two arguments") } size := 1 if len(value.Elems) == 2 { switch value.Elems[1].Type { case parser.ValueInt, parser.ValueFloat: var err error _size := int64(1) _size, err = strconv.ParseInt(value.Elems[1].Name, 10, 32) size = int(_size) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into an int", value.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a int", value.Elems[1].Name) } } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &ModeAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, defaultValue: wrappedDefaultValue, alias: value.Alias, size: size, }, nil }
func NewHistogramAggregator(q *parser.Query, v *parser.Value) (Aggregator, error) { if len(v.Elems) < 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() requires at least one arguments") } if len(v.Elems) > 2 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function histogram() takes at most two arguments") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function histogram() doesn't work with wildcards") } bucketSize := 1.0 if len(v.Elems) == 2 { switch v.Elems[1].Type { case parser.ValueInt, parser.ValueFloat: var err error bucketSize, err = strconv.ParseFloat(v.Elems[1].Name, 64) if err != nil { return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } default: return nil, common.NewQueryError(common.InvalidArgument, "Cannot parse %s into a float", v.Elems[1].Name) } } fieldName := v.Elems[0].Name return &HistogramAggregator{ AbstractAggregator: AbstractAggregator{ fieldName: fieldName, }, bucketSize: bucketSize, histograms: make(map[string]map[interface{}]map[int]int), }, nil }
func NewFirstOrLastAggregator(name string, v *parser.Value, isFirst bool) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function max() requires only one argument") } return &FirstOrLastAggregator{ AbstractAggregator: AbstractAggregator{ fieldName: v.Elems[0].Name, }, name: name, isFirst: isFirst, values: make(map[string]map[interface{}]*protocol.FieldValue), }, nil }
func NewDerivativeAggregator(q *parser.SelectQuery, v *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function derivative() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function derivative() doesn't work with wildcards") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &DerivativeAggregator{ AbstractAggregator: AbstractAggregator{ value: v.Elems[0], }, firstValues: make(map[string]map[interface{}]*protocol.Point), lastValues: make(map[string]map[interface{}]*protocol.Point), defaultValue: wrappedDefaultValue, }, nil }
func NewCountAggregator(q *parser.Query, v *parser.Value) (Aggregator, error) { if len(v.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function count() requires exactly one argument") } if v.Elems[0].Type == parser.ValueWildcard { return nil, common.NewQueryError(common.InvalidArgument, "function count() doesn't work with wildcards") } if v.Elems[0].Type != parser.ValueSimpleName { innerName := v.Elems[0].Name init := registeredAggregators[innerName] if init == nil { return nil, common.NewQueryError(common.InvalidArgument, fmt.Sprintf("Unknown function %s", innerName)) } inner, err := init(q, v.Elems[0]) if err != nil { return nil, err } return NewCompositeAggregator(&CountAggregator{make(map[string]map[interface{}]int32)}, inner) } return &CountAggregator{make(map[string]map[interface{}]int32)}, nil }
func (self *CoordinatorImpl) runListSeriesQuery(querySpec *parser.QuerySpec, seriesWriter SeriesWriter) error { shortTermShards := self.clusterConfiguration.GetShortTermShards() if len(shortTermShards) > SHARDS_TO_QUERY_FOR_LIST_SERIES { shortTermShards = shortTermShards[:SHARDS_TO_QUERY_FOR_LIST_SERIES] } longTermShards := self.clusterConfiguration.GetLongTermShards() if len(longTermShards) > SHARDS_TO_QUERY_FOR_LIST_SERIES { longTermShards = longTermShards[:SHARDS_TO_QUERY_FOR_LIST_SERIES] } seriesYielded := make(map[string]bool) responses := make([]chan *protocol.Response, 0) for _, shard := range shortTermShards { responseChan := make(chan *protocol.Response, self.config.QueryShardBufferSize) go shard.Query(querySpec, responseChan) responses = append(responses, responseChan) } for _, shard := range longTermShards { responseChan := make(chan *protocol.Response, self.config.QueryShardBufferSize) go shard.Query(querySpec, responseChan) responses = append(responses, responseChan) } var err error for _, responseChan := range responses { for { response := <-responseChan if *response.Type == endStreamResponse || *response.Type == accessDeniedResponse { if response.ErrorMessage != nil && err != nil { log.Debug("Error when querying shard: %s", err) err = common.NewQueryError(common.InvalidArgument, *response.ErrorMessage) } break } for _, series := range response.MultiSeries { if !seriesYielded[*series.Name] { seriesYielded[*series.Name] = true seriesWriter.Write(series) } } } } seriesWriter.Close() return err }
func NewMeanAggregator(_ *parser.SelectQuery, value *parser.Value, defaultValue *parser.Value) (Aggregator, error) { if len(value.Elems) != 1 { return nil, common.NewQueryError(common.WrongNumberOfArguments, "function mean() requires exactly one argument") } wrappedDefaultValue, err := wrapDefaultValue(defaultValue) if err != nil { return nil, err } return &MeanAggregator{ AbstractAggregator: AbstractAggregator{ value: value.Elems[0], }, defaultValue: wrappedDefaultValue, alias: value.Alias, }, nil }