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