github.com/bingoohuang/gg@v0.0.0-20240325092523-45da7dee9335/pkg/sqlparse/tidbparser/dependency/util/chunk/mutrow.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  	"math"
    19  	"unsafe"
    20  
    21  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/mysql"
    22  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/types"
    23  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/types/json"
    24  	"github.com/bingoohuang/gg/pkg/sqlparse/tidbparser/dependency/util/hack"
    25  )
    26  
    27  // MutRow represents a mutable Row.
    28  // The underlying columns only contains one row and not exposed to the user.
    29  type MutRow Row
    30  
    31  // ToRow converts the MutRow to Row, so it can be used to read data.
    32  func (mr MutRow) ToRow() Row {
    33  	return Row(mr)
    34  }
    35  
    36  // Len returns the number of columns.
    37  func (mr MutRow) Len() int {
    38  	return len(mr.c.columns)
    39  }
    40  
    41  // MutRowFromValues creates a MutRow from a interface slice.
    42  func MutRowFromValues(vals ...interface{}) MutRow {
    43  	c := &Chunk{}
    44  	for _, val := range vals {
    45  		col := makeMutRowColumn(val)
    46  		c.columns = append(c.columns, col)
    47  	}
    48  	return MutRow{c: c}
    49  }
    50  
    51  // MutRowFromDatums creates a MutRow from a datum slice.
    52  func MutRowFromDatums(datums []types.Datum) MutRow {
    53  	c := &Chunk{}
    54  	for _, d := range datums {
    55  		col := makeMutRowColumn(d.GetValue())
    56  		c.columns = append(c.columns, col)
    57  	}
    58  	return MutRow{c: c, idx: 0}
    59  }
    60  
    61  // MutRowFromTypes creates a MutRow from a FieldType slice, each column is initialized to zero value.
    62  func MutRowFromTypes(types []*types.FieldType) MutRow {
    63  	c := &Chunk{}
    64  	for _, tp := range types {
    65  		col := makeMutRowColumn(zeroValForType(tp))
    66  		c.columns = append(c.columns, col)
    67  	}
    68  	return MutRow{c: c, idx: 0}
    69  }
    70  
    71  func zeroValForType(tp *types.FieldType) interface{} {
    72  	switch tp.Tp {
    73  	case mysql.TypeFloat:
    74  		return float32(0)
    75  	case mysql.TypeDouble:
    76  		return float64(0)
    77  	case mysql.TypeTiny, mysql.TypeShort, mysql.TypeInt24, mysql.TypeLong, mysql.TypeLonglong, mysql.TypeYear:
    78  		if mysql.HasUnsignedFlag(tp.Flag) {
    79  			return uint64(0)
    80  		}
    81  		return int64(0)
    82  	case mysql.TypeString, mysql.TypeVarString, mysql.TypeVarchar:
    83  		return ""
    84  	case mysql.TypeBlob, mysql.TypeTinyBlob, mysql.TypeMediumBlob, mysql.TypeLongBlob:
    85  		return []byte{}
    86  	case mysql.TypeDuration:
    87  		return types.ZeroDuration
    88  	case mysql.TypeNewDecimal:
    89  		return types.NewDecFromInt(0)
    90  	case mysql.TypeDate:
    91  		return types.ZeroDate
    92  	case mysql.TypeDatetime:
    93  		return types.ZeroDatetime
    94  	case mysql.TypeTimestamp:
    95  		return types.ZeroTimestamp
    96  	case mysql.TypeBit:
    97  		return types.BinaryLiteral{}
    98  	case mysql.TypeSet:
    99  		return types.Set{}
   100  	case mysql.TypeEnum:
   101  		return types.Enum{}
   102  	case mysql.TypeJSON:
   103  		return json.CreateBinary(nil)
   104  	default:
   105  		return nil
   106  	}
   107  }
   108  
   109  func makeMutRowColumn(in interface{}) *column {
   110  	switch x := in.(type) {
   111  	case nil:
   112  		col := makeMutRowUint64Column(uint64(0))
   113  		col.nullBitmap[0] = 0
   114  		return col
   115  	case int:
   116  		return makeMutRowUint64Column(uint64(x))
   117  	case int64:
   118  		return makeMutRowUint64Column(uint64(x))
   119  	case uint64:
   120  		return makeMutRowUint64Column(x)
   121  	case float64:
   122  		return makeMutRowUint64Column(math.Float64bits(x))
   123  	case float32:
   124  		col := newMutRowFixedLenColumn(4)
   125  		*(*uint32)(unsafe.Pointer(&col.data[0])) = math.Float32bits(x)
   126  		return col
   127  	case string:
   128  		return makeMutRowBytesColumn(hack.Slice(x))
   129  	case []byte:
   130  		return makeMutRowBytesColumn(x)
   131  	case types.BinaryLiteral:
   132  		return makeMutRowBytesColumn(x)
   133  	case *types.MyDecimal:
   134  		col := newMutRowFixedLenColumn(types.MyDecimalStructSize)
   135  		*(*types.MyDecimal)(unsafe.Pointer(&col.data[0])) = *x
   136  		return col
   137  	case types.Time:
   138  		col := newMutRowFixedLenColumn(16)
   139  		writeTime(col.data, x)
   140  		return col
   141  	case json.BinaryJSON:
   142  		col := newMutRowVarLenColumn(len(x.Value) + 1)
   143  		col.data[0] = x.TypeCode
   144  		copy(col.data[1:], x.Value)
   145  		return col
   146  	case types.Duration:
   147  		col := newMutRowFixedLenColumn(16)
   148  		*(*types.Duration)(unsafe.Pointer(&col.data[0])) = x
   149  		return col
   150  	case types.Enum:
   151  		col := newMutRowVarLenColumn(len(x.Name) + 8)
   152  		*(*uint64)(unsafe.Pointer(&col.data[0])) = x.Value
   153  		copy(col.data[8:], x.Name)
   154  		return col
   155  	case types.Set:
   156  		col := newMutRowVarLenColumn(len(x.Name) + 8)
   157  		*(*uint64)(unsafe.Pointer(&col.data[0])) = x.Value
   158  		copy(col.data[8:], x.Name)
   159  		return col
   160  	default:
   161  		return nil
   162  	}
   163  }
   164  
   165  func newMutRowFixedLenColumn(elemSize int) *column {
   166  	buf := make([]byte, elemSize+1)
   167  	col := &column{
   168  		length:     1,
   169  		elemBuf:    buf[:elemSize],
   170  		data:       buf[:elemSize],
   171  		nullBitmap: buf[elemSize:],
   172  	}
   173  	col.nullBitmap[0] = 1
   174  	return col
   175  }
   176  
   177  func newMutRowVarLenColumn(valSize int) *column {
   178  	buf := make([]byte, valSize+1)
   179  	col := &column{
   180  		length:     1,
   181  		offsets:    []int32{0, int32(valSize)},
   182  		data:       buf[:valSize],
   183  		nullBitmap: buf[valSize:],
   184  	}
   185  	col.nullBitmap[0] = 1
   186  	return col
   187  }
   188  
   189  func makeMutRowUint64Column(val uint64) *column {
   190  	col := newMutRowFixedLenColumn(8)
   191  	*(*uint64)(unsafe.Pointer(&col.data[0])) = val
   192  	return col
   193  }
   194  
   195  func makeMutRowBytesColumn(bin []byte) *column {
   196  	col := newMutRowVarLenColumn(len(bin))
   197  	copy(col.data, bin)
   198  	col.nullBitmap[0] = 1
   199  	return col
   200  }
   201  
   202  // SetRow sets the MutRow with Row.
   203  func (mr MutRow) SetRow(row Row) {
   204  	for colIdx, rCol := range row.c.columns {
   205  		mrCol := mr.c.columns[colIdx]
   206  		if rCol.isNull(row.idx) {
   207  			mrCol.nullBitmap[0] = 0
   208  			continue
   209  		}
   210  		elemLen := len(rCol.elemBuf)
   211  		if elemLen > 0 {
   212  			copy(mrCol.data, rCol.data[row.idx*elemLen:(row.idx+1)*elemLen])
   213  		} else {
   214  			setMutRowBytes(mrCol, rCol.data[rCol.offsets[row.idx]:rCol.offsets[row.idx+1]])
   215  		}
   216  		mrCol.nullBitmap[0] = 1
   217  	}
   218  }
   219  
   220  // SetValues sets the MutRow with values.
   221  func (mr MutRow) SetValues(vals ...interface{}) {
   222  	for i, v := range vals {
   223  		mr.SetValue(i, v)
   224  	}
   225  }
   226  
   227  // SetValue sets the MutRow with colIdx and value.
   228  func (mr MutRow) SetValue(colIdx int, val interface{}) {
   229  	col := mr.c.columns[colIdx]
   230  	if val == nil {
   231  		col.nullBitmap[0] = 0
   232  		return
   233  	}
   234  	switch x := val.(type) {
   235  	case int:
   236  		binary.LittleEndian.PutUint64(col.data, uint64(x))
   237  	case int64:
   238  		binary.LittleEndian.PutUint64(col.data, uint64(x))
   239  	case uint64:
   240  		binary.LittleEndian.PutUint64(col.data, x)
   241  	case float64:
   242  		binary.LittleEndian.PutUint64(col.data, math.Float64bits(x))
   243  	case float32:
   244  		binary.LittleEndian.PutUint32(col.data, math.Float32bits(x))
   245  	case string:
   246  		setMutRowBytes(col, hack.Slice(x))
   247  	case []byte:
   248  		setMutRowBytes(col, x)
   249  	case types.BinaryLiteral:
   250  		setMutRowBytes(col, x)
   251  	case types.Duration:
   252  		*(*types.Duration)(unsafe.Pointer(&col.data[0])) = x
   253  	case *types.MyDecimal:
   254  		*(*types.MyDecimal)(unsafe.Pointer(&col.data[0])) = *x
   255  	case types.Time:
   256  		writeTime(col.data, x)
   257  	case types.Enum:
   258  		setMutRowNameValue(col, x.Name, x.Value)
   259  	case types.Set:
   260  		setMutRowNameValue(col, x.Name, x.Value)
   261  	case json.BinaryJSON:
   262  		setMutRowJSON(col, x)
   263  	}
   264  	col.nullBitmap[0] = 1
   265  }
   266  
   267  // SetDatums sets the MutRow with datum slice.
   268  func (mr MutRow) SetDatums(datums ...types.Datum) {
   269  	for i, d := range datums {
   270  		mr.SetDatum(i, d)
   271  	}
   272  }
   273  
   274  // SetDatum sets the MutRow with colIdx and datum.
   275  func (mr MutRow) SetDatum(colIdx int, d types.Datum) {
   276  	col := mr.c.columns[colIdx]
   277  	if d.IsNull() {
   278  		col.nullBitmap[0] = 0
   279  		return
   280  	}
   281  	switch d.Kind() {
   282  	case types.KindInt64, types.KindUint64, types.KindFloat64:
   283  		binary.LittleEndian.PutUint64(mr.c.columns[colIdx].data, d.GetUint64())
   284  	case types.KindFloat32:
   285  		binary.LittleEndian.PutUint32(mr.c.columns[colIdx].data, math.Float32bits(d.GetFloat32()))
   286  	case types.KindString, types.KindBytes, types.KindBinaryLiteral:
   287  		setMutRowBytes(col, d.GetBytes())
   288  	case types.KindMysqlTime:
   289  		writeTime(col.data, d.GetMysqlTime())
   290  	case types.KindMysqlDuration:
   291  		*(*types.Duration)(unsafe.Pointer(&col.data[0])) = d.GetMysqlDuration()
   292  	case types.KindMysqlDecimal:
   293  		*(*types.MyDecimal)(unsafe.Pointer(&col.data[0])) = *d.GetMysqlDecimal()
   294  	case types.KindMysqlJSON:
   295  		setMutRowJSON(col, d.GetMysqlJSON())
   296  	case types.KindMysqlEnum:
   297  		e := d.GetMysqlEnum()
   298  		setMutRowNameValue(col, e.Name, e.Value)
   299  	case types.KindMysqlSet:
   300  		s := d.GetMysqlSet()
   301  		setMutRowNameValue(col, s.Name, s.Value)
   302  	default:
   303  		mr.c.columns[colIdx] = makeMutRowColumn(d.GetValue())
   304  	}
   305  	col.nullBitmap[0] = 1
   306  }
   307  
   308  func setMutRowBytes(col *column, bin []byte) {
   309  	if len(col.data) >= len(bin) {
   310  		col.data = col.data[:len(bin)]
   311  	} else {
   312  		buf := make([]byte, len(bin)+1)
   313  		col.data = buf[:len(bin)]
   314  		col.nullBitmap = buf[len(bin):]
   315  	}
   316  	copy(col.data, bin)
   317  	col.offsets[1] = int32(len(bin))
   318  }
   319  
   320  func setMutRowNameValue(col *column, name string, val uint64) {
   321  	dataLen := len(name) + 8
   322  	if len(col.data) >= dataLen {
   323  		col.data = col.data[:dataLen]
   324  	} else {
   325  		buf := make([]byte, dataLen+1)
   326  		col.data = buf[:dataLen]
   327  		col.nullBitmap = buf[dataLen:]
   328  	}
   329  	binary.LittleEndian.PutUint64(col.data, val)
   330  	copy(col.data[8:], name)
   331  	col.offsets[1] = int32(dataLen)
   332  }
   333  
   334  func setMutRowJSON(col *column, j json.BinaryJSON) {
   335  	dataLen := len(j.Value) + 1
   336  	if len(col.data) >= dataLen {
   337  		col.data = col.data[:dataLen]
   338  	} else {
   339  		// In MutRow, there always exists 1 data in every column,
   340  		// we should allocate one more byte for null bitmap.
   341  		buf := make([]byte, dataLen+1)
   342  		col.data = buf[:dataLen]
   343  		col.nullBitmap = buf[dataLen:]
   344  	}
   345  	col.data[0] = j.TypeCode
   346  	copy(col.data[1:], j.Value)
   347  	col.offsets[1] = int32(dataLen)
   348  }