func Max(v1, v2 Value) Value {
	return minmax(v1, v2, false)
}
Max returns the maximum of v1 and v2. If one of the
values is NULL, it returns the other value. If both
are NULL, it returns NULL.
package sqltypes
import (
	"bytes"
	"fmt"
	"math"
	"strconv"
	"github.com/shopspring/decimal"
	"github.com/xelabs/go-mysqlstack/sqlparser/depends/common"
	querypb "github.com/xelabs/go-mysqlstack/sqlparser/depends/query"
)
type numeric struct {
	typ  querypb.Type
	ival int64
	uval uint64
	fval float64
	dval decimal.Decimal
}
func NullsafeAdd(v1, v2 Value, resultType querypb.Type, prec int) (Value, error) {
	if v1.IsNull() {
		return v2, nil
	}
	if v2.IsNull() {
		return v1, nil
	}
	lv1, err := newNumeric(v1)
	if err != nil {
		return NULL, err
	}
	lv2, err := newNumeric(v2)
	if err != nil {
		return NULL, err
	}
	res, err := addNumeric(lv1, lv2)
	if err != nil {
		return NULL, err
	}
	return castFromNumeric(res, resultType, prec)
}
func NullsafeSum(sum, v Value, resultType querypb.Type, prec int) (Value, error) {
	if sum.IsNull() {
		return v, nil
	}
	if v.IsNull() {
		return sum, nil
	}
	lv1, err := newNumericFloat(sum)
	if err != nil {
		return NULL, err
	}
	lv2, err := newNumericFloat(v)
	if err != nil {
		return NULL, err
	}
	res := numeric{}
	if resultType == Decimal {
		res = numeric{typ: Decimal, dval: decimal.NewFromFloat(lv1.fval).Add(decimal.NewFromFloat(lv2.fval))}
	} else {
		fval := lv1.fval + lv2.fval
		if math.IsInf(fval, 0) {
			return NULL, fmt.Errorf("DOUBLE.value.is.out.of.range.in: '%v + %v'", lv1.fval, lv2.fval)
		}
		res = numeric{typ: Float64, fval: fval}
	}
	return castFromNumeric(res, resultType, prec)
}
func NullsafeDiv(v1, v2 Value, resultType querypb.Type, prec int) (Value, error) {
	if v1.IsNull() || v2.IsNull() {
		return NULL, nil
	}
	lv1, err := newNumericFloat(v1)
	if err != nil {
		return NULL, err
	}
	lv2, err := newNumericFloat(v2)
	if err != nil {
		return NULL, err
	}
	if lv2.fval == 0 {
		return NULL, nil
	}
	res := numeric{}
	if resultType == Decimal {
		res = numeric{typ: Decimal, dval: decimal.NewFromFloat(lv1.fval).Div(decimal.NewFromFloat(lv2.fval))}
	} else {
		fval := lv1.fval / lv2.fval
		if math.IsInf(fval, 0) {
			return NULL, fmt.Errorf("DOUBLE.value.is.out.of.range.in: '%v / %v'", lv1.fval, lv2.fval)
		}
		res = numeric{typ: Float64, fval: fval}
	}
	return castFromNumeric(res, resultType, prec)
}
func NullsafeCompare(v1, v2 Value) int {
	if v1.IsNull() {
		if v2.IsNull() {
			return 0
		}
		return -1
	}
	if v2.IsNull() {
		return 1
	}
	if isNumber(v1.Type()) || isNumber(v2.Type()) {
		lv1, err := newNumeric(v1)
		if err != nil {
			panic(err)
		}
		lv2, err := newNumeric(v2)
		if err != nil {
			panic(err)
		}
		return compareNumeric(lv1, lv2)
	}
	if v1.Type() == Tuple || v2.Type() == Tuple {
		panic(fmt.Sprintf("unsupported.value.type:%v.vs.%v", v1.Type(), v2.Type()))
	}
	return bytes.Compare(v1.val, v2.val)
}
func Min(v1, v2 Value) Value {
	return minmax(v1, v2, true)
}