github.com/vedadiyan/sqlparser@v1.0.0/pkg/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/vedadiyan/sqlparser/pkg/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 uint: 161 return &querypb.BindVariable{ 162 Type: querypb.Type_UINT64, 163 Value: strconv.AppendUint(nil, uint64(v), 10), 164 }, nil 165 case int32: 166 return Int32BindVariable(v), nil 167 case uint32: 168 return Uint32BindVariable(v), nil 169 case int64: 170 return Int64BindVariable(v), nil 171 case uint64: 172 return Uint64BindVariable(v), nil 173 case DecimalFloat: 174 return DecimalBindVariable(v), nil 175 case float64: 176 return Float64BindVariable(v), nil 177 case nil: 178 return NullBindVariable, nil 179 case Value: 180 return ValueBindVariable(v), nil 181 case *querypb.BindVariable: 182 return v, nil 183 case []any: 184 bv := &querypb.BindVariable{ 185 Type: querypb.Type_TUPLE, 186 Values: make([]*querypb.Value, len(v)), 187 } 188 values := make([]querypb.Value, len(v)) 189 for i, lv := range v { 190 lbv, err := BuildBindVariable(lv) 191 if err != nil { 192 return nil, err 193 } 194 values[i].Type = lbv.Type 195 values[i].Value = lbv.Value 196 bv.Values[i] = &values[i] 197 } 198 return bv, nil 199 case []string: 200 bv := &querypb.BindVariable{ 201 Type: querypb.Type_TUPLE, 202 Values: make([]*querypb.Value, len(v)), 203 } 204 values := make([]querypb.Value, len(v)) 205 for i, lv := range v { 206 values[i].Type = querypb.Type_VARCHAR 207 values[i].Value = []byte(lv) 208 bv.Values[i] = &values[i] 209 } 210 return bv, nil 211 case [][]byte: 212 bv := &querypb.BindVariable{ 213 Type: querypb.Type_TUPLE, 214 Values: make([]*querypb.Value, len(v)), 215 } 216 values := make([]querypb.Value, len(v)) 217 for i, lv := range v { 218 values[i].Type = querypb.Type_VARBINARY 219 values[i].Value = lv 220 bv.Values[i] = &values[i] 221 } 222 return bv, nil 223 case []int: 224 bv := &querypb.BindVariable{ 225 Type: querypb.Type_TUPLE, 226 Values: make([]*querypb.Value, len(v)), 227 } 228 values := make([]querypb.Value, len(v)) 229 for i, lv := range v { 230 values[i].Type = querypb.Type_INT64 231 values[i].Value = strconv.AppendInt(nil, int64(lv), 10) 232 bv.Values[i] = &values[i] 233 } 234 return bv, nil 235 case []uint: 236 bv := &querypb.BindVariable{ 237 Type: querypb.Type_TUPLE, 238 Values: make([]*querypb.Value, len(v)), 239 } 240 values := make([]querypb.Value, len(v)) 241 for i, lv := range v { 242 values[i].Type = querypb.Type_UINT64 243 values[i].Value = strconv.AppendInt(nil, int64(lv), 10) 244 bv.Values[i] = &values[i] 245 } 246 return bv, nil 247 case []int32: 248 bv := &querypb.BindVariable{ 249 Type: querypb.Type_TUPLE, 250 Values: make([]*querypb.Value, len(v)), 251 } 252 values := make([]querypb.Value, len(v)) 253 for i, lv := range v { 254 values[i].Type = querypb.Type_INT32 255 values[i].Value = strconv.AppendInt(nil, int64(lv), 10) 256 bv.Values[i] = &values[i] 257 } 258 return bv, nil 259 case []uint32: 260 bv := &querypb.BindVariable{ 261 Type: querypb.Type_TUPLE, 262 Values: make([]*querypb.Value, len(v)), 263 } 264 values := make([]querypb.Value, len(v)) 265 for i, lv := range v { 266 values[i].Type = querypb.Type_UINT32 267 values[i].Value = strconv.AppendUint(nil, uint64(lv), 10) 268 bv.Values[i] = &values[i] 269 } 270 return bv, nil 271 case []int64: 272 bv := &querypb.BindVariable{ 273 Type: querypb.Type_TUPLE, 274 Values: make([]*querypb.Value, len(v)), 275 } 276 values := make([]querypb.Value, len(v)) 277 for i, lv := range v { 278 values[i].Type = querypb.Type_INT64 279 values[i].Value = strconv.AppendInt(nil, lv, 10) 280 bv.Values[i] = &values[i] 281 } 282 return bv, nil 283 case []uint64: 284 bv := &querypb.BindVariable{ 285 Type: querypb.Type_TUPLE, 286 Values: make([]*querypb.Value, len(v)), 287 } 288 values := make([]querypb.Value, len(v)) 289 for i, lv := range v { 290 values[i].Type = querypb.Type_UINT64 291 values[i].Value = strconv.AppendUint(nil, lv, 10) 292 bv.Values[i] = &values[i] 293 } 294 return bv, nil 295 case []float64: 296 bv := &querypb.BindVariable{ 297 Type: querypb.Type_TUPLE, 298 Values: make([]*querypb.Value, len(v)), 299 } 300 values := make([]querypb.Value, len(v)) 301 for i, lv := range v { 302 values[i].Type = querypb.Type_FLOAT64 303 values[i].Value = strconv.AppendFloat(nil, lv, 'g', -1, 64) 304 bv.Values[i] = &values[i] 305 } 306 return bv, nil 307 case []Value: 308 bv := &querypb.BindVariable{ 309 Type: querypb.Type_TUPLE, 310 Values: make([]*querypb.Value, len(v)), 311 } 312 values := make([]querypb.Value, len(v)) 313 for i, lv := range v { 314 lbv, err := BuildBindVariable(lv) 315 if err != nil { 316 return nil, err 317 } 318 values[i].Type = lbv.Type 319 values[i].Value = lbv.Value 320 bv.Values[i] = &values[i] 321 } 322 return bv, nil 323 } 324 return nil, fmt.Errorf("type %T not supported as bind var: %v", v, v) 325 } 326 327 // ValidateBindVariables validates a map[string]*querypb.BindVariable. 328 func ValidateBindVariables(bv map[string]*querypb.BindVariable) error { 329 for k, v := range bv { 330 if err := ValidateBindVariable(v); err != nil { 331 return fmt.Errorf("%s: %v", k, err) 332 } 333 } 334 return nil 335 } 336 337 // ValidateBindVariable returns an error if the bind variable has inconsistent 338 // fields. 339 func ValidateBindVariable(bv *querypb.BindVariable) error { 340 if bv == nil { 341 return errors.New("bind variable is nil") 342 } 343 344 if bv.Type == querypb.Type_TUPLE { 345 if len(bv.Values) == 0 { 346 return errors.New("empty tuple is not allowed") 347 } 348 for _, val := range bv.Values { 349 if val.Type == querypb.Type_TUPLE { 350 return errors.New("tuple not allowed inside another tuple") 351 } 352 if err := ValidateBindVariable(&querypb.BindVariable{Type: val.Type, Value: val.Value}); err != nil { 353 return err 354 } 355 } 356 return nil 357 } 358 359 // If NewValue succeeds, the value is valid. 360 _, err := NewValue(bv.Type, bv.Value) 361 return err 362 } 363 364 // BindVariableToValue converts a bind var into a Value. 365 func BindVariableToValue(bv *querypb.BindVariable) (Value, error) { 366 if bv.Type == querypb.Type_TUPLE { 367 return NULL, errors.New("cannot convert a TUPLE bind var into a value") 368 } 369 return MakeTrusted(bv.Type, bv.Value), nil 370 } 371 372 // BindVariablesEqual compares two maps of bind variables. 373 // For protobuf messages we have to use "proto.Equal". 374 func BindVariablesEqual(x, y map[string]*querypb.BindVariable) bool { 375 return proto.Equal(&querypb.BoundQuery{BindVariables: x}, &querypb.BoundQuery{BindVariables: y}) 376 } 377 378 // CopyBindVariables returns a shallow-copy of the given bindVariables map. 379 func CopyBindVariables(bindVariables map[string]*querypb.BindVariable) map[string]*querypb.BindVariable { 380 result := make(map[string]*querypb.BindVariable, len(bindVariables)) 381 for key, value := range bindVariables { 382 result[key] = value 383 } 384 return result 385 } 386 387 // FormatBindVariables returns a string representation of the 388 // bind variables. 389 // 390 // If full is false, then large string or tuple values are truncated 391 // to only print the lengths. 392 // 393 // If asJson is true, then the resulting string is a valid JSON 394 // representation, otherwise it is the golang printed map representation. 395 func FormatBindVariables(bindVariables map[string]*querypb.BindVariable, full, asJSON bool) string { 396 var out map[string]*querypb.BindVariable 397 if full { 398 out = bindVariables 399 } else { 400 // NOTE(szopa): I am getting rid of potentially large bind 401 // variables. 402 out = make(map[string]*querypb.BindVariable) 403 for k, v := range bindVariables { 404 if IsIntegral(v.Type) || IsFloat(v.Type) { 405 out[k] = v 406 } else if v.Type == querypb.Type_TUPLE { 407 out[k] = StringBindVariable(fmt.Sprintf("%v items", len(v.Values))) 408 } else { 409 out[k] = StringBindVariable(fmt.Sprintf("%v bytes", len(v.Value))) 410 } 411 } 412 } 413 414 if asJSON { 415 var buf bytes.Buffer 416 buf.WriteString("{") 417 first := true 418 for k, v := range out { 419 if !first { 420 buf.WriteString(", ") 421 } else { 422 first = false 423 } 424 if IsIntegral(v.Type) || IsFloat(v.Type) { 425 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %v}", k, v.Type, string(v.Value)) 426 } else { 427 fmt.Fprintf(&buf, "%q: {\"type\": %q, \"value\": %q}", k, v.Type, string(v.Value)) 428 } 429 } 430 buf.WriteString("}") 431 return buf.String() 432 } 433 434 return fmt.Sprintf("%v", out) 435 }