github.com/dolthub/go-mysql-server@v0.18.0/sql/types/system_double.go (about) 1 // Copyright 2022 Dolthub, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package types 16 17 import ( 18 "reflect" 19 "strconv" 20 21 "github.com/dolthub/vitess/go/sqltypes" 22 "github.com/dolthub/vitess/go/vt/proto/query" 23 "github.com/shopspring/decimal" 24 25 "github.com/dolthub/go-mysql-server/sql" 26 ) 27 28 var systemDoubleValueType = reflect.TypeOf(float64(0)) 29 30 // systemDoubleType is an internal double type ONLY for system variables. 31 type systemDoubleType struct { 32 varName string 33 lowerbound float64 34 upperbound float64 35 } 36 37 var _ sql.SystemVariableType = systemDoubleType{} 38 var _ sql.CollationCoercible = systemDoubleType{} 39 40 // NewSystemDoubleType returns a new systemDoubleType. 41 func NewSystemDoubleType(varName string, lowerbound, upperbound float64) sql.SystemVariableType { 42 return systemDoubleType{varName, lowerbound, upperbound} 43 } 44 45 // Compare implements Type interface. 46 func (t systemDoubleType) Compare(a interface{}, b interface{}) (int, error) { 47 as, _, err := t.Convert(a) 48 if err != nil { 49 return 0, err 50 } 51 bs, _, err := t.Convert(b) 52 if err != nil { 53 return 0, err 54 } 55 ai := as.(float64) 56 bi := bs.(float64) 57 58 if ai == bi { 59 return 0, nil 60 } 61 if ai < bi { 62 return -1, nil 63 } 64 return 1, nil 65 } 66 67 // Convert implements Type interface. 68 func (t systemDoubleType) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) { 69 // String nor nil values are accepted 70 switch value := v.(type) { 71 case int: 72 return t.Convert(float64(value)) 73 case uint: 74 return t.Convert(float64(value)) 75 case int8: 76 return t.Convert(float64(value)) 77 case uint8: 78 return t.Convert(float64(value)) 79 case int16: 80 return t.Convert(float64(value)) 81 case uint16: 82 return t.Convert(float64(value)) 83 case int32: 84 return t.Convert(float64(value)) 85 case uint32: 86 return t.Convert(float64(value)) 87 case int64: 88 return t.Convert(float64(value)) 89 case uint64: 90 return t.Convert(float64(value)) 91 case float32: 92 return t.Convert(float64(value)) 93 case float64: 94 if value >= t.lowerbound && value <= t.upperbound { 95 return value, sql.InRange, nil 96 } 97 case decimal.Decimal: 98 f, _ := value.Float64() 99 return t.Convert(f) 100 case decimal.NullDecimal: 101 if value.Valid { 102 f, _ := value.Decimal.Float64() 103 return t.Convert(f) 104 } 105 } 106 107 return nil, sql.OutOfRange, sql.ErrInvalidSystemVariableValue.New(t.varName, v) 108 } 109 110 // MustConvert implements the Type interface. 111 func (t systemDoubleType) MustConvert(v interface{}) interface{} { 112 value, _, err := t.Convert(v) 113 if err != nil { 114 panic(err) 115 } 116 return value 117 } 118 119 // Equals implements the Type interface. 120 func (t systemDoubleType) Equals(otherType sql.Type) bool { 121 if ot, ok := otherType.(systemDoubleType); ok { 122 return t.varName == ot.varName && t.lowerbound == ot.lowerbound && t.upperbound == ot.upperbound 123 } 124 return false 125 } 126 127 // MaxTextResponseByteLength implements the Type interface 128 func (t systemDoubleType) MaxTextResponseByteLength(ctx *sql.Context) uint32 { 129 return t.UnderlyingType().MaxTextResponseByteLength(ctx) 130 } 131 132 // Promote implements the Type interface. 133 func (t systemDoubleType) Promote() sql.Type { 134 return t 135 } 136 137 // SQL implements Type interface. 138 func (t systemDoubleType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) { 139 if v == nil { 140 return sqltypes.NULL, nil 141 } 142 143 v, _, err := t.Convert(v) 144 if err != nil { 145 return sqltypes.Value{}, err 146 } 147 148 stop := len(dest) 149 dest = strconv.AppendFloat(dest, v.(float64), 'f', -1, 64) 150 val := dest[stop:] 151 152 return sqltypes.MakeTrusted(t.Type(), val), nil 153 } 154 155 // String implements Type interface. 156 func (t systemDoubleType) String() string { 157 return "system_double" 158 } 159 160 // Type implements Type interface. 161 func (t systemDoubleType) Type() query.Type { 162 return sqltypes.Float64 163 } 164 165 // ValueType implements Type interface. 166 func (t systemDoubleType) ValueType() reflect.Type { 167 return systemDoubleValueType 168 } 169 170 // Zero implements Type interface. 171 func (t systemDoubleType) Zero() interface{} { 172 return float64(0) 173 } 174 175 // CollationCoercibility implements sql.CollationCoercible interface. 176 func (systemDoubleType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 177 return sql.Collation_binary, 5 178 } 179 180 // EncodeValue implements SystemVariableType interface. 181 func (t systemDoubleType) EncodeValue(val interface{}) (string, error) { 182 expectedVal, ok := val.(float64) 183 if !ok { 184 return "", sql.ErrSystemVariableCodeFail.New(val, t.String()) 185 } 186 return strconv.FormatFloat(expectedVal, 'f', -1, 64), nil 187 } 188 189 // DecodeValue implements SystemVariableType interface. 190 func (t systemDoubleType) DecodeValue(val string) (interface{}, error) { 191 parsedVal, err := strconv.ParseFloat(val, 64) 192 if err != nil { 193 return nil, err 194 } 195 if parsedVal >= t.lowerbound && parsedVal <= t.upperbound { 196 return parsedVal, nil 197 } 198 return nil, sql.ErrSystemVariableCodeFail.New(val, t.String()) 199 } 200 201 func (t systemDoubleType) UnderlyingType() sql.Type { 202 return Float64 203 }