in query/aql_compiler.go [1139:1250]
func (qc *AQLQueryContext) processMeasure() {
// OOPK engine only supports one measure per query.
if len(qc.Query.Measures) != 1 {
qc.Error = utils.StackError(nil, "expect one measure per query, but got %d",
len(qc.Query.Measures))
return
}
if _, ok := qc.Query.Measures[0].ExprParsed.(*expr.NumberLiteral); ok {
qc.IsNonAggregationQuery = true
// in case user forgot to provide limit
if qc.Query.Limit == 0 {
qc.Query.Limit = nonAggregationQueryLimit
}
return
}
// Match and strip the aggregate function.
aggregate, ok := qc.Query.Measures[0].ExprParsed.(*expr.Call)
if !ok {
qc.Error = utils.StackError(nil, "expect aggregate function, but got %s",
qc.Query.Measures[0].Expr)
return
}
if qc.ReturnHLLData && aggregate.Name != expr.HllCallName {
qc.Error = utils.StackError(nil, "expect hll aggregate function as client specify 'Accept' as "+
"'application/hll', but got %s",
qc.Query.Measures[0].Expr)
return
}
if len(aggregate.Args) != 1 {
qc.Error = utils.StackError(nil,
"expect one parameter for aggregate function %s, but got %d",
aggregate.Name, len(aggregate.Args))
return
}
qc.OOPK.Measure = aggregate.Args[0]
// check if any array column is used in measure
ac := &arrayColumnUsageCollector{}
expr.Walk(ac, qc.OOPK.Measure)
if ac.useArrayColumn {
qc.Error = utils.StackError(nil,
"Array column is not allowed to be used in measure: %s", qc.OOPK.Measure.String())
return
}
// default is 4 bytes
qc.OOPK.MeasureBytes = 4
switch strings.ToLower(aggregate.Name) {
case expr.CountCallName:
qc.OOPK.Measure = &expr.NumberLiteral{
Int: 1,
Expr: "1",
ExprType: expr.Unsigned,
}
qc.OOPK.AggregateType = C.AGGR_SUM_UNSIGNED
case expr.SumCallName:
qc.OOPK.MeasureBytes = 8
switch qc.OOPK.Measure.Type() {
case expr.Float:
qc.OOPK.AggregateType = C.AGGR_SUM_FLOAT
case expr.Signed:
qc.OOPK.AggregateType = C.AGGR_SUM_SIGNED
case expr.Unsigned:
qc.OOPK.AggregateType = C.AGGR_SUM_UNSIGNED
default:
qc.Error = utils.StackError(nil,
unsupportedInputType, expr.SumCallName, qc.OOPK.Measure.String())
return
}
case expr.AvgCallName:
// 4 bytes for storing average result and another 4 byte for count
qc.OOPK.MeasureBytes = 8
// for average, we should always use float type as the agg type.
qc.OOPK.AggregateType = C.AGGR_AVG_FLOAT
case expr.MinCallName:
switch qc.OOPK.Measure.Type() {
case expr.Float:
qc.OOPK.AggregateType = C.AGGR_MIN_FLOAT
case expr.Signed:
qc.OOPK.AggregateType = C.AGGR_MIN_SIGNED
case expr.Unsigned:
qc.OOPK.AggregateType = C.AGGR_MIN_UNSIGNED
default:
qc.Error = utils.StackError(nil,
unsupportedInputType, expr.MinCallName, qc.OOPK.Measure.String())
return
}
case expr.MaxCallName:
switch qc.OOPK.Measure.Type() {
case expr.Float:
qc.OOPK.AggregateType = C.AGGR_MAX_FLOAT
case expr.Signed:
qc.OOPK.AggregateType = C.AGGR_MAX_SIGNED
case expr.Unsigned:
qc.OOPK.AggregateType = C.AGGR_MAX_UNSIGNED
default:
qc.Error = utils.StackError(nil,
unsupportedInputType, expr.MaxCallName, qc.OOPK.Measure.String())
return
}
case expr.HllCallName:
qc.OOPK.AggregateType = C.AGGR_HLL
default:
qc.Error = utils.StackError(nil,
"unsupported aggregate function: %s", aggregate.Name)
return
}
}