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