vitess.io/vitess@v0.16.2/go/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 "vitess.io/vitess/go/vt/proto/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]any 54 func BuildBindVariables(in map[string]any) (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 // BitNumBindVariable converts bytes representing a bit encoded string to a bind var. 81 func BitNumBindVariable(v []byte) *querypb.BindVariable { 82 return ValueBindVariable(NewBitNum(v)) 83 } 84 85 // Int8BindVariable converts an int8 to a bind var. 86 func Int8BindVariable(v int8) *querypb.BindVariable { 87 return ValueBindVariable(NewInt8(v)) 88 } 89 90 // Int32BindVariable converts an int32 to a bind var. 91 func Int32BindVariable(v int32) *querypb.BindVariable { 92 return ValueBindVariable(NewInt32(v)) 93 } 94 95 // Uint32BindVariable converts a uint32 to a bind var. 96 func Uint32BindVariable(v uint32) *querypb.BindVariable { 97 return ValueBindVariable(NewUint32(v)) 98 } 99 100 // BoolBindVariable converts an bool to a int64 bind var. 101 func BoolBindVariable(v bool) *querypb.BindVariable { 102 if v { 103 return Int64BindVariable(1) 104 } 105 return Int64BindVariable(0) 106 } 107 108 // Int64BindVariable converts an int64 to a bind var. 109 func Int64BindVariable(v int64) *querypb.BindVariable { 110 return ValueBindVariable(NewInt64(v)) 111 } 112 113 // Uint64BindVariable converts a uint64 to a bind var. 114 func Uint64BindVariable(v uint64) *querypb.BindVariable { 115 return ValueBindVariable(NewUint64(v)) 116 } 117 118 // Float64BindVariable converts a float64 to a bind var. 119 func Float64BindVariable(v float64) *querypb.BindVariable { 120 return ValueBindVariable(NewFloat64(v)) 121 } 122 123 func DecimalBindVariable(v DecimalFloat) *querypb.BindVariable { 124 f := strconv.FormatFloat(float64(v), 'f', -1, 64) 125 return ValueBindVariable(NewDecimal(f)) 126 } 127 128 // StringBindVariable converts a string to a bind var. 129 func StringBindVariable(v string) *querypb.BindVariable { 130 return ValueBindVariable(NewVarChar(v)) 131 } 132 133 // BytesBindVariable converts a []byte to a bind var. 134 func BytesBindVariable(v []byte) *querypb.BindVariable { 135 return &querypb.BindVariable{Type: VarBinary, Value: v} 136 } 137 138 // ValueBindVariable converts a Value to a bind var. 139 func ValueBindVariable(v Value) *querypb.BindVariable { 140 return &querypb.BindVariable{Type: v.typ, Value: v.val} 141 } 142 143 // BuildBindVariable builds a *querypb.BindVariable from a valid input type. 144 func BuildBindVariable(v any) (*querypb.BindVariable, error) { 145 switch v := v.(type) { 146 case string: 147 return StringBindVariable(v), nil 148 case []byte: 149 return BytesBindVariable(v), nil 150 case bool: 151 if v { 152 return Int8BindVariable(1), nil 153 } 154 return Int8BindVariable(0), nil 155 case int: 156 return &querypb.BindVariable{ 157 Type: querypb.Type_INT64, 158 Value: strconv.AppendInt(nil, int64(v), 10), 159 }, nil 160 case int64: 161 return Int64BindVariable(v), nil 162 case uint64: 163 return Uint64BindVariable(v), nil 164 case DecimalFloat: 165 return DecimalBindVariable(v), nil 166 case float64: 167 return Float64BindVariable(v), nil 168 case nil: 169 return NullBindVariable, nil 170 case Value: 171 return ValueBindVariable(v), nil 172 case *querypb.BindVariable: 173 return v, nil 174 case []any: 175 bv := &querypb.BindVariable{ 176 Type: querypb.Type_TUPLE, 177 Values: make([]*querypb.Value, len(v)), 178 } 179 values := make([]querypb.Value, len(v)) 180 for i, lv := range v { 181 lbv, err := BuildBindVariable(lv) 182 if err != nil { 183 return nil, err 184 } 185 values[i].Type = lbv.Type 186 values[i].Value = lbv.Value 187 bv.Values[i] = &values[i] 188 } 189 return bv, nil 190 case []string: 191 bv := &querypb.BindVariable{ 192 Type: querypb.Type_TUPLE, 193 Values: make([]*querypb.Value, len(v)), 194 } 195 values := make([]querypb.Value, len(v)) 196 for i, lv := range v { 197 values[i].Type = querypb.Type_VARCHAR 198 values[i].Value = []byte(lv) 199 bv.Values[i] = &values[i] 200 } 201 return bv, nil 202 case [][]byte: 203 bv := &querypb.BindVariable{ 204 Type: querypb.Type_TUPLE, 205 Values: make([]*querypb.Value, len(v)), 206 } 207 values := make([]querypb.Value, len(v)) 208 for i, lv := range v { 209 values[i].Type = querypb.Type_VARBINARY 210 values[i].Value = lv 211 bv.Values[i] = &values[i] 212 } 213 return bv, nil 214 case []int: 215 bv := &querypb.BindVariable{ 216 Type: querypb.Type_TUPLE, 217 Values: make([]*querypb.Value, len(v)), 218 } 219 values := make([]querypb.Value, len(v)) 220 for i, lv := range v { 221 values[i].Type = querypb.Type_INT64 222 values[i].Value = strconv.AppendInt(nil, int64(lv), 10) 223 bv.Values[i] = &values[i] 224 } 225 return bv, nil 226 case []int64: 227 bv := &querypb.BindVariable{ 228 Type: querypb.Type_TUPLE, 229 Values: make([]*querypb.Value, len(v)), 230 } 231 values := make([]querypb.Value, len(v)) 232 for i, lv := range v { 233 values[i].Type = querypb.Type_INT64 234 values[i].Value = strconv.AppendInt(nil, lv, 10) 235 bv.Values[i] = &values[i] 236 } 237 return bv, nil 238 case []uint64: 239 bv := &querypb.BindVariable{ 240 Type: querypb.Type_TUPLE, 241 Values: make([]*querypb.Value, len(v)), 242 } 243 values := make([]querypb.Value, len(v)) 244 for i, lv := range v { 245 values[i].Type = querypb.Type_UINT64 246 values[i].Value = strconv.AppendUint(nil, lv, 10) 247 bv.Values[i] = &values[i] 248 } 249 return bv, nil 250 case []float64: 251 bv := &querypb.BindVariable{ 252 Type: querypb.Type_TUPLE, 253 Values: make([]*querypb.Value, len(v)), 254 } 255 values := make([]querypb.Value, len(v)) 256 for i, lv := range v { 257 values[i].Type = querypb.Type_FLOAT64 258 values[i].Value = strconv.AppendFloat(nil, lv, 'g', -1, 64) 259 bv.Values[i] = &values[i] 260 } 261 return bv, nil 262 case []Value: 263 bv := &querypb.BindVariable{ 264 Type: querypb.Type_TUPLE, 265 Values: make([]*querypb.Value, len(v)), 266 } 267 values := make([]querypb.Value, len(v)) 268 for i, lv := range v { 269 lbv, err := BuildBindVariable(lv) 270 if err != nil { 271 return nil, err 272 } 273 values[i].Type = lbv.Type 274 values[i].Value = lbv.Value 275 bv.Values[i] = &values[i] 276 } 277 return bv, nil 278 } 279 return nil, fmt.Errorf("type %T not supported as bind var: %v", v, v) 280 } 281 282 // ValidateBindVariables validates a map[string]*querypb.BindVariable. 283 func ValidateBindVariables(bv map[string]*querypb.BindVariable) error { 284 for k, v := range bv { 285 if err := ValidateBindVariable(v); err != nil { 286 return fmt.Errorf("%s: %v", k, err) 287 } 288 } 289 return nil 290 } 291 292 // ValidateBindVariable returns an error if the bind variable has inconsistent 293 // fields. 294 func ValidateBindVariable(bv *querypb.BindVariable) error { 295 if bv == nil { 296 return errors.New("bind variable is nil") 297 } 298 299 if bv.Type == querypb.Type_TUPLE { 300 if len(bv.Values) == 0 { 301 return errors.New("empty tuple is not allowed") 302 } 303 for _, val := range bv.Values { 304 if val.Type == querypb.Type_TUPLE { 305 return errors.New("tuple not allowed inside another tuple") 306 } 307 if err := ValidateBindVariable(&querypb.BindVariable{Type: val.Type, Value: val.Value}); err != nil { 308 return err 309 } 310 } 311 return nil 312 } 313 314 // If NewValue succeeds, the value is valid. 315 _, err := NewValue(bv.Type, bv.Value) 316 return err 317 } 318 319 // BindVariableToValue converts a bind var into a Value. 320 func BindVariableToValue(bv *querypb.BindVariable) (Value, error) { 321 if bv.Type == querypb.Type_TUPLE { 322 return NULL, errors.New("cannot convert a TUPLE bind var into a value") 323 } 324 return MakeTrusted(bv.Type, bv.Value), nil 325 } 326 327 // BindVariablesEqual compares two maps of bind variables. 328 // For protobuf messages we have to use "proto.Equal". 329 func BindVariablesEqual(x, y map[string]*querypb.BindVariable) bool { 330 return proto.Equal(&querypb.BoundQuery{BindVariables: x}, &querypb.BoundQuery{BindVariables: y}) 331 } 332 333 // CopyBindVariables returns a shallow-copy of the given bindVariables map. 334 func CopyBindVariables(bindVariables map[string]*querypb.BindVariable) map[string]*querypb.BindVariable { 335 result := make(map[string]*querypb.BindVariable, len(bindVariables)) 336 for key, value := range bindVariables { 337 result[key] = value 338 } 339 return result 340 } 341 342 // FormatBindVariables returns a string representation of the 343 // bind variables. 344 // 345 // If full is false, then large string or tuple values are truncated 346 // to only print the lengths. 347 // 348 // If asJson is true, then the resulting string is a valid JSON 349 // representation, otherwise it is the golang printed map representation. 350 func FormatBindVariables(bindVariables map[string]*querypb.BindVariable, full, asJSON bool) string { 351 var out map[string]*querypb.BindVariable 352 if full { 353 out = bindVariables 354 } else { 355 // NOTE(szopa): I am getting rid of potentially large bind 356 // variables. 357 out = make(map[string]*querypb.BindVariable) 358 for k, v := range bindVariables { 359 if IsIntegral(v.Type) || IsFloat(v.Type) { 360 out[k] = v 361 } else if v.Type == querypb.Type_TUPLE { 362 out[k] = StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) 363 } else { 364 out[k] = StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) 365 } 366 } 367 } 368 369 if asJSON { 370 var buf bytes.Buffer 371 buf.WriteString("{") 372 first := true 373 for k, v := range out { 374 if !first { 375 buf.WriteString(", ") 376 } else { 377 first = false 378 } 379 if IsIntegral(v.Type) || IsFloat(v.Type) { 380 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) 381 } else { 382 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) 383 } 384 } 385 buf.WriteString("}") 386 return buf.String() 387 } 388 389 return fmt.Sprintf("%v", out) 390 }