// Copyright 2018 PingCAP, Inc. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // See the License for the specific language governing permissions and // limitations under the License. package chunk import ( "unsafe" "github.com/pingcap/tidb/types" "github.com/pingcap/tidb/types/json" ) func (c *column) appendDuration(dur types.Duration) { c.appendInt64(int64(dur.Duration)) } func (c *column) appendMyDecimal(dec *types.MyDecimal) { *(*types.MyDecimal)(unsafe.Pointer(&c.elemBuf[0])) = *dec c.finishAppendFixed() } func (c *column) appendNameValue(name string, val uint64) { var buf [8]byte *(*uint64)(unsafe.Pointer(&buf[0])) = val c.data = append(c.data, buf[:]...) c.data = append(c.data, name...) c.finishAppendVar() } func (c *column) appendJSON(j json.BinaryJSON) { c.data = append(c.data, j.TypeCode) c.data = append(c.data, j.Value...) c.finishAppendVar() } type column struct { length int nullCount int nullBitmap []byte offsets []int32 data []byte elemBuf []byte } func (c *column) isFixed() bool { return c.elemBuf != nil } func (c *column) reset() { c.length = 0 c.nullCount = 0 c.nullBitmap = c.nullBitmap[:0] if len(c.offsets) > 0 { // The first offset is always 0, it makes slicing the data easier, we need to keep it. c.offsets = c.offsets[:1] } c.data = c.data[:0] } func (c *column) isNull(rowIdx int) bool { nullByte := c.nullBitmap[rowIdx/8] return nullByte&(1<<(uint(rowIdx)&7)) == 0 } func (c *column) copyConstruct() *column { newCol := &column{length: c.length, nullCount: c.nullCount} newCol.nullBitmap = append(newCol.nullBitmap, c.nullBitmap...) newCol.offsets = append(newCol.offsets, c.offsets...) newCol.data = append(newCol.data, c.data...) newCol.elemBuf = append(newCol.elemBuf, c.elemBuf...) return newCol } func (c *column) appendNullBitmap(notNull bool) { idx := c.length >> 3 if idx >= len(c.nullBitmap) { c.nullBitmap = append(c.nullBitmap, 0) } if notNull { pos := uint(c.length) & 7 c.nullBitmap[idx] |= byte(1 << pos) } else { c.nullCount++ } } // appendMultiSameNullBitmap appends multiple same bit value to `nullBitMap`. // notNull means not null. // num means the number of bits that should be appended. func (c *column) appendMultiSameNullBitmap(notNull bool, num int) { numNewBytes := ((c.length + num + 7) >> 3) - len(c.nullBitmap) b := byte(0) if notNull { b = 0xff } for i := 0; i < numNewBytes; i++ { c.nullBitmap = append(c.nullBitmap, b) } if !notNull { c.nullCount += num return } // 1. Set all the remaining bits in the last slot of old c.numBitMap to 1. numRemainingBits := uint(c.length % 8) bitMask := byte(^((1 << numRemainingBits) - 1)) c.nullBitmap[c.length/8] |= bitMask // 2. Set all the redundant bits in the last slot of new c.numBitMap to 0. numRedundantBits := uint(len(c.nullBitmap)*8 - c.length - num) bitMask = byte(1<<(8-numRedundantBits)) - 1 c.nullBitmap[len(c.nullBitmap)-1] &= bitMask } func (c *column) appendNull() { c.appendNullBitmap(false) if c.isFixed() { c.data = append(c.data, c.elemBuf...) } else { c.offsets = append(c.offsets, c.offsets[c.length]) } c.length++ } func (c *column) finishAppendFixed() { c.data = append(c.data, c.elemBuf...) c.appendNullBitmap(true) c.length++ } func (c *column) appendInt64(i int64) { *(*int64)(unsafe.Pointer(&c.elemBuf[0])) = i c.finishAppendFixed() } func (c *column) appendUint64(u uint64) { *(*uint64)(unsafe.Pointer(&c.elemBuf[0])) = u c.finishAppendFixed() } func (c *column) appendFloat32(f float32) { *(*float32)(unsafe.Pointer(&c.elemBuf[0])) = f c.finishAppendFixed() } func (c *column) appendFloat64(f float64) { *(*float64)(unsafe.Pointer(&c.elemBuf[0])) = f c.finishAppendFixed() } func (c *column) finishAppendVar() { c.appendNullBitmap(true) c.offsets = append(c.offsets, int32(len(c.data))) c.length++ } func (c *column) appendString(str string) { c.data = append(c.data, str...) c.finishAppendVar() } func (c *column) appendBytes(b []byte) { c.data = append(c.data, b...) c.finishAppendVar() } func (c *column) appendTime(t types.Time) { writeTime(c.elemBuf, t) c.finishAppendFixed() }