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 }