github.com/pingcap/tidb/parser@v0.0.0-20231013125129-93a834a6bf8d/test_driver/test_driver_datum.go (about)

     1  // Copyright 2019 PingCAP, Inc.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // See the License for the specific language governing permissions and
    12  // limitations under the License.
    13  
    14  //go:build !codes
    15  // +build !codes
    16  
    17  package test_driver
    18  
    19  import (
    20  	"bytes"
    21  	"encoding/hex"
    22  	"fmt"
    23  	"math"
    24  	"strconv"
    25  	"strings"
    26  
    27  	"github.com/pingcap/errors"
    28  	"github.com/pingcap/tidb/parser/charset"
    29  	"github.com/pingcap/tidb/parser/mysql"
    30  	"github.com/pingcap/tidb/parser/types"
    31  )
    32  
    33  // Kind constants.
    34  const (
    35  	KindNull          byte = 0
    36  	KindInt64         byte = 1
    37  	KindUint64        byte = 2
    38  	KindFloat32       byte = 3
    39  	KindFloat64       byte = 4
    40  	KindString        byte = 5
    41  	KindBytes         byte = 6
    42  	KindBinaryLiteral byte = 7 // Used for BIT / HEX literals.
    43  	KindMysqlDecimal  byte = 8
    44  	KindMysqlDuration byte = 9
    45  	KindMysqlEnum     byte = 10
    46  	KindMysqlBit      byte = 11 // Used for BIT table column values.
    47  	KindMysqlSet      byte = 12
    48  	KindMysqlTime     byte = 13
    49  	KindInterface     byte = 14
    50  	KindMinNotNull    byte = 15
    51  	KindMaxValue      byte = 16
    52  	KindRaw           byte = 17
    53  	KindMysqlJSON     byte = 18
    54  )
    55  
    56  // Datum is a data box holds different kind of data.
    57  // It has better performance and is easier to use than `interface{}`.
    58  type Datum struct {
    59  	k byte        // datum kind.
    60  	i int64       // i can hold int64 uint64 float64 values.
    61  	b []byte      // b can hold string or []byte values.
    62  	x interface{} // x hold all other types.
    63  }
    64  
    65  // Kind gets the kind of the datum.
    66  func (d *Datum) Kind() byte {
    67  	return d.k
    68  }
    69  
    70  // GetInt64 gets int64 value.
    71  func (d *Datum) GetInt64() int64 {
    72  	return d.i
    73  }
    74  
    75  // SetInt64 sets int64 value.
    76  func (d *Datum) SetInt64(i int64) {
    77  	d.k = KindInt64
    78  	d.i = i
    79  }
    80  
    81  // GetUint64 gets uint64 value.
    82  func (d *Datum) GetUint64() uint64 {
    83  	return uint64(d.i)
    84  }
    85  
    86  // SetUint64 sets uint64 value.
    87  func (d *Datum) SetUint64(i uint64) {
    88  	d.k = KindUint64
    89  	d.i = int64(i)
    90  }
    91  
    92  // GetFloat64 gets float64 value.
    93  func (d *Datum) GetFloat64() float64 {
    94  	return math.Float64frombits(uint64(d.i))
    95  }
    96  
    97  // SetFloat64 sets float64 value.
    98  func (d *Datum) SetFloat64(f float64) {
    99  	d.k = KindFloat64
   100  	d.i = int64(math.Float64bits(f))
   101  }
   102  
   103  // GetFloat32 gets float32 value.
   104  func (d *Datum) GetFloat32() float32 {
   105  	return float32(math.Float64frombits(uint64(d.i)))
   106  }
   107  
   108  // SetFloat32 sets float32 value.
   109  func (d *Datum) SetFloat32(f float32) {
   110  	d.k = KindFloat32
   111  	d.i = int64(math.Float64bits(float64(f)))
   112  }
   113  
   114  // GetString gets string value.
   115  func (d *Datum) GetString() string {
   116  	return string(d.b)
   117  }
   118  
   119  // SetString sets string value.
   120  func (d *Datum) SetString(s string) {
   121  	d.k = KindString
   122  	d.b = []byte(s)
   123  }
   124  
   125  // GetBytes gets bytes value.
   126  func (d *Datum) GetBytes() []byte {
   127  	return d.b
   128  }
   129  
   130  // SetBytes sets bytes value to datum.
   131  func (d *Datum) SetBytes(b []byte) {
   132  	d.k = KindBytes
   133  	d.b = b
   134  }
   135  
   136  // SetBytesAsString sets bytes value to datum as string type.
   137  func (d *Datum) SetBytesAsString(b []byte) {
   138  	d.k = KindString
   139  	d.b = b
   140  }
   141  
   142  // GetInterface gets interface value.
   143  func (d *Datum) GetInterface() interface{} {
   144  	return d.x
   145  }
   146  
   147  // SetInterface sets interface to datum.
   148  func (d *Datum) SetInterface(x interface{}) {
   149  	d.k = KindInterface
   150  	d.x = x
   151  }
   152  
   153  // SetNull sets datum to nil.
   154  func (d *Datum) SetNull() {
   155  	d.k = KindNull
   156  	d.x = nil
   157  }
   158  
   159  // GetBinaryLiteral gets Bit value
   160  func (d *Datum) GetBinaryLiteral() BinaryLiteral {
   161  	return d.b
   162  }
   163  
   164  // SetBinaryLiteral sets Bit value
   165  func (d *Datum) SetBinaryLiteral(b BinaryLiteral) {
   166  	d.k = KindBinaryLiteral
   167  	d.b = b
   168  }
   169  
   170  // GetMysqlDecimal gets decimal value
   171  func (d *Datum) GetMysqlDecimal() *MyDecimal {
   172  	return d.x.(*MyDecimal)
   173  }
   174  
   175  // SetMysqlDecimal sets decimal value
   176  func (d *Datum) SetMysqlDecimal(b *MyDecimal) {
   177  	d.k = KindMysqlDecimal
   178  	d.x = b
   179  }
   180  
   181  // GetValue gets the value of the datum of any kind.
   182  func (d *Datum) GetValue() interface{} {
   183  	switch d.k {
   184  	case KindInt64:
   185  		return d.GetInt64()
   186  	case KindUint64:
   187  		return d.GetUint64()
   188  	case KindFloat32:
   189  		return d.GetFloat32()
   190  	case KindFloat64:
   191  		return d.GetFloat64()
   192  	case KindString:
   193  		return d.GetString()
   194  	case KindBytes:
   195  		return d.GetBytes()
   196  	case KindMysqlDecimal:
   197  		return d.GetMysqlDecimal()
   198  	case KindBinaryLiteral, KindMysqlBit:
   199  		return d.GetBinaryLiteral()
   200  	default:
   201  		return d.GetInterface()
   202  	}
   203  }
   204  
   205  // SetValue sets any kind of value.
   206  func (d *Datum) SetValue(val interface{}) {
   207  	switch x := val.(type) {
   208  	case nil:
   209  		d.SetNull()
   210  	case bool:
   211  		if x {
   212  			d.SetInt64(1)
   213  		} else {
   214  			d.SetInt64(0)
   215  		}
   216  	case int:
   217  		d.SetInt64(int64(x))
   218  	case int64:
   219  		d.SetInt64(x)
   220  	case uint64:
   221  		d.SetUint64(x)
   222  	case float32:
   223  		d.SetFloat32(x)
   224  	case float64:
   225  		d.SetFloat64(x)
   226  	case string:
   227  		d.SetString(x)
   228  	case []byte:
   229  		d.SetBytes(x)
   230  	case *MyDecimal:
   231  		d.SetMysqlDecimal(x)
   232  	case BinaryLiteral:
   233  		d.SetBinaryLiteral(x)
   234  	case BitLiteral: // Store as BinaryLiteral for Bit and Hex literals
   235  		d.SetBinaryLiteral(BinaryLiteral(x))
   236  	case HexLiteral:
   237  		d.SetBinaryLiteral(BinaryLiteral(x))
   238  	default:
   239  		d.SetInterface(x)
   240  	}
   241  }
   242  
   243  // NewDatum creates a new Datum from an interface{}.
   244  func NewDatum(in interface{}) (d Datum) {
   245  	switch x := in.(type) {
   246  	case []interface{}:
   247  		d.SetValue(MakeDatums(x...))
   248  	default:
   249  		d.SetValue(in)
   250  	}
   251  	return d
   252  }
   253  
   254  // NewBytesDatum creates a new Datum from a byte slice.
   255  func NewBytesDatum(b []byte) (d Datum) {
   256  	d.SetBytes(b)
   257  	return d
   258  }
   259  
   260  // NewStringDatum creates a new Datum from a string.
   261  func NewStringDatum(s string) (d Datum) {
   262  	d.SetString(s)
   263  	return d
   264  }
   265  
   266  // MakeDatums creates datum slice from interfaces.
   267  func MakeDatums(args ...interface{}) []Datum {
   268  	datums := make([]Datum, len(args))
   269  	for i, v := range args {
   270  		datums[i] = NewDatum(v)
   271  	}
   272  	return datums
   273  }
   274  
   275  // BinaryLiteral is the internal type for storing bit / hex literal type.
   276  type BinaryLiteral []byte
   277  
   278  // BitLiteral is the bit literal type.
   279  type BitLiteral BinaryLiteral
   280  
   281  // HexLiteral is the hex literal type.
   282  type HexLiteral BinaryLiteral
   283  
   284  // ZeroBinaryLiteral is a BinaryLiteral literal with zero value.
   285  var ZeroBinaryLiteral = BinaryLiteral{}
   286  
   287  // String implements fmt.Stringer interface.
   288  func (b BinaryLiteral) String() string {
   289  	if len(b) == 0 {
   290  		return ""
   291  	}
   292  	return "0x" + hex.EncodeToString(b)
   293  }
   294  
   295  // ToString returns the string representation for the literal.
   296  func (b BinaryLiteral) ToString() string {
   297  	return string(b)
   298  }
   299  
   300  // ToBitLiteralString returns the bit literal representation for the literal.
   301  func (b BinaryLiteral) ToBitLiteralString(trimLeadingZero bool) string {
   302  	if len(b) == 0 {
   303  		return "b''"
   304  	}
   305  	var buf bytes.Buffer
   306  	for _, data := range b {
   307  		fmt.Fprintf(&buf, "%08b", data)
   308  	}
   309  	ret := buf.Bytes()
   310  	if trimLeadingZero {
   311  		ret = bytes.TrimLeft(ret, "0")
   312  		if len(ret) == 0 {
   313  			ret = []byte{'0'}
   314  		}
   315  	}
   316  	return fmt.Sprintf("b'%s'", string(ret))
   317  }
   318  
   319  // ParseBitStr parses bit string.
   320  // The string format can be b'val', B'val' or 0bval, val must be 0 or 1.
   321  // See https://dev.mysql.com/doc/refman/5.7/en/bit-value-literals.html
   322  func ParseBitStr(s string) (BinaryLiteral, error) {
   323  	if len(s) == 0 {
   324  		return nil, errors.Errorf("invalid empty string for parsing bit type")
   325  	}
   326  
   327  	if s[0] == 'b' || s[0] == 'B' {
   328  		// format is b'val' or B'val'
   329  		s = strings.Trim(s[1:], "'")
   330  	} else if strings.HasPrefix(s, "0b") {
   331  		s = s[2:]
   332  	} else {
   333  		// here means format is not b'val', B'val' or 0bval.
   334  		return nil, errors.Errorf("invalid bit type format %s", s)
   335  	}
   336  
   337  	if len(s) == 0 {
   338  		return ZeroBinaryLiteral, nil
   339  	}
   340  
   341  	alignedLength := (len(s) + 7) &^ 7
   342  	s = ("00000000" + s)[len(s)+8-alignedLength:] // Pad with zero (slice from `-alignedLength`)
   343  	byteLength := len(s) >> 3
   344  	buf := make([]byte, byteLength)
   345  
   346  	for i := 0; i < byteLength; i++ {
   347  		strPosition := i << 3
   348  		val, err := strconv.ParseUint(s[strPosition:strPosition+8], 2, 8)
   349  		if err != nil {
   350  			return nil, errors.Trace(err)
   351  		}
   352  		buf[i] = byte(val)
   353  	}
   354  
   355  	return buf, nil
   356  }
   357  
   358  // NewBitLiteral parses bit string as BitLiteral type.
   359  func NewBitLiteral(s string) (BitLiteral, error) {
   360  	b, err := ParseBitStr(s)
   361  	if err != nil {
   362  		return BitLiteral{}, err
   363  	}
   364  	return BitLiteral(b), nil
   365  }
   366  
   367  // ToString implement ast.BinaryLiteral interface
   368  func (b BitLiteral) ToString() string {
   369  	return BinaryLiteral(b).ToString()
   370  }
   371  
   372  // ParseHexStr parses hexadecimal string literal.
   373  // See https://dev.mysql.com/doc/refman/5.7/en/hexadecimal-literals.html
   374  func ParseHexStr(s string) (BinaryLiteral, error) {
   375  	if len(s) == 0 {
   376  		return nil, errors.Errorf("invalid empty string for parsing hexadecimal literal")
   377  	}
   378  
   379  	if s[0] == 'x' || s[0] == 'X' {
   380  		// format is x'val' or X'val'
   381  		s = strings.Trim(s[1:], "'")
   382  		if len(s)%2 != 0 {
   383  			return nil, errors.Errorf("invalid hexadecimal format, must even numbers, but %d", len(s))
   384  		}
   385  	} else if strings.HasPrefix(s, "0x") {
   386  		s = s[2:]
   387  	} else {
   388  		// here means format is not x'val', X'val' or 0xval.
   389  		return nil, errors.Errorf("invalid hexadecimal format %s", s)
   390  	}
   391  
   392  	if len(s) == 0 {
   393  		return ZeroBinaryLiteral, nil
   394  	}
   395  
   396  	if len(s)%2 != 0 {
   397  		s = "0" + s
   398  	}
   399  	buf, err := hex.DecodeString(s)
   400  	if err != nil {
   401  		return nil, errors.Trace(err)
   402  	}
   403  	return buf, nil
   404  }
   405  
   406  // NewHexLiteral parses hexadecimal string as HexLiteral type.
   407  func NewHexLiteral(s string) (HexLiteral, error) {
   408  	h, err := ParseHexStr(s)
   409  	if err != nil {
   410  		return HexLiteral{}, err
   411  	}
   412  	return HexLiteral(h), nil
   413  }
   414  
   415  // ToString implement ast.BinaryLiteral interface
   416  func (b HexLiteral) ToString() string {
   417  	return BinaryLiteral(b).ToString()
   418  }
   419  
   420  // SetBinChsClnFlag sets charset, collation as 'binary' and adds binaryFlag to FieldType.
   421  func SetBinChsClnFlag(ft *types.FieldType) {
   422  	ft.SetCharset(charset.CharsetBin)
   423  	ft.SetCollate(charset.CollationBin)
   424  	ft.AddFlag(mysql.BinaryFlag)
   425  }
   426  
   427  // DefaultFsp is the default digit of fractional seconds part.
   428  // MySQL use 0 as the default Fsp.
   429  const DefaultFsp = int8(0)
   430  
   431  // DefaultTypeForValue returns the default FieldType for the value.
   432  func DefaultTypeForValue(value interface{}, tp *types.FieldType, charset string, collate string) {
   433  	switch x := value.(type) {
   434  	case nil:
   435  		tp.SetType(mysql.TypeNull)
   436  		tp.SetFlen(0)
   437  		tp.SetDecimal(0)
   438  		SetBinChsClnFlag(tp)
   439  	case bool:
   440  		tp.SetType(mysql.TypeLonglong)
   441  		tp.SetFlen(1)
   442  		tp.SetDecimal(0)
   443  		tp.AddFlag(mysql.IsBooleanFlag)
   444  		SetBinChsClnFlag(tp)
   445  	case int:
   446  		tp.SetType(mysql.TypeLonglong)
   447  		tp.SetFlen(StrLenOfInt64Fast(int64(x)))
   448  		tp.SetDecimal(0)
   449  		SetBinChsClnFlag(tp)
   450  	case int64:
   451  		tp.SetType(mysql.TypeLonglong)
   452  		tp.SetFlen(StrLenOfInt64Fast(x))
   453  		tp.SetDecimal(0)
   454  		SetBinChsClnFlag(tp)
   455  	case uint64:
   456  		tp.SetType(mysql.TypeLonglong)
   457  		tp.AddFlag(mysql.UnsignedFlag)
   458  		tp.SetFlen(StrLenOfUint64Fast(x))
   459  		tp.SetDecimal(0)
   460  		SetBinChsClnFlag(tp)
   461  	case string:
   462  		tp.SetType(mysql.TypeVarString)
   463  		// TODO: tp.flen should be len(x) * 3 (max bytes length of CharsetUTF8)
   464  		tp.SetFlen(len(x))
   465  		tp.SetDecimal(types.UnspecifiedLength)
   466  		tp.SetCharset(charset)
   467  		tp.SetCollate(collate)
   468  	case float32:
   469  		tp.SetType(mysql.TypeFloat)
   470  		s := strconv.FormatFloat(float64(x), 'f', -1, 32)
   471  		tp.SetFlen(len(s))
   472  		tp.SetDecimal(types.UnspecifiedLength)
   473  		SetBinChsClnFlag(tp)
   474  	case float64:
   475  		tp.SetType(mysql.TypeDouble)
   476  		s := strconv.FormatFloat(x, 'f', -1, 64)
   477  		tp.SetFlen(len(s))
   478  		tp.SetDecimal(types.UnspecifiedLength)
   479  		SetBinChsClnFlag(tp)
   480  	case []byte:
   481  		tp.SetType(mysql.TypeBlob)
   482  		tp.SetFlen(len(x))
   483  		tp.SetDecimal(types.UnspecifiedLength)
   484  		SetBinChsClnFlag(tp)
   485  	case BitLiteral:
   486  		tp.SetType(mysql.TypeVarString)
   487  		tp.SetFlen(len(x))
   488  		tp.SetDecimal(0)
   489  		SetBinChsClnFlag(tp)
   490  	case HexLiteral:
   491  		tp.SetType(mysql.TypeVarString)
   492  		tp.SetFlen(len(x) * 3)
   493  		tp.SetDecimal(0)
   494  		tp.AddFlag(mysql.UnsignedFlag)
   495  		SetBinChsClnFlag(tp)
   496  	case BinaryLiteral:
   497  		tp.SetType(mysql.TypeBit)
   498  		tp.SetFlen(len(x) * 8)
   499  		tp.SetDecimal(0)
   500  		SetBinChsClnFlag(tp)
   501  		tp.DelFlag(mysql.BinaryFlag)
   502  		tp.AddFlag(mysql.UnsignedFlag)
   503  	case *MyDecimal:
   504  		tp.SetType(mysql.TypeNewDecimal)
   505  		tp.SetFlen(len(x.ToString()))
   506  		tp.SetDecimal(int(x.digitsFrac))
   507  		SetBinChsClnFlag(tp)
   508  	default:
   509  		tp.SetType(mysql.TypeUnspecified)
   510  		tp.SetFlen(types.UnspecifiedLength)
   511  		tp.SetDecimal(types.UnspecifiedLength)
   512  	}
   513  }