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 }