github.com/influxdata/influxdb/v2@v2.7.6/influxql/query/math.go (about) 1 package query 2 3 import ( 4 "fmt" 5 "math" 6 7 "github.com/influxdata/influxql" 8 ) 9 10 func isMathFunction(call *influxql.Call) bool { 11 switch call.Name { 12 case "abs", "sin", "cos", "tan", "asin", "acos", "atan", "atan2", "exp", "log", "ln", "log2", "log10", "sqrt", "pow", "floor", "ceil", "round": 13 return true 14 } 15 return false 16 } 17 18 type MathTypeMapper struct{} 19 20 func (MathTypeMapper) MapType(measurement *influxql.Measurement, field string) influxql.DataType { 21 return influxql.Unknown 22 } 23 24 func (MathTypeMapper) CallType(name string, args []influxql.DataType) (influxql.DataType, error) { 25 switch name { 26 case "sin", "cos", "tan", "atan", "exp", "log", "ln", "log2", "log10", "sqrt": 27 var arg0 influxql.DataType 28 if len(args) > 0 { 29 arg0 = args[0] 30 } 31 switch arg0 { 32 case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown: 33 return influxql.Float, nil 34 default: 35 return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0) 36 } 37 case "asin", "acos": 38 var arg0 influxql.DataType 39 if len(args) > 0 { 40 arg0 = args[0] 41 } 42 switch arg0 { 43 case influxql.Float, influxql.Unknown: 44 return influxql.Float, nil 45 default: 46 return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0) 47 } 48 case "atan2", "pow": 49 var arg0, arg1 influxql.DataType 50 if len(args) > 0 { 51 arg0 = args[0] 52 } 53 if len(args) > 1 { 54 arg1 = args[1] 55 } 56 57 switch arg0 { 58 case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown: 59 // Pass through to verify the second argument. 60 default: 61 return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0) 62 } 63 64 switch arg1 { 65 case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown: 66 return influxql.Float, nil 67 default: 68 return influxql.Unknown, fmt.Errorf("invalid argument type for the second argument in %s(): %s", name, arg1) 69 } 70 case "abs", "floor", "ceil", "round": 71 var arg0 influxql.DataType 72 if len(args) > 0 { 73 arg0 = args[0] 74 } 75 switch arg0 { 76 case influxql.Float, influxql.Integer, influxql.Unsigned, influxql.Unknown: 77 return args[0], nil 78 default: 79 return influxql.Unknown, fmt.Errorf("invalid argument type for the first argument in %s(): %s", name, arg0) 80 } 81 } 82 return influxql.Unknown, nil 83 } 84 85 type MathValuer struct{} 86 87 var _ influxql.CallValuer = MathValuer{} 88 89 func (MathValuer) Value(key string) (interface{}, bool) { 90 return nil, false 91 } 92 93 func (v MathValuer) Call(name string, args []interface{}) (interface{}, bool) { 94 if len(args) == 1 { 95 arg0 := args[0] 96 switch name { 97 case "abs": 98 switch arg0 := arg0.(type) { 99 case float64: 100 return math.Abs(arg0), true 101 case int64: 102 sign := arg0 >> 63 103 return (arg0 ^ sign) - sign, true 104 case uint64: 105 return arg0, true 106 default: 107 return nil, true 108 } 109 case "sin": 110 if arg0, ok := asFloat(arg0); ok { 111 return math.Sin(arg0), true 112 } 113 return nil, true 114 case "cos": 115 if arg0, ok := asFloat(arg0); ok { 116 return math.Cos(arg0), true 117 } 118 return nil, true 119 case "tan": 120 if arg0, ok := asFloat(arg0); ok { 121 return math.Tan(arg0), true 122 } 123 return nil, true 124 case "floor": 125 switch arg0 := arg0.(type) { 126 case float64: 127 return math.Floor(arg0), true 128 case int64, uint64: 129 return arg0, true 130 default: 131 return nil, true 132 } 133 case "ceil": 134 switch arg0 := arg0.(type) { 135 case float64: 136 return math.Ceil(arg0), true 137 case int64, uint64: 138 return arg0, true 139 default: 140 return nil, true 141 } 142 case "round": 143 switch arg0 := arg0.(type) { 144 case float64: 145 return round(arg0), true 146 case int64, uint64: 147 return arg0, true 148 default: 149 return nil, true 150 } 151 case "asin": 152 if arg0, ok := asFloat(arg0); ok { 153 return math.Asin(arg0), true 154 } 155 return nil, true 156 case "acos": 157 if arg0, ok := asFloat(arg0); ok { 158 return math.Acos(arg0), true 159 } 160 return nil, true 161 case "atan": 162 if arg0, ok := asFloat(arg0); ok { 163 return math.Atan(arg0), true 164 } 165 return nil, true 166 case "exp": 167 if arg0, ok := asFloat(arg0); ok { 168 return math.Exp(arg0), true 169 } 170 return nil, true 171 case "ln": 172 if arg0, ok := asFloat(arg0); ok { 173 return math.Log(arg0), true 174 } 175 return nil, true 176 case "log2": 177 if arg0, ok := asFloat(arg0); ok { 178 return math.Log2(arg0), true 179 } 180 return nil, true 181 case "log10": 182 if arg0, ok := asFloat(arg0); ok { 183 return math.Log10(arg0), true 184 } 185 return nil, true 186 case "sqrt": 187 if arg0, ok := asFloat(arg0); ok { 188 return math.Sqrt(arg0), true 189 } 190 return nil, true 191 } 192 } else if len(args) == 2 { 193 arg0, arg1 := args[0], args[1] 194 switch name { 195 case "atan2": 196 if arg0, arg1, ok := asFloats(arg0, arg1); ok { 197 return math.Atan2(arg0, arg1), true 198 } 199 return nil, true 200 case "log": 201 if arg0, arg1, ok := asFloats(arg0, arg1); ok { 202 return math.Log(arg0) / math.Log(arg1), true 203 } 204 return nil, true 205 case "pow": 206 if arg0, arg1, ok := asFloats(arg0, arg1); ok { 207 return math.Pow(arg0, arg1), true 208 } 209 return nil, true 210 } 211 } 212 return nil, false 213 } 214 215 func asFloat(x interface{}) (float64, bool) { 216 switch arg0 := x.(type) { 217 case float64: 218 return arg0, true 219 case int64: 220 return float64(arg0), true 221 case uint64: 222 return float64(arg0), true 223 default: 224 return 0, false 225 } 226 } 227 228 func asFloats(x, y interface{}) (float64, float64, bool) { 229 arg0, ok := asFloat(x) 230 if !ok { 231 return 0, 0, false 232 } 233 arg1, ok := asFloat(y) 234 if !ok { 235 return 0, 0, false 236 } 237 return arg0, arg1, true 238 } 239 240 func round(x float64) float64 { 241 t := math.Trunc(x) 242 if math.Abs(x-t) >= 0.5 { 243 return t + math.Copysign(1, x) 244 } 245 return t 246 }