github.com/whtcorpsinc/milevadb-prod@v0.0.0-20211104133533-f57f4be3b597/soliton/rowcodec/encoder.go (about)

     1  // Copyright 2020 WHTCORPS INC, 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 rowcodec
    15  
    16  import (
    17  	"math"
    18  	"sort"
    19  	"time"
    20  
    21  	"github.com/whtcorpsinc/errors"
    22  	"github.com/whtcorpsinc/BerolinaSQL/allegrosql"
    23  	"github.com/whtcorpsinc/BerolinaSQL/terror"
    24  	"github.com/whtcorpsinc/milevadb/stochastikctx/stmtctx"
    25  	"github.com/whtcorpsinc/milevadb/types"
    26  	"github.com/whtcorpsinc/milevadb/soliton/codec"
    27  )
    28  
    29  // CausetEncoder is used to encode a event.
    30  type CausetEncoder struct {
    31  	event
    32  	tempDefCausIDs []int64
    33  	values     []*types.Causet
    34  	// Enable indicates whether this causetCausetEncoder should be use.
    35  	Enable bool
    36  }
    37  
    38  // Encode encodes a event from a datums slice.
    39  func (causetCausetEncoder *CausetEncoder) Encode(sc *stmtctx.StatementContext, defCausIDs []int64, values []types.Causet, buf []byte) ([]byte, error) {
    40  	causetCausetEncoder.reset()
    41  	causetCausetEncoder.appendDefCausVals(defCausIDs, values)
    42  	numDefCauss, notNullIdx := causetCausetEncoder.reformatDefCauss()
    43  	err := causetCausetEncoder.encodeRowDefCauss(sc, numDefCauss, notNullIdx)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	return causetCausetEncoder.event.toBytes(buf[:0]), nil
    48  }
    49  
    50  func (causetCausetEncoder *CausetEncoder) reset() {
    51  	causetCausetEncoder.large = false
    52  	causetCausetEncoder.numNotNullDefCauss = 0
    53  	causetCausetEncoder.numNullDefCauss = 0
    54  	causetCausetEncoder.data = causetCausetEncoder.data[:0]
    55  	causetCausetEncoder.tempDefCausIDs = causetCausetEncoder.tempDefCausIDs[:0]
    56  	causetCausetEncoder.values = causetCausetEncoder.values[:0]
    57  	causetCausetEncoder.offsets32 = causetCausetEncoder.offsets32[:0]
    58  	causetCausetEncoder.offsets = causetCausetEncoder.offsets[:0]
    59  }
    60  
    61  func (causetCausetEncoder *CausetEncoder) appendDefCausVals(defCausIDs []int64, values []types.Causet) {
    62  	for i, defCausID := range defCausIDs {
    63  		causetCausetEncoder.appendDefCausVal(defCausID, &values[i])
    64  	}
    65  }
    66  
    67  func (causetCausetEncoder *CausetEncoder) appendDefCausVal(defCausID int64, d *types.Causet) {
    68  	if defCausID > 255 {
    69  		causetCausetEncoder.large = true
    70  	}
    71  	if d.IsNull() {
    72  		causetCausetEncoder.numNullDefCauss++
    73  	} else {
    74  		causetCausetEncoder.numNotNullDefCauss++
    75  	}
    76  	causetCausetEncoder.tempDefCausIDs = append(causetCausetEncoder.tempDefCausIDs, defCausID)
    77  	causetCausetEncoder.values = append(causetCausetEncoder.values, d)
    78  }
    79  
    80  func (causetCausetEncoder *CausetEncoder) reformatDefCauss() (numDefCauss, notNullIdx int) {
    81  	r := &causetCausetEncoder.event
    82  	numDefCauss = len(causetCausetEncoder.tempDefCausIDs)
    83  	nullIdx := numDefCauss - int(r.numNullDefCauss)
    84  	notNullIdx = 0
    85  	if r.large {
    86  		r.initDefCausIDs32()
    87  		r.initOffsets32()
    88  	} else {
    89  		r.initDefCausIDs()
    90  		r.initOffsets()
    91  	}
    92  	for i, defCausID := range causetCausetEncoder.tempDefCausIDs {
    93  		if causetCausetEncoder.values[i].IsNull() {
    94  			if r.large {
    95  				r.defCausIDs32[nullIdx] = uint32(defCausID)
    96  			} else {
    97  				r.defCausIDs[nullIdx] = byte(defCausID)
    98  			}
    99  			nullIdx++
   100  		} else {
   101  			if r.large {
   102  				r.defCausIDs32[notNullIdx] = uint32(defCausID)
   103  			} else {
   104  				r.defCausIDs[notNullIdx] = byte(defCausID)
   105  			}
   106  			causetCausetEncoder.values[notNullIdx] = causetCausetEncoder.values[i]
   107  			notNullIdx++
   108  		}
   109  	}
   110  	if r.large {
   111  		largeNotNullSorter := (*largeNotNullSorter)(causetCausetEncoder)
   112  		sort.Sort(largeNotNullSorter)
   113  		if r.numNullDefCauss > 0 {
   114  			largeNullSorter := (*largeNullSorter)(causetCausetEncoder)
   115  			sort.Sort(largeNullSorter)
   116  		}
   117  	} else {
   118  		smallNotNullSorter := (*smallNotNullSorter)(causetCausetEncoder)
   119  		sort.Sort(smallNotNullSorter)
   120  		if r.numNullDefCauss > 0 {
   121  			smallNullSorter := (*smallNullSorter)(causetCausetEncoder)
   122  			sort.Sort(smallNullSorter)
   123  		}
   124  	}
   125  	return
   126  }
   127  
   128  func (causetCausetEncoder *CausetEncoder) encodeRowDefCauss(sc *stmtctx.StatementContext, numDefCauss, notNullIdx int) error {
   129  	r := &causetCausetEncoder.event
   130  	for i := 0; i < notNullIdx; i++ {
   131  		d := causetCausetEncoder.values[i]
   132  		var err error
   133  		r.data, err = encodeValueCauset(sc, d, r.data)
   134  		if err != nil {
   135  			return err
   136  		}
   137  		// handle convert to large
   138  		if len(r.data) > math.MaxUint16 && !r.large {
   139  			r.initDefCausIDs32()
   140  			for j := 0; j < numDefCauss; j++ {
   141  				r.defCausIDs32[j] = uint32(r.defCausIDs[j])
   142  			}
   143  			r.initOffsets32()
   144  			for j := 0; j <= i; j++ {
   145  				r.offsets32[j] = uint32(r.offsets[j])
   146  			}
   147  			r.large = true
   148  		}
   149  		if r.large {
   150  			r.offsets32[i] = uint32(len(r.data))
   151  		} else {
   152  			r.offsets[i] = uint16(len(r.data))
   153  		}
   154  	}
   155  	return nil
   156  }
   157  
   158  // encodeValueCauset encodes one event causet entry into bytes.
   159  // due to encode as value, this method will flatten value type like blockcodec.flatten
   160  func encodeValueCauset(sc *stmtctx.StatementContext, d *types.Causet, buffer []byte) (nBuffer []byte, err error) {
   161  	switch d.HoTT() {
   162  	case types.HoTTInt64:
   163  		buffer = encodeInt(buffer, d.GetInt64())
   164  	case types.HoTTUint64:
   165  		buffer = encodeUint(buffer, d.GetUint64())
   166  	case types.HoTTString, types.HoTTBytes:
   167  		buffer = append(buffer, d.GetBytes()...)
   168  	case types.HoTTMysqlTime:
   169  		// for allegrosql datetime, timestamp and date type
   170  		t := d.GetMysqlTime()
   171  		if t.Type() == allegrosql.TypeTimestamp && sc != nil && sc.TimeZone != time.UTC {
   172  			err = t.ConvertTimeZone(sc.TimeZone, time.UTC)
   173  			if err != nil {
   174  				return
   175  			}
   176  		}
   177  		var v uint64
   178  		v, err = t.ToPackedUint()
   179  		if err != nil {
   180  			return
   181  		}
   182  		buffer = encodeUint(buffer, v)
   183  	case types.HoTTMysqlDuration:
   184  		buffer = encodeInt(buffer, int64(d.GetMysqlDuration().Duration))
   185  	case types.HoTTMysqlEnum:
   186  		buffer = encodeUint(buffer, d.GetMysqlEnum().Value)
   187  	case types.HoTTMysqlSet:
   188  		buffer = encodeUint(buffer, d.GetMysqlSet().Value)
   189  	case types.HoTTBinaryLiteral, types.HoTTMysqlBit:
   190  		// We don't need to handle errors here since the literal is ensured to be able to causetstore in uint64 in convertToMysqlBit.
   191  		var val uint64
   192  		val, err = d.GetBinaryLiteral().ToInt(sc)
   193  		if err != nil {
   194  			return
   195  		}
   196  		buffer = encodeUint(buffer, val)
   197  	case types.HoTTFloat32, types.HoTTFloat64:
   198  		buffer = codec.EncodeFloat(buffer, d.GetFloat64())
   199  	case types.HoTTMysqlDecimal:
   200  		buffer, err = codec.EncodeDecimal(buffer, d.GetMysqlDecimal(), d.Length(), d.Frac())
   201  		if err != nil && sc != nil {
   202  			if terror.ErrorEqual(err, types.ErrTruncated) {
   203  				err = sc.HandleTruncate(err)
   204  			} else if terror.ErrorEqual(err, types.ErrOverflow) {
   205  				err = sc.HandleOverflow(err, err)
   206  			}
   207  		}
   208  	case types.HoTTMysqlJSON:
   209  		j := d.GetMysqlJSON()
   210  		buffer = append(buffer, j.TypeCode)
   211  		buffer = append(buffer, j.Value...)
   212  	default:
   213  		err = errors.Errorf("unsupport encode type %d", d.HoTT())
   214  	}
   215  	nBuffer = buffer
   216  	return
   217  }