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  }