247 lines
5.6 KiB
Go
247 lines
5.6 KiB
Go
package query
|
|
|
|
import (
|
|
"fmt"
|
|
"math"
|
|
|
|
"github.com/influxdata/influxql"
|
|
)
|
|
|
|
func isMathFunction(call *influxql.Call) bool {
|
|
switch call.Name {
|
|
case "abs", "sin", "cos", "tan", "asin", "acos", "atan", "atan2", "exp", "log", "ln", "log2", "log10", "sqrt", "pow", "floor", "ceil", "round":
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
type MathTypeMapper struct{}
|
|
|
|
func (MathTypeMapper) MapType(measurement *influxql.Measurement, field string) influxql.DataType {
|
|
return influxql.Unknown
|
|
}
|
|
|
|
func (MathTypeMapper) CallType(name string, args []influxql.DataType) (influxql.DataType, error) {
|
|
switch name {
|
|
case "sin", "cos", "tan", "atan", "exp", "log", "ln", "log2", "log10", "sqrt":
|
|
var arg0 influxql.DataType
|
|
if len(args) > 0 {
|
|
arg0 = args[0]
|
|
}
|
|
switch arg0 {
|
|
case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown:
|
|
return influxql.Float, nil
|
|
default:
|
|
return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0)
|
|
}
|
|
case "asin", "acos":
|
|
var arg0 influxql.DataType
|
|
if len(args) > 0 {
|
|
arg0 = args[0]
|
|
}
|
|
switch arg0 {
|
|
case influxql.Float, influxql.Unknown:
|
|
return influxql.Float, nil
|
|
default:
|
|
return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0)
|
|
}
|
|
case "atan2", "pow":
|
|
var arg0, arg1 influxql.DataType
|
|
if len(args) > 0 {
|
|
arg0 = args[0]
|
|
}
|
|
if len(args) > 1 {
|
|
arg1 = args[1]
|
|
}
|
|
|
|
switch arg0 {
|
|
case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown:
|
|
// Pass through to verify the second argument.
|
|
default:
|
|
return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0)
|
|
}
|
|
|
|
switch arg1 {
|
|
case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown:
|
|
return influxql.Float, nil
|
|
default:
|
|
return influxql.Unknown, fmt.Errorf("invalid argument type for the second argument in %s(): %s", name, arg1)
|
|
}
|
|
case "abs", "floor", "ceil", "round":
|
|
var arg0 influxql.DataType
|
|
if len(args) > 0 {
|
|
arg0 = args[0]
|
|
}
|
|
switch arg0 {
|
|
case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown:
|
|
return args[0], nil
|
|
default:
|
|
return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0)
|
|
}
|
|
}
|
|
return influxql.Unknown, nil
|
|
}
|
|
|
|
type MathValuer struct{}
|
|
|
|
var _ influxql.CallValuer = MathValuer{}
|
|
|
|
func (MathValuer) Value(key string) (interface{}, bool) {
|
|
return nil, false
|
|
}
|
|
|
|
func (v MathValuer) Call(name string, args []interface{}) (interface{}, bool) {
|
|
if len(args) == 1 {
|
|
arg0 := args[0]
|
|
switch name {
|
|
case "abs":
|
|
switch arg0 := arg0.(type) {
|
|
case float64:
|
|
return math.Abs(arg0), true
|
|
case int64:
|
|
sign := arg0 >> 63
|
|
return (arg0 ^ sign) - sign, true
|
|
case uint64:
|
|
return arg0, true
|
|
default:
|
|
return nil, true
|
|
}
|
|
case "sin":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Sin(arg0), true
|
|
}
|
|
return nil, true
|
|
case "cos":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Cos(arg0), true
|
|
}
|
|
return nil, true
|
|
case "tan":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Tan(arg0), true
|
|
}
|
|
return nil, true
|
|
case "floor":
|
|
switch arg0 := arg0.(type) {
|
|
case float64:
|
|
return math.Floor(arg0), true
|
|
case int64, uint64:
|
|
return arg0, true
|
|
default:
|
|
return nil, true
|
|
}
|
|
case "ceil":
|
|
switch arg0 := arg0.(type) {
|
|
case float64:
|
|
return math.Ceil(arg0), true
|
|
case int64, uint64:
|
|
return arg0, true
|
|
default:
|
|
return nil, true
|
|
}
|
|
case "round":
|
|
switch arg0 := arg0.(type) {
|
|
case float64:
|
|
return round(arg0), true
|
|
case int64, uint64:
|
|
return arg0, true
|
|
default:
|
|
return nil, true
|
|
}
|
|
case "asin":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Asin(arg0), true
|
|
}
|
|
return nil, true
|
|
case "acos":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Acos(arg0), true
|
|
}
|
|
return nil, true
|
|
case "atan":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Atan(arg0), true
|
|
}
|
|
return nil, true
|
|
case "exp":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Exp(arg0), true
|
|
}
|
|
return nil, true
|
|
case "ln":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Log(arg0), true
|
|
}
|
|
return nil, true
|
|
case "log2":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Log2(arg0), true
|
|
}
|
|
return nil, true
|
|
case "log10":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Log10(arg0), true
|
|
}
|
|
return nil, true
|
|
case "sqrt":
|
|
if arg0, ok := asFloat(arg0); ok {
|
|
return math.Sqrt(arg0), true
|
|
}
|
|
return nil, true
|
|
}
|
|
} else if len(args) == 2 {
|
|
arg0, arg1 := args[0], args[1]
|
|
switch name {
|
|
case "atan2":
|
|
if arg0, arg1, ok := asFloats(arg0, arg1); ok {
|
|
return math.Atan2(arg0, arg1), true
|
|
}
|
|
return nil, true
|
|
case "log":
|
|
if arg0, arg1, ok := asFloats(arg0, arg1); ok {
|
|
return math.Log(arg0) / math.Log(arg1), true
|
|
}
|
|
return nil, true
|
|
case "pow":
|
|
if arg0, arg1, ok := asFloats(arg0, arg1); ok {
|
|
return math.Pow(arg0, arg1), true
|
|
}
|
|
return nil, true
|
|
}
|
|
}
|
|
return nil, false
|
|
}
|
|
|
|
func asFloat(x interface{}) (float64, bool) {
|
|
switch arg0 := x.(type) {
|
|
case float64:
|
|
return arg0, true
|
|
case int64:
|
|
return float64(arg0), true
|
|
case uint64:
|
|
return float64(arg0), true
|
|
default:
|
|
return 0, false
|
|
}
|
|
}
|
|
|
|
func asFloats(x, y interface{}) (float64, float64, bool) {
|
|
arg0, ok := asFloat(x)
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
arg1, ok := asFloat(y)
|
|
if !ok {
|
|
return 0, 0, false
|
|
}
|
|
return arg0, arg1, true
|
|
}
|
|
|
|
func round(x float64) float64 {
|
|
t := math.Trunc(x)
|
|
if math.Abs(x-t) >= 0.5 {
|
|
return t + math.Copysign(1, x)
|
|
}
|
|
return t
|
|
}
|