github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/dependency/util/chunk/chunk.go (about)

     1  // Copyright 2017 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  package chunk
    15  
    16  import (
    17  	"encoding/binary"
    18  	"unsafe"
    19  
    20  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/mysql"
    21  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/types"
    22  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/types/json"
    23  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/util/hack"
    24  )
    25  
    26  var _ types.Row = Row{}
    27  
    28  // Chunk stores multiple rows of data in Apache Arrow format.
    29  // See https://arrow.apache.org/docs/memory_layout.html
    30  // Values are appended in compact format and can be directly accessed without decoding.
    31  // When the chunk is done processing, we can reuse the allocated memory by resetting it.
    32  type Chunk struct {
    33  	columns []*column
    34  	// numVirtualRows indicates the number of virtual rows, witch have zero columns.
    35  	// It is used only when this Chunk doesn't hold any data, i.e. "len(columns)==0".
    36  	numVirtualRows int
    37  }
    38  
    39  // Capacity constants.
    40  const (
    41  	InitialCapacity = 32
    42  )
    43  
    44  // NewChunk creates a new chunk with field types.
    45  func NewChunk(fields []*types.FieldType) *Chunk {
    46  	return NewChunkWithCapacity(fields, InitialCapacity)
    47  }
    48  
    49  // NewChunkWithCapacity creates a new chunk with field types and capacity.
    50  func NewChunkWithCapacity(fields []*types.FieldType, cap int) *Chunk {
    51  	chk := new(Chunk)
    52  	chk.columns = make([]*column, 0, len(fields))
    53  	chk.numVirtualRows = 0
    54  	for _, f := range fields {
    55  		chk.addColumnByFieldType(f, cap)
    56  	}
    57  	return chk
    58  }
    59  
    60  // MemoryUsage returns the total memory usage of a Chunk in B.
    61  // We ignore the size of column.length and column.nullCount
    62  // since they have little effect of the total memory usage.
    63  func (c *Chunk) MemoryUsage() (sum int64) {
    64  	for _, col := range c.columns {
    65  		curColMemUsage := int64(unsafe.Sizeof(*col)) + int64(cap(col.nullBitmap)) + int64(cap(col.offsets)*4) + int64(cap(col.data)) + int64(cap(col.elemBuf))
    66  		sum += curColMemUsage
    67  	}
    68  	return
    69  }
    70  
    71  // addFixedLenColumn adds a fixed length column with elemLen and initial data capacity.
    72  func (c *Chunk) addFixedLenColumn(elemLen, initCap int) {
    73  	c.columns = append(c.columns, &column{
    74  		elemBuf:    make([]byte, elemLen),
    75  		data:       make([]byte, 0, initCap*elemLen),
    76  		nullBitmap: make([]byte, 0, initCap>>3),
    77  	})
    78  }
    79  
    80  // addVarLenColumn adds a variable length column with initial data capacity.
    81  func (c *Chunk) addVarLenColumn(initCap int) {
    82  	c.columns = append(c.columns, &column{
    83  		offsets:    make([]int32, 1, initCap+1),
    84  		data:       make([]byte, 0, initCap*4),
    85  		nullBitmap: make([]byte, 0, initCap>>3),
    86  	})
    87  }
    88  
    89  // addColumnByFieldType adds a column by field type.
    90  func (c *Chunk) addColumnByFieldType(fieldTp *types.FieldType, initCap int) {
    91  	switch fieldTp.Tp {
    92  	case mysql.TypeFloat:
    93  		c.addFixedLenColumn(4, initCap)
    94  	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong,
    95  		mysql.TypeDouble, mysql.TypeYear:
    96  		c.addFixedLenColumn(8, initCap)
    97  	case mysql.TypeDuration:
    98  		c.addFixedLenColumn(16, initCap)
    99  	case mysql.TypeNewDecimal:
   100  		c.addFixedLenColumn(types.MyDecimalStructSize, initCap)
   101  	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
   102  		c.addFixedLenColumn(16, initCap)
   103  	default:
   104  		c.addVarLenColumn(initCap)
   105  	}
   106  }
   107  
   108  // MakeRef makes column in "dstColIdx" reference to column in "srcColIdx".
   109  func (c *Chunk) MakeRef(srcColIdx, dstColIdx int) {
   110  	c.columns[dstColIdx] = c.columns[srcColIdx]
   111  }
   112  
   113  // SwapColumn swaps column "c.columns[colIdx]" with column "other.columns[otherIdx]".
   114  func (c *Chunk) SwapColumn(colIdx int, other *Chunk, otherIdx int) {
   115  	c.columns[colIdx], other.columns[otherIdx] = other.columns[otherIdx], c.columns[colIdx]
   116  }
   117  
   118  // SwapColumns swaps columns with another Chunk.
   119  func (c *Chunk) SwapColumns(other *Chunk) {
   120  	c.columns, other.columns = other.columns, c.columns
   121  	c.numVirtualRows, other.numVirtualRows = other.numVirtualRows, c.numVirtualRows
   122  }
   123  
   124  // SetNumVirtualRows sets the virtual row number for a Chunk.
   125  // It should only be used when there exists no column in the Chunk.
   126  func (c *Chunk) SetNumVirtualRows(numVirtualRows int) {
   127  	c.numVirtualRows = numVirtualRows
   128  }
   129  
   130  // Reset resets the chunk, so the memory it allocated can be reused.
   131  // Make sure all the data in the chunk is not used anymore before you reuse this chunk.
   132  func (c *Chunk) Reset() {
   133  	for _, c := range c.columns {
   134  		c.reset()
   135  	}
   136  	c.numVirtualRows = 0
   137  }
   138  
   139  // NumCols returns the number of columns in the chunk.
   140  func (c *Chunk) NumCols() int {
   141  	return len(c.columns)
   142  }
   143  
   144  // NumRows returns the number of rows in the chunk.
   145  func (c *Chunk) NumRows() int {
   146  	if c.NumCols() == 0 {
   147  		return c.numVirtualRows
   148  	}
   149  	return c.columns[0].length
   150  }
   151  
   152  // GetRow gets the Row in the chunk with the row index.
   153  func (c *Chunk) GetRow(idx int) Row {
   154  	return Row{c: c, idx: idx}
   155  }
   156  
   157  // AppendRow appends a row to the chunk.
   158  func (c *Chunk) AppendRow(row Row) {
   159  	c.AppendPartialRow(0, row)
   160  	c.numVirtualRows++
   161  }
   162  
   163  // AppendPartialRow appends a row to the chunk.
   164  func (c *Chunk) AppendPartialRow(colIdx int, row Row) {
   165  	for i, rowCol := range row.c.columns {
   166  		chkCol := c.columns[colIdx+i]
   167  		chkCol.appendNullBitmap(!rowCol.isNull(row.idx))
   168  		if rowCol.isFixed() {
   169  			elemLen := len(rowCol.elemBuf)
   170  			offset := row.idx * elemLen
   171  			chkCol.data = append(chkCol.data, rowCol.data[offset:offset+elemLen]...)
   172  		} else {
   173  			start, end := rowCol.offsets[row.idx], rowCol.offsets[row.idx+1]
   174  			chkCol.data = append(chkCol.data, rowCol.data[start:end]...)
   175  			chkCol.offsets = append(chkCol.offsets, int32(len(chkCol.data)))
   176  		}
   177  		chkCol.length++
   178  	}
   179  }
   180  
   181  // Append appends rows in [begin, end) in another Chunk to a Chunk.
   182  func (c *Chunk) Append(other *Chunk, begin, end int) {
   183  	for colID, src := range other.columns {
   184  		dst := c.columns[colID]
   185  		if src.isFixed() {
   186  			elemLen := len(src.elemBuf)
   187  			dst.data = append(dst.data, src.data[begin*elemLen:end*elemLen]...)
   188  		} else {
   189  			beginOffset, endOffset := src.offsets[begin], src.offsets[end]
   190  			dst.data = append(dst.data, src.data[beginOffset:endOffset]...)
   191  			for i := begin; i < end; i++ {
   192  				dst.offsets = append(dst.offsets, dst.offsets[len(dst.offsets)-1]+src.offsets[i+1]-src.offsets[i])
   193  			}
   194  		}
   195  		for i := begin; i < end; i++ {
   196  			dst.appendNullBitmap(!src.isNull(i))
   197  			dst.length++
   198  		}
   199  	}
   200  	c.numVirtualRows += end - begin
   201  }
   202  
   203  // TruncateTo truncates rows from tail to head in a Chunk to "numRows" rows.
   204  func (c *Chunk) TruncateTo(numRows int) {
   205  	for _, col := range c.columns {
   206  		if col.isFixed() {
   207  			elemLen := len(col.elemBuf)
   208  			col.data = col.data[:numRows*elemLen]
   209  		} else {
   210  			col.data = col.data[:col.offsets[numRows]]
   211  			col.offsets = col.offsets[:numRows+1]
   212  		}
   213  		for i := numRows; i < col.length; i++ {
   214  			if col.isNull(i) {
   215  				col.nullCount--
   216  			}
   217  		}
   218  		col.length = numRows
   219  		col.nullBitmap = col.nullBitmap[:(col.length>>3)+1]
   220  	}
   221  	c.numVirtualRows = numRows
   222  }
   223  
   224  // AppendNull appends a null value to the chunk.
   225  func (c *Chunk) AppendNull(colIdx int) {
   226  	c.columns[colIdx].appendNull()
   227  }
   228  
   229  // AppendInt64 appends a int64 value to the chunk.
   230  func (c *Chunk) AppendInt64(colIdx int, i int64) {
   231  	c.columns[colIdx].appendInt64(i)
   232  }
   233  
   234  // AppendUint64 appends a uint64 value to the chunk.
   235  func (c *Chunk) AppendUint64(colIdx int, u uint64) {
   236  	c.columns[colIdx].appendUint64(u)
   237  }
   238  
   239  // AppendFloat32 appends a float32 value to the chunk.
   240  func (c *Chunk) AppendFloat32(colIdx int, f float32) {
   241  	c.columns[colIdx].appendFloat32(f)
   242  }
   243  
   244  // AppendFloat64 appends a float64 value to the chunk.
   245  func (c *Chunk) AppendFloat64(colIdx int, f float64) {
   246  	c.columns[colIdx].appendFloat64(f)
   247  }
   248  
   249  // AppendString appends a string value to the chunk.
   250  func (c *Chunk) AppendString(colIdx int, str string) {
   251  	c.columns[colIdx].appendString(str)
   252  }
   253  
   254  // AppendBytes appends a bytes value to the chunk.
   255  func (c *Chunk) AppendBytes(colIdx int, b []byte) {
   256  	c.columns[colIdx].appendBytes(b)
   257  }
   258  
   259  // AppendTime appends a Time value to the chunk.
   260  // TODO: change the time structure so it can be directly written to memory.
   261  func (c *Chunk) AppendTime(colIdx int, t types.Time) {
   262  	c.columns[colIdx].appendTime(t)
   263  }
   264  
   265  // AppendDuration appends a Duration value to the chunk.
   266  func (c *Chunk) AppendDuration(colIdx int, dur types.Duration) {
   267  	c.columns[colIdx].appendDuration(dur)
   268  }
   269  
   270  // AppendMyDecimal appends a MyDecimal value to the chunk.
   271  func (c *Chunk) AppendMyDecimal(colIdx int, dec *types.MyDecimal) {
   272  	c.columns[colIdx].appendMyDecimal(dec)
   273  }
   274  
   275  // AppendEnum appends an Enum value to the chunk.
   276  func (c *Chunk) AppendEnum(colIdx int, enum types.Enum) {
   277  	c.columns[colIdx].appendNameValue(enum.Name, enum.Value)
   278  }
   279  
   280  // AppendSet appends a Set value to the chunk.
   281  func (c *Chunk) AppendSet(colIdx int, set types.Set) {
   282  	c.columns[colIdx].appendNameValue(set.Name, set.Value)
   283  }
   284  
   285  // AppendJSON appends a JSON value to the chunk.
   286  func (c *Chunk) AppendJSON(colIdx int, j json.BinaryJSON) {
   287  	c.columns[colIdx].appendJSON(j)
   288  }
   289  
   290  // AppendDatum appends a datum into the chunk.
   291  func (c *Chunk) AppendDatum(colIdx int, d *types.Datum) {
   292  	switch d.Kind() {
   293  	case types.KindNull:
   294  		c.AppendNull(colIdx)
   295  	case types.KindInt64:
   296  		c.AppendInt64(colIdx, d.GetInt64())
   297  	case types.KindUint64:
   298  		c.AppendUint64(colIdx, d.GetUint64())
   299  	case types.KindFloat32:
   300  		c.AppendFloat32(colIdx, d.GetFloat32())
   301  	case types.KindFloat64:
   302  		c.AppendFloat64(colIdx, d.GetFloat64())
   303  	case types.KindString, types.KindBytes, types.KindBinaryLiteral, types.KindRaw, types.KindMysqlBit:
   304  		c.AppendBytes(colIdx, d.GetBytes())
   305  	case types.KindMysqlDecimal:
   306  		c.AppendMyDecimal(colIdx, d.GetMysqlDecimal())
   307  	case types.KindMysqlDuration:
   308  		c.AppendDuration(colIdx, d.GetMysqlDuration())
   309  	case types.KindMysqlEnum:
   310  		c.AppendEnum(colIdx, d.GetMysqlEnum())
   311  	case types.KindMysqlSet:
   312  		c.AppendSet(colIdx, d.GetMysqlSet())
   313  	case types.KindMysqlTime:
   314  		c.AppendTime(colIdx, d.GetMysqlTime())
   315  	case types.KindMysqlJSON:
   316  		c.AppendJSON(colIdx, d.GetMysqlJSON())
   317  	}
   318  }
   319  
   320  type column struct {
   321  	length     int
   322  	nullCount  int
   323  	nullBitmap []byte
   324  	offsets    []int32
   325  	data       []byte
   326  	elemBuf    []byte
   327  }
   328  
   329  func (c *column) isFixed() bool {
   330  	return c.elemBuf != nil
   331  }
   332  
   333  func (c *column) reset() {
   334  	c.length = 0
   335  	c.nullCount = 0
   336  	c.nullBitmap = c.nullBitmap[:0]
   337  	if len(c.offsets) > 0 {
   338  		// The first offset is always 0, it makes slicing the data easier, we need to keep it.
   339  		c.offsets = c.offsets[:1]
   340  	}
   341  	c.data = c.data[:0]
   342  }
   343  
   344  func (c *column) isNull(rowIdx int) bool {
   345  	nullByte := c.nullBitmap[rowIdx/8]
   346  	return nullByte&(1<<(uint(rowIdx)&7)) == 0
   347  }
   348  
   349  func (c *column) appendNullBitmap(on bool) {
   350  	idx := c.length >> 3
   351  	if idx >= len(c.nullBitmap) {
   352  		c.nullBitmap = append(c.nullBitmap, 0)
   353  	}
   354  	if on {
   355  		pos := uint(c.length) & 7
   356  		c.nullBitmap[idx] |= byte(1 << pos)
   357  	} else {
   358  		c.nullCount++
   359  	}
   360  }
   361  
   362  func (c *column) appendNull() {
   363  	c.appendNullBitmap(false)
   364  	if c.isFixed() {
   365  		c.data = append(c.data, c.elemBuf...)
   366  	} else {
   367  		c.offsets = append(c.offsets, c.offsets[c.length])
   368  	}
   369  	c.length++
   370  }
   371  
   372  func (c *column) finishAppendFixed() {
   373  	c.data = append(c.data, c.elemBuf...)
   374  	c.appendNullBitmap(true)
   375  	c.length++
   376  }
   377  
   378  func (c *column) appendInt64(i int64) {
   379  	*(*int64)(unsafe.Pointer(&c.elemBuf[0])) = i
   380  	c.finishAppendFixed()
   381  }
   382  
   383  func (c *column) appendUint64(u uint64) {
   384  	*(*uint64)(unsafe.Pointer(&c.elemBuf[0])) = u
   385  	c.finishAppendFixed()
   386  }
   387  
   388  func (c *column) appendFloat32(f float32) {
   389  	*(*float32)(unsafe.Pointer(&c.elemBuf[0])) = f
   390  	c.finishAppendFixed()
   391  }
   392  
   393  func (c *column) appendFloat64(f float64) {
   394  	*(*float64)(unsafe.Pointer(&c.elemBuf[0])) = f
   395  	c.finishAppendFixed()
   396  }
   397  
   398  func (c *column) finishAppendVar() {
   399  	c.appendNullBitmap(true)
   400  	c.offsets = append(c.offsets, int32(len(c.data)))
   401  	c.length++
   402  }
   403  
   404  func (c *column) appendString(str string) {
   405  	c.data = append(c.data, str...)
   406  	c.finishAppendVar()
   407  }
   408  
   409  func (c *column) appendBytes(b []byte) {
   410  	c.data = append(c.data, b...)
   411  	c.finishAppendVar()
   412  }
   413  
   414  func (c *column) appendTime(t types.Time) {
   415  	writeTime(c.elemBuf, t)
   416  	c.finishAppendFixed()
   417  }
   418  
   419  func writeTime(buf []byte, t types.Time) {
   420  	binary.BigEndian.PutUint16(buf, uint16(t.Time.Year()))
   421  	buf[2] = uint8(t.Time.Month())
   422  	buf[3] = uint8(t.Time.Day())
   423  	buf[4] = uint8(t.Time.Hour())
   424  	buf[5] = uint8(t.Time.Minute())
   425  	buf[6] = uint8(t.Time.Second())
   426  	binary.BigEndian.PutUint32(buf[8:], uint32(t.Time.Microsecond()))
   427  	buf[12] = t.Type
   428  	buf[13] = uint8(t.Fsp)
   429  }
   430  
   431  func (c *column) appendDuration(dur types.Duration) {
   432  	*(*types.Duration)(unsafe.Pointer(&c.elemBuf[0])) = dur
   433  	c.finishAppendFixed()
   434  }
   435  
   436  func (c *column) appendMyDecimal(dec *types.MyDecimal) {
   437  	*(*types.MyDecimal)(unsafe.Pointer(&c.elemBuf[0])) = *dec
   438  	c.finishAppendFixed()
   439  }
   440  
   441  func (c *column) appendNameValue(name string, val uint64) {
   442  	var buf [8]byte
   443  	*(*uint64)(unsafe.Pointer(&buf[0])) = val
   444  	c.data = append(c.data, buf[:]...)
   445  	c.data = append(c.data, name...)
   446  	c.finishAppendVar()
   447  }
   448  
   449  func (c *column) appendJSON(j json.BinaryJSON) {
   450  	c.data = append(c.data, j.TypeCode)
   451  	c.data = append(c.data, j.Value...)
   452  	c.finishAppendVar()
   453  }
   454  
   455  // Row represents a row of data, can be used to assess values.
   456  type Row struct {
   457  	c   *Chunk
   458  	idx int
   459  }
   460  
   461  // Idx returns the row index of Chunk.
   462  func (r Row) Idx() int {
   463  	return r.idx
   464  }
   465  
   466  // Len returns the number of values in the row.
   467  func (r Row) Len() int {
   468  	return r.c.NumCols()
   469  }
   470  
   471  // GetInt64 returns the int64 value with the colIdx.
   472  func (r Row) GetInt64(colIdx int) int64 {
   473  	col := r.c.columns[colIdx]
   474  	return *(*int64)(unsafe.Pointer(&col.data[r.idx*8]))
   475  }
   476  
   477  // GetUint64 returns the uint64 value with the colIdx.
   478  func (r Row) GetUint64(colIdx int) uint64 {
   479  	col := r.c.columns[colIdx]
   480  	return *(*uint64)(unsafe.Pointer(&col.data[r.idx*8]))
   481  }
   482  
   483  // GetFloat32 returns the float64 value with the colIdx.
   484  func (r Row) GetFloat32(colIdx int) float32 {
   485  	col := r.c.columns[colIdx]
   486  	return *(*float32)(unsafe.Pointer(&col.data[r.idx*4]))
   487  }
   488  
   489  // GetFloat64 returns the float64 value with the colIdx.
   490  func (r Row) GetFloat64(colIdx int) float64 {
   491  	col := r.c.columns[colIdx]
   492  	return *(*float64)(unsafe.Pointer(&col.data[r.idx*8]))
   493  }
   494  
   495  // GetString returns the string value with the colIdx.
   496  func (r Row) GetString(colIdx int) string {
   497  	col := r.c.columns[colIdx]
   498  	start, end := col.offsets[r.idx], col.offsets[r.idx+1]
   499  	return hack.String(col.data[start:end])
   500  }
   501  
   502  // GetBytes returns the bytes value with the colIdx.
   503  func (r Row) GetBytes(colIdx int) []byte {
   504  	col := r.c.columns[colIdx]
   505  	start, end := col.offsets[r.idx], col.offsets[r.idx+1]
   506  	return col.data[start:end]
   507  }
   508  
   509  // GetTime returns the Time value with the colIdx.
   510  // TODO: use Time structure directly.
   511  func (r Row) GetTime(colIdx int) types.Time {
   512  	col := r.c.columns[colIdx]
   513  	return readTime(col.data[r.idx*16:])
   514  }
   515  
   516  func readTime(buf []byte) types.Time {
   517  	year := int(binary.BigEndian.Uint16(buf))
   518  	month := int(buf[2])
   519  	day := int(buf[3])
   520  	hour := int(buf[4])
   521  	minute := int(buf[5])
   522  	second := int(buf[6])
   523  	microseconds := int(binary.BigEndian.Uint32(buf[8:]))
   524  	tp := buf[12]
   525  	fsp := int(buf[13])
   526  	return types.Time{
   527  		Time: types.FromDate(year, month, day, hour, minute, second, microseconds),
   528  		Type: tp,
   529  		Fsp:  fsp,
   530  	}
   531  }
   532  
   533  // GetDuration returns the Duration value with the colIdx.
   534  func (r Row) GetDuration(colIdx int) types.Duration {
   535  	col := r.c.columns[colIdx]
   536  	return *(*types.Duration)(unsafe.Pointer(&col.data[r.idx*16]))
   537  }
   538  
   539  func (r Row) getNameValue(colIdx int) (string, uint64) {
   540  	col := r.c.columns[colIdx]
   541  	start, end := col.offsets[r.idx], col.offsets[r.idx+1]
   542  	if start == end {
   543  		return "", 0
   544  	}
   545  	val := *(*uint64)(unsafe.Pointer(&col.data[start]))
   546  	name := hack.String(col.data[start+8 : end])
   547  	return name, val
   548  }
   549  
   550  // GetEnum returns the Enum value with the colIdx.
   551  func (r Row) GetEnum(colIdx int) types.Enum {
   552  	name, val := r.getNameValue(colIdx)
   553  	return types.Enum{Name: name, Value: val}
   554  }
   555  
   556  // GetSet returns the Set value with the colIdx.
   557  func (r Row) GetSet(colIdx int) types.Set {
   558  	name, val := r.getNameValue(colIdx)
   559  	return types.Set{Name: name, Value: val}
   560  }
   561  
   562  // GetMyDecimal returns the MyDecimal value with the colIdx.
   563  func (r Row) GetMyDecimal(colIdx int) *types.MyDecimal {
   564  	col := r.c.columns[colIdx]
   565  	return (*types.MyDecimal)(unsafe.Pointer(&col.data[r.idx*types.MyDecimalStructSize]))
   566  }
   567  
   568  // GetJSON returns the JSON value with the colIdx.
   569  func (r Row) GetJSON(colIdx int) json.BinaryJSON {
   570  	col := r.c.columns[colIdx]
   571  	start, end := col.offsets[r.idx], col.offsets[r.idx+1]
   572  	return json.BinaryJSON{TypeCode: col.data[start], Value: col.data[start+1 : end]}
   573  }
   574  
   575  // GetDatumRow converts chunk.Row to types.DatumRow.
   576  // Keep in mind that GetDatumRow has a reference to r.c, which is a chunk,
   577  // this function works only if the underlying chunk is valid or unchanged.
   578  func (r Row) GetDatumRow(fields []*types.FieldType) types.DatumRow {
   579  	datumRow := make(types.DatumRow, 0, r.c.NumCols())
   580  	for colIdx := 0; colIdx < r.c.NumCols(); colIdx++ {
   581  		datum := r.GetDatum(colIdx, fields[colIdx])
   582  		datumRow = append(datumRow, datum)
   583  	}
   584  	return datumRow
   585  }
   586  
   587  // GetDatum implements the types.Row interface.
   588  func (r Row) GetDatum(colIdx int, tp *types.FieldType) types.Datum {
   589  	var d types.Datum
   590  	switch tp.Tp {
   591  	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear:
   592  		if !r.IsNull(colIdx) {
   593  			if mysql.HasUnsignedFlag(tp.Flag) {
   594  				d.SetUint64(r.GetUint64(colIdx))
   595  			} else {
   596  				d.SetInt64(r.GetInt64(colIdx))
   597  			}
   598  		}
   599  	case mysql.TypeFloat:
   600  		if !r.IsNull(colIdx) {
   601  			d.SetFloat32(r.GetFloat32(colIdx))
   602  		}
   603  	case mysql.TypeDouble:
   604  		if !r.IsNull(colIdx) {
   605  			d.SetFloat64(r.GetFloat64(colIdx))
   606  		}
   607  	case mysql.TypeVarchar, mysql.TypeVarString, mysql.TypeString,
   608  		mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:
   609  		if !r.IsNull(colIdx) {
   610  			d.SetBytes(r.GetBytes(colIdx))
   611  		}
   612  	case mysql.TypeDate, mysql.TypeDatetime, mysql.TypeTimestamp:
   613  		if !r.IsNull(colIdx) {
   614  			d.SetMysqlTime(r.GetTime(colIdx))
   615  		}
   616  	case mysql.TypeDuration:
   617  		if !r.IsNull(colIdx) {
   618  			d.SetMysqlDuration(r.GetDuration(colIdx))
   619  		}
   620  	case mysql.TypeNewDecimal:
   621  		if !r.IsNull(colIdx) {
   622  			d.SetMysqlDecimal(r.GetMyDecimal(colIdx))
   623  			d.SetLength(tp.Flen)
   624  			d.SetFrac(tp.Decimal)
   625  		}
   626  	case mysql.TypeEnum:
   627  		if !r.IsNull(colIdx) {
   628  			d.SetMysqlEnum(r.GetEnum(colIdx))
   629  		}
   630  	case mysql.TypeSet:
   631  		if !r.IsNull(colIdx) {
   632  			d.SetMysqlSet(r.GetSet(colIdx))
   633  		}
   634  	case mysql.TypeBit:
   635  		if !r.IsNull(colIdx) {
   636  			d.SetMysqlBit(r.GetBytes(colIdx))
   637  		}
   638  	case mysql.TypeJSON:
   639  		if !r.IsNull(colIdx) {
   640  			d.SetMysqlJSON(r.GetJSON(colIdx))
   641  		}
   642  	}
   643  	return d
   644  }
   645  
   646  // IsNull implements the types.Row interface.
   647  func (r Row) IsNull(colIdx int) bool {
   648  	return r.c.columns[colIdx].isNull(r.idx)
   649  }