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  }