vitess.io/vitess@v0.16.2/go/sqltypes/value.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 implements interfaces and types that represent SQL values. 18 package sqltypes 19 20 import ( 21 "encoding/base64" 22 "encoding/hex" 23 "encoding/json" 24 "errors" 25 "fmt" 26 "math/big" 27 "strconv" 28 "strings" 29 30 "vitess.io/vitess/go/bytes2" 31 "vitess.io/vitess/go/hack" 32 33 querypb "vitess.io/vitess/go/vt/proto/query" 34 "vitess.io/vitess/go/vt/proto/vtrpc" 35 vtrpcpb "vitess.io/vitess/go/vt/proto/vtrpc" 36 "vitess.io/vitess/go/vt/vterrors" 37 ) 38 39 var ( 40 // NULL represents the NULL value. 41 NULL = Value{} 42 43 // DontEscape tells you if a character should not be escaped. 44 DontEscape = byte(255) 45 46 nullstr = []byte("null") 47 48 // ErrIncompatibleTypeCast indicates a casting problem 49 ErrIncompatibleTypeCast = errors.New("Cannot convert value to desired type") 50 ) 51 52 type ( 53 // BinWriter interface is used for encoding values. 54 // Types like bytes.Buffer conform to this interface. 55 // We expect the writer objects to be in-memory buffers. 56 // So, we don't expect the write operations to fail. 57 BinWriter interface { 58 Write([]byte) (int, error) 59 } 60 61 // Value can store any SQL value. If the value represents 62 // an integral type, the bytes are always stored as a canonical 63 // representation that matches how MySQL returns such values. 64 Value struct { 65 typ querypb.Type 66 val []byte 67 } 68 69 Row = []Value 70 ) 71 72 // NewValue builds a Value using typ and val. If the value and typ 73 // don't match, it returns an error. 74 func NewValue(typ querypb.Type, val []byte) (v Value, err error) { 75 switch { 76 case IsSigned(typ): 77 if _, err := strconv.ParseInt(string(val), 10, 64); err != nil { 78 return NULL, err 79 } 80 return MakeTrusted(typ, val), nil 81 case IsUnsigned(typ): 82 if _, err := strconv.ParseUint(string(val), 10, 64); err != nil { 83 return NULL, err 84 } 85 return MakeTrusted(typ, val), nil 86 case IsFloat(typ) || typ == Decimal: 87 if _, err := strconv.ParseFloat(string(val), 64); err != nil { 88 return NULL, err 89 } 90 return MakeTrusted(typ, val), nil 91 case IsQuoted(typ) || typ == Bit || typ == HexNum || typ == HexVal || typ == Null || typ == BitNum: 92 return MakeTrusted(typ, val), nil 93 } 94 // All other types are unsafe or invalid. 95 return NULL, fmt.Errorf("invalid type specified for MakeValue: %v", typ) 96 } 97 98 // MakeTrusted makes a new Value based on the type. 99 // This function should only be used if you know the value 100 // and type conform to the rules. Every place this function is 101 // called, a comment is needed that explains why it's justified. 102 // Exceptions: The current package and mysql package do not need 103 // comments. Other packages can also use the function to create 104 // VarBinary or VarChar values. 105 func MakeTrusted(typ querypb.Type, val []byte) Value { 106 107 if typ == Null { 108 return NULL 109 } 110 111 return Value{typ: typ, val: val} 112 } 113 114 // NewHexNum builds an Hex Value. 115 func NewHexNum(v []byte) Value { 116 return MakeTrusted(HexNum, v) 117 } 118 119 // NewHexVal builds a HexVal Value. 120 func NewHexVal(v []byte) Value { 121 return MakeTrusted(HexVal, v) 122 } 123 124 // NewBitNum builds a BitNum Value. 125 func NewBitNum(v []byte) Value { 126 return MakeTrusted(BitNum, v) 127 } 128 129 // NewInt64 builds an Int64 Value. 130 func NewInt64(v int64) Value { 131 return MakeTrusted(Int64, strconv.AppendInt(nil, v, 10)) 132 } 133 134 // NewInt8 builds an Int8 Value. 135 func NewInt8(v int8) Value { 136 return MakeTrusted(Int8, strconv.AppendInt(nil, int64(v), 10)) 137 } 138 139 // NewInt32 builds an Int64 Value. 140 func NewInt32(v int32) Value { 141 return MakeTrusted(Int32, strconv.AppendInt(nil, int64(v), 10)) 142 } 143 144 // NewUint64 builds an Uint64 Value. 145 func NewUint64(v uint64) Value { 146 return MakeTrusted(Uint64, strconv.AppendUint(nil, v, 10)) 147 } 148 149 // NewUint32 builds an Uint32 Value. 150 func NewUint32(v uint32) Value { 151 return MakeTrusted(Uint32, strconv.AppendUint(nil, uint64(v), 10)) 152 } 153 154 // NewFloat64 builds an Float64 Value. 155 func NewFloat64(v float64) Value { 156 return MakeTrusted(Float64, strconv.AppendFloat(nil, v, 'g', -1, 64)) 157 } 158 159 // NewVarChar builds a VarChar Value. 160 func NewVarChar(v string) Value { 161 return MakeTrusted(VarChar, []byte(v)) 162 } 163 164 // NewVarBinary builds a VarBinary Value. 165 // The input is a string because it's the most common use case. 166 func NewVarBinary(v string) Value { 167 return MakeTrusted(VarBinary, []byte(v)) 168 } 169 170 // NewDate builds a Date value. 171 func NewDate(v string) Value { 172 return MakeTrusted(Date, []byte(v)) 173 } 174 175 // NewTime builds a Time value. 176 func NewTime(v string) Value { 177 return MakeTrusted(Time, []byte(v)) 178 } 179 180 // NewTimestamp builds a Timestamp value. 181 func NewTimestamp(v string) Value { 182 return MakeTrusted(Timestamp, []byte(v)) 183 } 184 185 // NewDatetime builds a Datetime value. 186 func NewDatetime(v string) Value { 187 return MakeTrusted(Datetime, []byte(v)) 188 } 189 190 // NewDecimal builds a Decimal value. 191 func NewDecimal(v string) Value { 192 return MakeTrusted(Decimal, []byte(v)) 193 } 194 195 // NewIntegral builds an integral type from a string representation. 196 // The type will be Int64 or Uint64. Int64 will be preferred where possible. 197 func NewIntegral(val string) (n Value, err error) { 198 signed, err := strconv.ParseInt(val, 0, 64) 199 if err == nil { 200 return MakeTrusted(Int64, strconv.AppendInt(nil, signed, 10)), nil 201 } 202 unsigned, err := strconv.ParseUint(val, 0, 64) 203 if err != nil { 204 return Value{}, err 205 } 206 return MakeTrusted(Uint64, strconv.AppendUint(nil, unsigned, 10)), nil 207 } 208 209 // InterfaceToValue builds a value from a go type. 210 // Supported types are nil, int64, uint64, float64, 211 // string and []byte. 212 // This function is deprecated. Use the type-specific 213 // functions instead. 214 func InterfaceToValue(goval any) (Value, error) { 215 switch goval := goval.(type) { 216 case nil: 217 return NULL, nil 218 case []byte: 219 return MakeTrusted(VarBinary, goval), nil 220 case int64: 221 return NewInt64(goval), nil 222 case uint64: 223 return NewUint64(goval), nil 224 case float64: 225 return NewFloat64(goval), nil 226 case string: 227 return NewVarChar(goval), nil 228 default: 229 return NULL, fmt.Errorf("unexpected type %T: %v", goval, goval) 230 } 231 } 232 233 // Type returns the type of Value. 234 func (v Value) Type() querypb.Type { 235 return v.typ 236 } 237 238 // Raw returns the internal representation of the value. For newer types, 239 // this may not match MySQL's representation. 240 func (v Value) Raw() []byte { 241 return v.val 242 } 243 244 // RawStr returns the internal representation of the value as a string instead 245 // of a byte slice. This is equivalent to calling `string(v.Raw())` but does 246 // not allocate. 247 func (v Value) RawStr() string { 248 return hack.String(v.val) 249 } 250 251 // ToBytes returns the value as MySQL would return it as []byte. 252 // In contrast, Raw returns the internal representation of the Value, which may not 253 // match MySQL's representation for hex encoded binary data or newer types. 254 // If the value is not convertible like in the case of Expression, it returns an error. 255 func (v Value) ToBytes() ([]byte, error) { 256 switch v.typ { 257 case Expression: 258 return nil, vterrors.New(vtrpcpb.Code_INVALID_ARGUMENT, "expression cannot be converted to bytes") 259 case HexVal: // TODO: all the decode below have problem when decoding odd number of bytes. This needs to be fixed. 260 return v.decodeHexVal() 261 case HexNum: 262 return v.decodeHexNum() 263 case BitNum: 264 return v.decodeBitNum() 265 default: 266 return v.val, nil 267 } 268 } 269 270 // Len returns the length. 271 func (v Value) Len() int { 272 return len(v.val) 273 } 274 275 // ToInt64 returns the value as MySQL would return it as a int64. 276 func (v Value) ToInt64() (int64, error) { 277 if !v.IsIntegral() { 278 return 0, ErrIncompatibleTypeCast 279 } 280 281 return strconv.ParseInt(v.RawStr(), 10, 64) 282 } 283 284 // ToFloat64 returns the value as MySQL would return it as a float64. 285 func (v Value) ToFloat64() (float64, error) { 286 if !IsNumber(v.typ) { 287 return 0, ErrIncompatibleTypeCast 288 } 289 290 return strconv.ParseFloat(v.RawStr(), 64) 291 } 292 293 // ToUint64 returns the value as MySQL would return it as a uint64. 294 func (v Value) ToUint64() (uint64, error) { 295 if !v.IsIntegral() { 296 return 0, ErrIncompatibleTypeCast 297 } 298 299 return strconv.ParseUint(v.RawStr(), 10, 64) 300 } 301 302 // ToBool returns the value as a bool value 303 func (v Value) ToBool() (bool, error) { 304 i, err := v.ToInt64() 305 if err != nil { 306 return false, err 307 } 308 switch i { 309 case 0: 310 return false, nil 311 case 1: 312 return true, nil 313 } 314 return false, ErrIncompatibleTypeCast 315 } 316 317 // ToString returns the value as MySQL would return it as string. 318 // If the value is not convertible like in the case of Expression, it returns nil. 319 func (v Value) ToString() string { 320 if v.typ == Expression { 321 return "" 322 } 323 return hack.String(v.val) 324 } 325 326 // String returns a printable version of the value. 327 func (v Value) String() string { 328 if v.typ == Null { 329 return "NULL" 330 } 331 if v.IsQuoted() || v.typ == Bit { 332 return fmt.Sprintf("%v(%q)", v.typ, v.val) 333 } 334 return fmt.Sprintf("%v(%s)", v.typ, v.val) 335 } 336 337 // EncodeSQL encodes the value into an SQL statement. Can be binary. 338 func (v Value) EncodeSQL(b BinWriter) { 339 switch { 340 case v.typ == Null: 341 b.Write(nullstr) 342 case v.IsQuoted(): 343 encodeBytesSQL(v.val, b) 344 case v.typ == Bit: 345 encodeBytesSQLBits(v.val, b) 346 default: 347 b.Write(v.val) 348 } 349 } 350 351 // EncodeSQLStringBuilder is identical to EncodeSQL but it takes a strings.Builder 352 // as its writer, so it can be inlined for performance. 353 func (v Value) EncodeSQLStringBuilder(b *strings.Builder) { 354 switch { 355 case v.typ == Null: 356 b.Write(nullstr) 357 case v.IsQuoted(): 358 encodeBytesSQLStringBuilder(v.val, b) 359 case v.typ == Bit: 360 encodeBytesSQLBits(v.val, b) 361 default: 362 b.Write(v.val) 363 } 364 } 365 366 // EncodeSQLBytes2 is identical to EncodeSQL but it takes a bytes2.Buffer 367 // as its writer, so it can be inlined for performance. 368 func (v Value) EncodeSQLBytes2(b *bytes2.Buffer) { 369 switch { 370 case v.typ == Null: 371 b.Write(nullstr) 372 case v.IsQuoted(): 373 encodeBytesSQLBytes2(v.val, b) 374 case v.typ == Bit: 375 encodeBytesSQLBits(v.val, b) 376 default: 377 b.Write(v.val) 378 } 379 } 380 381 // EncodeASCII encodes the value using 7-bit clean ascii bytes. 382 func (v Value) EncodeASCII(b BinWriter) { 383 switch { 384 case v.typ == Null: 385 b.Write(nullstr) 386 case v.IsQuoted() || v.typ == Bit: 387 encodeBytesASCII(v.val, b) 388 default: 389 b.Write(v.val) 390 } 391 } 392 393 // IsNull returns true if Value is null. 394 func (v Value) IsNull() bool { 395 return v.typ == Null 396 } 397 398 // IsIntegral returns true if Value is an integral. 399 func (v Value) IsIntegral() bool { 400 return IsIntegral(v.typ) 401 } 402 403 // IsSigned returns true if Value is a signed integral. 404 func (v Value) IsSigned() bool { 405 return IsSigned(v.typ) 406 } 407 408 // IsUnsigned returns true if Value is an unsigned integral. 409 func (v Value) IsUnsigned() bool { 410 return IsUnsigned(v.typ) 411 } 412 413 // IsFloat returns true if Value is a float. 414 func (v Value) IsFloat() bool { 415 return IsFloat(v.typ) 416 } 417 418 // IsQuoted returns true if Value must be SQL-quoted. 419 func (v Value) IsQuoted() bool { 420 return IsQuoted(v.typ) 421 } 422 423 // IsText returns true if Value is a collatable text. 424 func (v Value) IsText() bool { 425 return IsText(v.typ) 426 } 427 428 // IsBinary returns true if Value is binary. 429 func (v Value) IsBinary() bool { 430 return IsBinary(v.typ) 431 } 432 433 // IsDateTime returns true if Value is datetime. 434 func (v Value) IsDateTime() bool { 435 dt := int(querypb.Type_DATETIME) 436 return int(v.typ)&dt == dt 437 } 438 439 // IsComparable returns true if the Value is null safe comparable without collation information. 440 func (v *Value) IsComparable() bool { 441 if v.typ == Null || IsNumber(v.typ) || IsBinary(v.typ) { 442 return true 443 } 444 switch v.typ { 445 case Timestamp, Date, Time, Datetime, Enum, Set, TypeJSON, Bit: 446 return true 447 } 448 return false 449 } 450 451 // MarshalJSON should only be used for testing. 452 // It's not a complete implementation. 453 func (v Value) MarshalJSON() ([]byte, error) { 454 switch { 455 case v.IsQuoted() || v.typ == Bit: 456 return json.Marshal(v.ToString()) 457 case v.typ == Null: 458 return nullstr, nil 459 } 460 return v.val, nil 461 } 462 463 // UnmarshalJSON should only be used for testing. 464 // It's not a complete implementation. 465 func (v *Value) UnmarshalJSON(b []byte) error { 466 if len(b) == 0 { 467 return fmt.Errorf("error unmarshaling empty bytes") 468 } 469 var val any 470 var err error 471 switch b[0] { 472 case '-': 473 var ival int64 474 err = json.Unmarshal(b, &ival) 475 val = ival 476 case '"': 477 var bval []byte 478 err = json.Unmarshal(b, &bval) 479 val = bval 480 case 'n': // null 481 err = json.Unmarshal(b, &val) 482 default: 483 var uval uint64 484 err = json.Unmarshal(b, &uval) 485 val = uval 486 } 487 if err != nil { 488 return err 489 } 490 *v, err = InterfaceToValue(val) 491 return err 492 } 493 494 // decodeHexVal decodes the SQL hex value of the form x'A1' into a byte 495 // array matching what MySQL would return when querying the column where 496 // an INSERT was performed with x'A1' having been specified as a value 497 func (v *Value) decodeHexVal() ([]byte, error) { 498 if len(v.val) < 3 || (v.val[0] != 'x' && v.val[0] != 'X') || v.val[1] != '\'' || v.val[len(v.val)-1] != '\'' { 499 return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex value: %v", v.val) 500 } 501 hexBytes := v.val[2 : len(v.val)-1] 502 decodedHexBytes, err := hex.DecodeString(string(hexBytes)) 503 if err != nil { 504 return nil, err 505 } 506 return decodedHexBytes, nil 507 } 508 509 // decodeHexNum decodes the SQL hex value of the form 0xA1 into a byte 510 // array matching what MySQL would return when querying the column where 511 // an INSERT was performed with 0xA1 having been specified as a value 512 func (v *Value) decodeHexNum() ([]byte, error) { 513 if len(v.val) < 3 || v.val[0] != '0' || v.val[1] != 'x' { 514 return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid hex number: %v", v.val) 515 } 516 hexBytes := v.val[2:] 517 decodedHexBytes, err := hex.DecodeString(string(hexBytes)) 518 if err != nil { 519 return nil, err 520 } 521 return decodedHexBytes, nil 522 } 523 524 // decodeBitNum decodes the SQL bit value of the form 0b101 into a byte 525 // array matching what MySQL would return when querying the column where 526 // an INSERT was performed with 0x5 having been specified as a value 527 func (v *Value) decodeBitNum() ([]byte, error) { 528 if len(v.val) < 3 || v.val[0] != '0' || v.val[1] != 'b' { 529 return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid bit number: %v", v.val) 530 } 531 var i big.Int 532 _, ok := i.SetString(string(v.val), 0) 533 if !ok { 534 return nil, vterrors.Errorf(vtrpc.Code_INVALID_ARGUMENT, "invalid bit number: %v", v.val) 535 } 536 return i.Bytes(), nil 537 } 538 539 func encodeBytesSQL(val []byte, b BinWriter) { 540 buf := &bytes2.Buffer{} 541 encodeBytesSQLBytes2(val, buf) 542 b.Write(buf.Bytes()) 543 } 544 545 func encodeBytesSQLBytes2(val []byte, buf *bytes2.Buffer) { 546 buf.WriteByte('\'') 547 for idx, ch := range val { 548 // If \% or \_ is present, we want to keep them as is, and don't want to escape \ again 549 if ch == '\\' && idx+1 < len(val) && (val[idx+1] == '%' || val[idx+1] == '_') { 550 buf.WriteByte(ch) 551 continue 552 } 553 if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape { 554 buf.WriteByte(ch) 555 } else { 556 buf.WriteByte('\\') 557 buf.WriteByte(encodedChar) 558 } 559 } 560 buf.WriteByte('\'') 561 } 562 563 func encodeBytesSQLStringBuilder(val []byte, buf *strings.Builder) { 564 buf.WriteByte('\'') 565 for idx, ch := range val { 566 // If \% or \_ is present, we want to keep them as is, and don't want to escape \ again 567 if ch == '\\' && idx+1 < len(val) && (val[idx+1] == '%' || val[idx+1] == '_') { 568 buf.WriteByte(ch) 569 continue 570 } 571 if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape { 572 buf.WriteByte(ch) 573 } else { 574 buf.WriteByte('\\') 575 buf.WriteByte(encodedChar) 576 } 577 } 578 buf.WriteByte('\'') 579 } 580 581 // BufEncodeStringSQL encodes the string into a strings.Builder 582 func BufEncodeStringSQL(buf *strings.Builder, val string) { 583 buf.WriteByte('\'') 584 for idx, ch := range val { 585 if ch > 255 { 586 buf.WriteRune(ch) 587 continue 588 } 589 // If \% or \_ is present, we want to keep them as is, and don't want to escape \ again 590 if ch == '\\' && idx+1 < len(val) && (val[idx+1] == '%' || val[idx+1] == '_') { 591 buf.WriteRune(ch) 592 continue 593 } 594 if encodedChar := SQLEncodeMap[ch]; encodedChar == DontEscape { 595 buf.WriteRune(ch) 596 } else { 597 buf.WriteByte('\\') 598 buf.WriteByte(encodedChar) 599 } 600 } 601 buf.WriteByte('\'') 602 } 603 604 // EncodeStringSQL encodes the string as a SQL string. 605 func EncodeStringSQL(val string) string { 606 var buf strings.Builder 607 BufEncodeStringSQL(&buf, val) 608 return buf.String() 609 } 610 611 func encodeBytesSQLBits(val []byte, b BinWriter) { 612 fmt.Fprint(b, "b'") 613 for _, ch := range val { 614 fmt.Fprintf(b, "%08b", ch) 615 } 616 fmt.Fprint(b, "'") 617 } 618 619 func encodeBytesASCII(val []byte, b BinWriter) { 620 buf := &bytes2.Buffer{} 621 buf.WriteByte('\'') 622 encoder := base64.NewEncoder(base64.StdEncoding, buf) 623 encoder.Write(val) 624 encoder.Close() 625 buf.WriteByte('\'') 626 b.Write(buf.Bytes()) 627 } 628 629 // SQLEncodeMap specifies how to escape binary data with '\'. 630 // Complies to https://dev.mysql.com/doc/refman/5.7/en/string-literals.html 631 // Handling escaping of % and _ is different than other characters. 632 // When escaped in a like clause, they are supposed to be treated as literals 633 // Everywhere else, they evaluate to strings '\%' and '\_' respectively. 634 // In Vitess, the way we are choosing to handle this behaviour is to always 635 // preserve the escaping of % and _ as is in all the places and handle it like MySQL 636 // in our evaluation engine for Like. 637 var SQLEncodeMap [256]byte 638 639 // SQLDecodeMap is the reverse of SQLEncodeMap 640 var SQLDecodeMap [256]byte 641 642 var encodeRef = map[byte]byte{ 643 '\x00': '0', 644 '\'': '\'', 645 '"': '"', 646 '\b': 'b', 647 '\n': 'n', 648 '\r': 'r', 649 '\t': 't', 650 26: 'Z', // ctl-Z 651 '\\': '\\', 652 } 653 654 func init() { 655 for i := range SQLEncodeMap { 656 SQLEncodeMap[i] = DontEscape 657 SQLDecodeMap[i] = DontEscape 658 } 659 for i := range SQLEncodeMap { 660 if to, ok := encodeRef[byte(i)]; ok { 661 SQLEncodeMap[byte(i)] = to 662 SQLDecodeMap[to] = byte(i) 663 } 664 } 665 }