github.com/dolthub/go-mysql-server@v0.18.0/sql/row_frame.go (about) 1 // Copyright 2020-2021 Dolthub, 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 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 package sql 16 17 import ( 18 "sync" 19 20 querypb "github.com/dolthub/vitess/go/vt/proto/query" 21 ) 22 23 const ( 24 valueArrSize = 64 25 fieldArrSize = 2048 26 ) 27 28 // Row2 is a slice of values 29 type Row2 []Value 30 31 // GetField returns the Value for the ith field in this row. 32 func (r Row2) GetField(i int) Value { 33 return r[i] 34 } 35 36 // Len returns the number of fields of this row 37 func (r Row2) Len() int { 38 return len(r) 39 } 40 41 // Value is a logical index into a Row2. For efficiency reasons, use sparingly. 42 type Value struct { 43 Typ querypb.Type 44 Val ValueBytes 45 } 46 47 // IsNull returns whether this value represents NULL 48 func (v Value) IsNull() bool { 49 return v.Val == nil || v.Typ == querypb.Type_NULL_TYPE 50 } 51 52 type ValueBytes []byte 53 54 type RowFrame struct { 55 Types []querypb.Type 56 57 // Values are the values this row. 58 Values []ValueBytes 59 60 // varr is used as the backing array for the |Values| 61 // slice when len(Values) <= valueArrSize 62 varr [valueArrSize][]ValueBytes 63 64 // farr is used as the backing array for |Value.Val| 65 // slices when there is capacity 66 farr [fieldArrSize]byte 67 68 // off tracks the next available position in |farr| 69 off uint16 70 } 71 72 func NewRowFrame(vals ...Value) (f *RowFrame) { 73 f = framePool.Get().(*RowFrame) 74 f.Append(vals...) 75 return 76 } 77 78 var framePool = sync.Pool{New: makeRowFrame} 79 80 func makeRowFrame() interface{} { 81 return &RowFrame{} 82 } 83 84 // Recycle returns this row frame to the shared pool. Further use will result in concurrency errors. All RowFrames 85 // should be recycled when they are no longer being used to prevent resource leaks. 86 func (f *RowFrame) Recycle() { 87 f.Clear() 88 framePool.Put(f) 89 } 90 91 // Row2 returns the underlying row value in this frame. Does not make a deep copy of underlying byte arrays, so 92 // further modification to this frame may result in the returned value changing as well. 93 func (f *RowFrame) Row2() Row2 { 94 if f == nil { 95 return nil 96 } 97 98 rs := make(Row2, len(f.Values)) 99 for i := range f.Values { 100 rs[i] = Value{ 101 Typ: f.Types[i], 102 Val: f.Values[i], 103 } 104 } 105 return rs 106 } 107 108 // Row2Copy returns the row in this frame as a deep copy of the underlying byte arrays. Useful when reusing the 109 // RowFrame object via Clear() 110 func (f *RowFrame) Row2Copy() Row2 { 111 rs := make(Row2, len(f.Values)) 112 // TODO: it would be faster here to just copy the entire value backing array in one pass 113 for i := range f.Values { 114 v := make(ValueBytes, len(f.Values[i])) 115 copy(v, f.Values[i]) 116 rs[i] = Value{ 117 Typ: f.Types[i], 118 Val: v, 119 } 120 } 121 return rs 122 } 123 124 // Clear clears this row frame for reuse. The underlying byte arrays are not zeroed out or discarded, but will be 125 // overwritten by future calls to Append. 126 func (f *RowFrame) Clear() { 127 f.Types = f.Types[:0] 128 f.Values = f.Values[:0] 129 f.off = 0 130 } 131 132 // Append appends the values given into this frame. 133 func (f *RowFrame) Append(vals ...Value) { 134 for _, v := range vals { 135 f.append(v) 136 } 137 } 138 139 // AppendMany appends the types and values given, as two parallel arrays, into this frame. 140 func (f *RowFrame) AppendMany(types []querypb.Type, vals []ValueBytes) { 141 // TODO: one big copy here would be better probably, need to benchmark 142 for i := range vals { 143 f.appendTypeAndVal(types[i], vals[i]) 144 } 145 } 146 147 func (f *RowFrame) append(v Value) { 148 buf := f.getBuffer(v) 149 copy(buf, v.Val) 150 v.Val = buf 151 152 f.Types = append(f.Types, v.Typ) 153 154 // if |f.Values| grows past |len(f.varr)| 155 // we'll allocate a new backing array here 156 f.Values = append(f.Values, v.Val) 157 } 158 159 func (f *RowFrame) appendTypeAndVal(typ querypb.Type, val ValueBytes) { 160 v := f.bufferForBytes(val) 161 copy(v, val) 162 163 f.Types = append(f.Types, typ) 164 165 // if |f.Values| grows past |len(f.varr)| 166 // we'll allocate a new backing array here 167 f.Values = append(f.Values, v) 168 } 169 170 func (f *RowFrame) getBuffer(v Value) (buf []byte) { 171 return f.bufferForBytes(v.Val) 172 } 173 174 func (f *RowFrame) bufferForBytes(v ValueBytes) (buf []byte) { 175 if f.checkCapacity(v) { 176 start := f.off 177 f.off += uint16(len(v)) 178 stop := f.off 179 buf = f.farr[start:stop] 180 } else { 181 buf = make([]byte, len(v)) 182 } 183 184 return 185 } 186 187 func (f *RowFrame) checkCapacity(v ValueBytes) bool { 188 return len(v) <= (len(f.farr) - int(f.off)) 189 }