mirror of https://github.com/minio/minio.git
176 lines
4.5 KiB
Go
176 lines
4.5 KiB
Go
|
/*
|
||
|
* Minio Cloud Storage, (C) 2019 Minio, Inc.
|
||
|
*
|
||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||
|
* you may not use this file except in compliance with the License.
|
||
|
* You may obtain a copy of the License at
|
||
|
*
|
||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||
|
*
|
||
|
* Unless required by applicable law or agreed to in writing, software
|
||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
|
* See the License for the specific language governing permissions and
|
||
|
* limitations under the License.
|
||
|
*/
|
||
|
|
||
|
package sql
|
||
|
|
||
|
import "fmt"
|
||
|
|
||
|
// ArithOperator - arithmetic operator.
|
||
|
type ArithOperator string
|
||
|
|
||
|
const (
|
||
|
// Add operator '+'.
|
||
|
Add ArithOperator = "+"
|
||
|
|
||
|
// Subtract operator '-'.
|
||
|
Subtract ArithOperator = "-"
|
||
|
|
||
|
// Multiply operator '*'.
|
||
|
Multiply ArithOperator = "*"
|
||
|
|
||
|
// Divide operator '/'.
|
||
|
Divide ArithOperator = "/"
|
||
|
|
||
|
// Modulo operator '%'.
|
||
|
Modulo ArithOperator = "%"
|
||
|
)
|
||
|
|
||
|
// arithExpr - arithmetic function.
|
||
|
type arithExpr struct {
|
||
|
left Expr
|
||
|
right Expr
|
||
|
operator ArithOperator
|
||
|
funcType Type
|
||
|
}
|
||
|
|
||
|
// String - returns string representation of this function.
|
||
|
func (f *arithExpr) String() string {
|
||
|
return fmt.Sprintf("(%v %v %v)", f.left, f.operator, f.right)
|
||
|
}
|
||
|
|
||
|
func (f *arithExpr) compute(lv, rv *Value) (*Value, error) {
|
||
|
leftValueType := lv.Type()
|
||
|
rightValueType := rv.Type()
|
||
|
if !leftValueType.isNumber() {
|
||
|
err := fmt.Errorf("%v: left side expression evaluated to %v; not to number", f, leftValueType)
|
||
|
return nil, errExternalEvalException(err)
|
||
|
}
|
||
|
if !rightValueType.isNumber() {
|
||
|
err := fmt.Errorf("%v: right side expression evaluated to %v; not to number", f, rightValueType)
|
||
|
return nil, errExternalEvalException(err)
|
||
|
}
|
||
|
|
||
|
leftValue := lv.FloatValue()
|
||
|
rightValue := rv.FloatValue()
|
||
|
|
||
|
var result float64
|
||
|
switch f.operator {
|
||
|
case Add:
|
||
|
result = leftValue + rightValue
|
||
|
case Subtract:
|
||
|
result = leftValue - rightValue
|
||
|
case Multiply:
|
||
|
result = leftValue * rightValue
|
||
|
case Divide:
|
||
|
result = leftValue / rightValue
|
||
|
case Modulo:
|
||
|
result = float64(int64(leftValue) % int64(rightValue))
|
||
|
}
|
||
|
|
||
|
if leftValueType == Float || rightValueType == Float {
|
||
|
return NewFloat(result), nil
|
||
|
}
|
||
|
|
||
|
return NewInt(int64(result)), nil
|
||
|
}
|
||
|
|
||
|
// Call - evaluates this function for given arg values and returns result as Value.
|
||
|
func (f *arithExpr) Eval(record Record) (*Value, error) {
|
||
|
leftValue, err := f.left.Eval(record)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
rightValue, err := f.right.Eval(record)
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
if f.funcType == aggregateFunction {
|
||
|
return nil, nil
|
||
|
}
|
||
|
|
||
|
return f.compute(leftValue, rightValue)
|
||
|
}
|
||
|
|
||
|
// AggregateValue - returns aggregated value.
|
||
|
func (f *arithExpr) AggregateValue() (*Value, error) {
|
||
|
if f.funcType != aggregateFunction {
|
||
|
err := fmt.Errorf("%v is not aggreate expression", f)
|
||
|
return nil, errExternalEvalException(err)
|
||
|
}
|
||
|
|
||
|
lv, err := f.left.AggregateValue()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
rv, err := f.right.AggregateValue()
|
||
|
if err != nil {
|
||
|
return nil, err
|
||
|
}
|
||
|
|
||
|
return f.compute(lv, rv)
|
||
|
}
|
||
|
|
||
|
// Type - returns arithmeticFunction or aggregateFunction type.
|
||
|
func (f *arithExpr) Type() Type {
|
||
|
return f.funcType
|
||
|
}
|
||
|
|
||
|
// ReturnType - returns Float as return type.
|
||
|
func (f *arithExpr) ReturnType() Type {
|
||
|
return Float
|
||
|
}
|
||
|
|
||
|
// newArithExpr - creates new arithmetic function.
|
||
|
func newArithExpr(operator ArithOperator, left, right Expr) (*arithExpr, error) {
|
||
|
if !left.ReturnType().isNumberKind() {
|
||
|
err := fmt.Errorf("operator %v: left side expression %v evaluate to %v, not number", operator, left, left.ReturnType())
|
||
|
return nil, errInvalidDataType(err)
|
||
|
}
|
||
|
|
||
|
if !right.ReturnType().isNumberKind() {
|
||
|
err := fmt.Errorf("operator %v: right side expression %v evaluate to %v; not number", operator, right, right.ReturnType())
|
||
|
return nil, errInvalidDataType(err)
|
||
|
}
|
||
|
|
||
|
funcType := arithmeticFunction
|
||
|
if left.Type() == aggregateFunction || right.Type() == aggregateFunction {
|
||
|
funcType = aggregateFunction
|
||
|
switch left.Type() {
|
||
|
case Int, Float, aggregateFunction:
|
||
|
default:
|
||
|
err := fmt.Errorf("operator %v: left side expression %v return type %v is incompatible for aggregate evaluation", operator, left, left.Type())
|
||
|
return nil, errUnsupportedSQLOperation(err)
|
||
|
}
|
||
|
|
||
|
switch right.Type() {
|
||
|
case Int, Float, aggregateFunction:
|
||
|
default:
|
||
|
err := fmt.Errorf("operator %v: right side expression %v return type %v is incompatible for aggregate evaluation", operator, right, right.Type())
|
||
|
return nil, errUnsupportedSQLOperation(err)
|
||
|
}
|
||
|
}
|
||
|
|
||
|
return &arithExpr{
|
||
|
left: left,
|
||
|
right: right,
|
||
|
operator: operator,
|
||
|
funcType: funcType,
|
||
|
}, nil
|
||
|
}
|