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  }