github.com/dolthub/go-mysql-server@v0.18.0/sql/types/system_bool.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 "strings" 21 22 "github.com/dolthub/vitess/go/sqltypes" 23 "github.com/dolthub/vitess/go/vt/proto/query" 24 "github.com/shopspring/decimal" 25 26 "github.com/dolthub/go-mysql-server/sql" 27 ) 28 29 var systemBoolValueType = reflect.TypeOf(int8(0)) 30 31 // SystemBoolType is an internal boolean type ONLY for system variables. 32 type SystemBoolType struct { 33 varName string 34 } 35 36 var _ sql.SystemVariableType = SystemBoolType{} 37 var _ sql.CollationCoercible = SystemBoolType{} 38 39 // NewSystemBoolType returns a new systemBoolType. 40 func NewSystemBoolType(varName string) sql.SystemVariableType { 41 return SystemBoolType{varName} 42 } 43 44 // Compare implements Type interface. 45 func (t SystemBoolType) Compare(a interface{}, b interface{}) (int, error) { 46 as, _, err := t.Convert(a) 47 if err != nil { 48 return 0, err 49 } 50 bs, _, err := t.Convert(b) 51 if err != nil { 52 return 0, err 53 } 54 ai := as.(int8) 55 bi := bs.(int8) 56 57 if ai == bi { 58 return 0, nil 59 } 60 if ai < bi { 61 return -1, nil 62 } 63 return 1, nil 64 } 65 66 // Convert implements Type interface. 67 func (t SystemBoolType) Convert(v interface{}) (interface{}, sql.ConvertInRange, error) { 68 // Nil values are not accepted 69 switch value := v.(type) { 70 case bool: 71 if value { 72 return int8(1), sql.InRange, nil 73 } 74 return int8(0), sql.InRange, nil 75 case int: 76 return t.Convert(int64(value)) 77 case uint: 78 return t.Convert(int64(value)) 79 case int8: 80 return t.Convert(int64(value)) 81 case uint8: 82 return t.Convert(int64(value)) 83 case int16: 84 return t.Convert(int64(value)) 85 case uint16: 86 return t.Convert(int64(value)) 87 case int32: 88 return t.Convert(int64(value)) 89 case uint32: 90 return t.Convert(int64(value)) 91 case int64: 92 if value == 0 || value == 1 { 93 return int8(value), sql.InRange, nil 94 } 95 case uint64: 96 return t.Convert(int64(value)) 97 case float32: 98 return t.Convert(float64(value)) 99 case float64: 100 // Float values aren't truly accepted, but the engine will give them when it should give ints. 101 // Therefore, if the float doesn't have a fractional portion, we treat it as an int. 102 if value == float64(int64(value)) { 103 return t.Convert(int64(value)) 104 } 105 case decimal.Decimal: 106 f, _ := value.Float64() 107 return t.Convert(f) 108 case decimal.NullDecimal: 109 if value.Valid { 110 f, _ := value.Decimal.Float64() 111 return t.Convert(f) 112 } 113 case string: 114 switch strings.ToLower(value) { 115 case "on", "true": 116 return int8(1), sql.InRange, nil 117 case "off", "false": 118 return int8(0), sql.InRange, nil 119 } 120 } 121 122 return nil, sql.OutOfRange, sql.ErrInvalidSystemVariableValue.New(t.varName, v) 123 } 124 125 // MustConvert implements the Type interface. 126 func (t SystemBoolType) MustConvert(v interface{}) interface{} { 127 value, _, err := t.Convert(v) 128 if err != nil { 129 panic(err) 130 } 131 return value 132 } 133 134 // Equals implements the Type interface. 135 func (t SystemBoolType) Equals(otherType sql.Type) bool { 136 if ot, ok := otherType.(SystemBoolType); ok { 137 return t.varName == ot.varName 138 } 139 return false 140 } 141 142 // MaxTextResponseByteLength implements the Type interface 143 func (t SystemBoolType) MaxTextResponseByteLength(ctx *sql.Context) uint32 { 144 return t.UnderlyingType().MaxTextResponseByteLength(ctx) 145 } 146 147 // Promote implements the Type interface. 148 func (t SystemBoolType) Promote() sql.Type { 149 return t 150 } 151 152 // SQL implements Type interface. 153 func (t SystemBoolType) SQL(ctx *sql.Context, dest []byte, v interface{}) (sqltypes.Value, error) { 154 if v == nil { 155 return sqltypes.NULL, nil 156 } 157 158 v, _, err := t.Convert(v) 159 if err != nil { 160 return sqltypes.Value{}, err 161 } 162 163 stop := len(dest) 164 dest = strconv.AppendInt(dest, int64(v.(int8)), 10) 165 val := dest[stop:] 166 167 return sqltypes.MakeTrusted(t.Type(), val), nil 168 } 169 170 // String implements Type interface. 171 func (t SystemBoolType) String() string { 172 return "system_bool" 173 } 174 175 // Type implements Type interface. 176 func (t SystemBoolType) Type() query.Type { 177 return sqltypes.Int8 178 } 179 180 // CollationCoercibility implements sql.CollationCoercible interface. 181 func (SystemBoolType) CollationCoercibility(ctx *sql.Context) (collation sql.CollationID, coercibility byte) { 182 return sql.Collation_binary, 5 183 } 184 185 // ValueType implements Type interface. 186 func (t SystemBoolType) ValueType() reflect.Type { 187 return systemBoolValueType 188 } 189 190 // Zero implements Type interface. 191 func (t SystemBoolType) Zero() interface{} { 192 return int8(0) 193 } 194 195 // EncodeValue implements SystemVariableType interface. 196 func (t SystemBoolType) EncodeValue(val interface{}) (string, error) { 197 expectedVal, ok := val.(int8) 198 if !ok { 199 return "", sql.ErrSystemVariableCodeFail.New(val, t.String()) 200 } 201 if expectedVal == 0 { 202 return "0", nil 203 } 204 return "1", nil 205 } 206 207 // DecodeValue implements SystemVariableType interface. 208 func (t SystemBoolType) DecodeValue(val string) (interface{}, error) { 209 if val == "0" { 210 return int8(0), nil 211 } else if val == "1" { 212 return int8(1), nil 213 } 214 return nil, sql.ErrSystemVariableCodeFail.New(val, t.String()) 215 } 216 217 func (t SystemBoolType) UnderlyingType() sql.Type { 218 return Boolean 219 }