github.com/team-ide/go-dialect@v1.9.20/vitess/sqltypes/bind_variables.go (about) 1 /* 2 Copyright 2019 The Vitess Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package sqltypes 18 19 import ( 20 "bytes" 21 "errors" 22 "fmt" 23 "strconv" 24 25 "google.golang.org/protobuf/proto" 26 27 querypb "github.com/team-ide/go-dialect/vitess/query" 28 ) 29 30 type DecimalFloat float64 31 32 var ( 33 // BvSchemaName is bind variable to be sent down to vttablet for schema name. 34 BvSchemaName = "__vtschemaname" 35 36 // BvReplaceSchemaName is bind variable to be sent down to vttablet to replace schema name. 37 BvReplaceSchemaName = "__replacevtschemaname" 38 39 // NullBindVariable is a bindvar with NULL value. 40 NullBindVariable = &querypb.BindVariable{Type: querypb.Type_NULL_TYPE} 41 ) 42 43 // ValueToProto converts Value to a *querypb.Value. 44 func ValueToProto(v Value) *querypb.Value { 45 return &querypb.Value{Type: v.typ, Value: v.val} 46 } 47 48 // ProtoToValue converts a *querypb.Value to a Value. 49 func ProtoToValue(v *querypb.Value) Value { 50 return MakeTrusted(v.Type, v.Value) 51 } 52 53 // BuildBindVariables builds a map[string]*querypb.BindVariable from a map[string]interface{}. 54 func BuildBindVariables(in map[string]interface{}) (map[string]*querypb.BindVariable, error) { 55 if len(in) == 0 { 56 return nil, nil 57 } 58 59 out := make(map[string]*querypb.BindVariable, len(in)) 60 for k, v := range in { 61 bv, err := BuildBindVariable(v) 62 if err != nil { 63 return nil, fmt.Errorf("%s: %v", k, err) 64 } 65 out[k] = bv 66 } 67 return out, nil 68 } 69 70 // HexNumBindVariable converts bytes representing a hex number to a bind var. 71 func HexNumBindVariable(v []byte) *querypb.BindVariable { 72 return ValueBindVariable(NewHexNum(v)) 73 } 74 75 // HexValBindVariable converts bytes representing a hex encoded string to a bind var. 76 func HexValBindVariable(v []byte) *querypb.BindVariable { 77 return ValueBindVariable(NewHexVal(v)) 78 } 79 80 // Int8BindVariable converts an int8 to a bind var. 81 func Int8BindVariable(v int8) *querypb.BindVariable { 82 return ValueBindVariable(NewInt8(v)) 83 } 84 85 // Int32BindVariable converts an int32 to a bind var. 86 func Int32BindVariable(v int32) *querypb.BindVariable { 87 return ValueBindVariable(NewInt32(v)) 88 } 89 90 // BoolBindVariable converts an bool to a int64 bind var. 91 func BoolBindVariable(v bool) *querypb.BindVariable { 92 if v { 93 return Int64BindVariable(1) 94 } 95 return Int64BindVariable(0) 96 } 97 98 // Int64BindVariable converts an int64 to a bind var. 99 func Int64BindVariable(v int64) *querypb.BindVariable { 100 return ValueBindVariable(NewInt64(v)) 101 } 102 103 // Uint64BindVariable converts a uint64 to a bind var. 104 func Uint64BindVariable(v uint64) *querypb.BindVariable { 105 return ValueBindVariable(NewUint64(v)) 106 } 107 108 // Float64BindVariable converts a float64 to a bind var. 109 func Float64BindVariable(v float64) *querypb.BindVariable { 110 return ValueBindVariable(NewFloat64(v)) 111 } 112 113 func DecimalBindVariable(v DecimalFloat) *querypb.BindVariable { 114 f := strconv.FormatFloat(float64(v), 'f', -1, 64) 115 return ValueBindVariable(NewDecimal(f)) 116 } 117 118 // StringBindVariable converts a string to a bind var. 119 func StringBindVariable(v string) *querypb.BindVariable { 120 return ValueBindVariable(NewVarChar(v)) 121 } 122 123 // BytesBindVariable converts a []byte to a bind var. 124 func BytesBindVariable(v []byte) *querypb.BindVariable { 125 return &querypb.BindVariable{Type: VarBinary, Value: v} 126 } 127 128 // ValueBindVariable converts a Value to a bind var. 129 func ValueBindVariable(v Value) *querypb.BindVariable { 130 return &querypb.BindVariable{Type: v.typ, Value: v.val} 131 } 132 133 // BuildBindVariable builds a *querypb.BindVariable from a valid input type. 134 func BuildBindVariable(v interface{}) (*querypb.BindVariable, error) { 135 switch v := v.(type) { 136 case string: 137 return StringBindVariable(v), nil 138 case []byte: 139 return BytesBindVariable(v), nil 140 case bool: 141 if v { 142 return Int8BindVariable(1), nil 143 } 144 return Int8BindVariable(0), nil 145 case int: 146 return &querypb.BindVariable{ 147 Type: querypb.Type_INT64, 148 Value: strconv.AppendInt(nil, int64(v), 10), 149 }, nil 150 case int64: 151 return Int64BindVariable(v), nil 152 case uint64: 153 return Uint64BindVariable(v), nil 154 case DecimalFloat: 155 return DecimalBindVariable(v), nil 156 case float64: 157 return Float64BindVariable(v), nil 158 case nil: 159 return NullBindVariable, nil 160 case Value: 161 return ValueBindVariable(v), nil 162 case *querypb.BindVariable: 163 return v, nil 164 case []interface{}: 165 bv := &querypb.BindVariable{ 166 Type: querypb.Type_TUPLE, 167 Values: make([]*querypb.Value, len(v)), 168 } 169 values := make([]querypb.Value, len(v)) 170 for i, lv := range v { 171 lbv, err := BuildBindVariable(lv) 172 if err != nil { 173 return nil, err 174 } 175 values[i].Type = lbv.Type 176 values[i].Value = lbv.Value 177 bv.Values[i] = &values[i] 178 } 179 return bv, nil 180 case []string: 181 bv := &querypb.BindVariable{ 182 Type: querypb.Type_TUPLE, 183 Values: make([]*querypb.Value, len(v)), 184 } 185 values := make([]querypb.Value, len(v)) 186 for i, lv := range v { 187 values[i].Type = querypb.Type_VARCHAR 188 values[i].Value = []byte(lv) 189 bv.Values[i] = &values[i] 190 } 191 return bv, nil 192 case [][]byte: 193 bv := &querypb.BindVariable{ 194 Type: querypb.Type_TUPLE, 195 Values: make([]*querypb.Value, len(v)), 196 } 197 values := make([]querypb.Value, len(v)) 198 for i, lv := range v { 199 values[i].Type = querypb.Type_VARBINARY 200 values[i].Value = lv 201 bv.Values[i] = &values[i] 202 } 203 return bv, nil 204 case []int: 205 bv := &querypb.BindVariable{ 206 Type: querypb.Type_TUPLE, 207 Values: make([]*querypb.Value, len(v)), 208 } 209 values := make([]querypb.Value, len(v)) 210 for i, lv := range v { 211 values[i].Type = querypb.Type_INT64 212 values[i].Value = strconv.AppendInt(nil, int64(lv), 10) 213 bv.Values[i] = &values[i] 214 } 215 return bv, nil 216 case []int64: 217 bv := &querypb.BindVariable{ 218 Type: querypb.Type_TUPLE, 219 Values: make([]*querypb.Value, len(v)), 220 } 221 values := make([]querypb.Value, len(v)) 222 for i, lv := range v { 223 values[i].Type = querypb.Type_INT64 224 values[i].Value = strconv.AppendInt(nil, lv, 10) 225 bv.Values[i] = &values[i] 226 } 227 return bv, nil 228 case []uint64: 229 bv := &querypb.BindVariable{ 230 Type: querypb.Type_TUPLE, 231 Values: make([]*querypb.Value, len(v)), 232 } 233 values := make([]querypb.Value, len(v)) 234 for i, lv := range v { 235 values[i].Type = querypb.Type_UINT64 236 values[i].Value = strconv.AppendUint(nil, lv, 10) 237 bv.Values[i] = &values[i] 238 } 239 return bv, nil 240 case []float64: 241 bv := &querypb.BindVariable{ 242 Type: querypb.Type_TUPLE, 243 Values: make([]*querypb.Value, len(v)), 244 } 245 values := make([]querypb.Value, len(v)) 246 for i, lv := range v { 247 values[i].Type = querypb.Type_FLOAT64 248 values[i].Value = strconv.AppendFloat(nil, lv, 'g', -1, 64) 249 bv.Values[i] = &values[i] 250 } 251 return bv, nil 252 case []Value: 253 bv := &querypb.BindVariable{ 254 Type: querypb.Type_TUPLE, 255 Values: make([]*querypb.Value, len(v)), 256 } 257 values := make([]querypb.Value, len(v)) 258 for i, lv := range v { 259 lbv, err := BuildBindVariable(lv) 260 if err != nil { 261 return nil, err 262 } 263 values[i].Type = lbv.Type 264 values[i].Value = lbv.Value 265 bv.Values[i] = &values[i] 266 } 267 return bv, nil 268 } 269 return nil, fmt.Errorf("type %T not supported as bind var: %v", v, v) 270 } 271 272 // ValidateBindVariables validates a map[string]*querypb.BindVariable. 273 func ValidateBindVariables(bv map[string]*querypb.BindVariable) error { 274 for k, v := range bv { 275 if err := ValidateBindVariable(v); err != nil { 276 return fmt.Errorf("%s: %v", k, err) 277 } 278 } 279 return nil 280 } 281 282 // ValidateBindVariable returns an error if the bind variable has inconsistent 283 // fields. 284 func ValidateBindVariable(bv *querypb.BindVariable) error { 285 if bv == nil { 286 return errors.New("bind variable is nil") 287 } 288 289 if bv.Type == querypb.Type_TUPLE { 290 if len(bv.Values) == 0 { 291 return errors.New("empty tuple is not allowed") 292 } 293 for _, val := range bv.Values { 294 if val.Type == querypb.Type_TUPLE { 295 return errors.New("tuple not allowed inside another tuple") 296 } 297 if err := ValidateBindVariable(&querypb.BindVariable{Type: val.Type, Value: val.Value}); err != nil { 298 return err 299 } 300 } 301 return nil 302 } 303 304 // If NewValue succeeds, the value is valid. 305 _, err := NewValue(bv.Type, bv.Value) 306 return err 307 } 308 309 // BindVariableToValue converts a bind var into a Value. 310 func BindVariableToValue(bv *querypb.BindVariable) (Value, error) { 311 if bv.Type == querypb.Type_TUPLE { 312 return NULL, errors.New("cannot convert a TUPLE bind var into a value") 313 } 314 return MakeTrusted(bv.Type, bv.Value), nil 315 } 316 317 // BindVariablesEqual compares two maps of bind variables. 318 // For protobuf messages we have to use "proto.Equal". 319 func BindVariablesEqual(x, y map[string]*querypb.BindVariable) bool { 320 return proto.Equal(&querypb.BoundQuery{BindVariables: x}, &querypb.BoundQuery{BindVariables: y}) 321 } 322 323 // CopyBindVariables returns a shallow-copy of the given bindVariables map. 324 func CopyBindVariables(bindVariables map[string]*querypb.BindVariable) map[string]*querypb.BindVariable { 325 result := make(map[string]*querypb.BindVariable, len(bindVariables)) 326 for key, value := range bindVariables { 327 result[key] = value 328 } 329 return result 330 } 331 332 // FormatBindVariables returns a string representation of the 333 // bind variables. 334 // 335 // If full is false, then large string or tuple values are truncated 336 // to only print the lengths. 337 // 338 // If asJson is true, then the resulting string is a valid JSON 339 // representation, otherwise it is the golang printed map representation. 340 func FormatBindVariables(bindVariables map[string]*querypb.BindVariable, full, asJSON bool) string { 341 var out map[string]*querypb.BindVariable 342 if full { 343 out = bindVariables 344 } else { 345 // NOTE(szopa): I am getting rid of potentially large bind 346 // variables. 347 out = make(map[string]*querypb.BindVariable) 348 for k, v := range bindVariables { 349 if IsIntegral(v.Type) || IsFloat(v.Type) { 350 out[k] = v 351 } else if v.Type == querypb.Type_TUPLE { 352 out[k] = StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) 353 } else { 354 out[k] = StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) 355 } 356 } 357 } 358 359 if asJSON { 360 var buf bytes.Buffer 361 buf.WriteString("{") 362 first := true 363 for k, v := range out { 364 if !first { 365 buf.WriteString(", ") 366 } else { 367 first = false 368 } 369 if IsIntegral(v.Type) || IsFloat(v.Type) { 370 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) 371 } else { 372 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) 373 } 374 } 375 buf.WriteString("}") 376 return buf.String() 377 } 378 379 return fmt.Sprintf("%v", out) 380 }