github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/col/coldataext/datum_vec.go (about)

     1  // Copyright 2020 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package coldataext
    12  
    13  import (
    14  	"fmt"
    15  
    16  	"github.com/cockroachdb/cockroach/pkg/col/coldata"
    17  	"github.com/cockroachdb/cockroach/pkg/sql/colexecbase/colexecerror"
    18  	"github.com/cockroachdb/cockroach/pkg/sql/sem/tree"
    19  	"github.com/cockroachdb/cockroach/pkg/sql/sqlbase"
    20  	"github.com/cockroachdb/cockroach/pkg/sql/types"
    21  	"github.com/cockroachdb/cockroach/pkg/util/encoding"
    22  )
    23  
    24  // Datum wraps a tree.Datum. This is the struct that datumVec.Get() returns.
    25  type Datum struct {
    26  	tree.Datum
    27  }
    28  
    29  var _ coldata.Datum = &Datum{}
    30  var _ tree.Datum = &Datum{}
    31  
    32  // datumVec is a vector of tree.Datums of the same type.
    33  type datumVec struct {
    34  	// t is the type of the tree.Datums that datumVec stores.
    35  	t *types.T
    36  	// data is the underlying data stored in datumVec.
    37  	data []tree.Datum
    38  	// evalCtx is required for most of the methods of tree.Datum interface.
    39  	evalCtx *tree.EvalContext
    40  
    41  	scratch []byte
    42  	da      sqlbase.DatumAlloc
    43  }
    44  
    45  var _ coldata.DatumVec = &datumVec{}
    46  
    47  // newDatumVec returns a datumVec struct with capacity of n.
    48  func newDatumVec(t *types.T, n int, evalCtx *tree.EvalContext) coldata.DatumVec {
    49  	return &datumVec{
    50  		t:       t,
    51  		data:    make([]tree.Datum, n),
    52  		evalCtx: evalCtx,
    53  	}
    54  }
    55  
    56  // BinFn evaluates the provided binary function between the receiver and other.
    57  // dVec is the datumVec that stores either d or other (it doesn't matter which
    58  // one because it is used only to supply the eval context).
    59  func (d *Datum) BinFn(binFn *tree.BinOp, dVec, other interface{}) (tree.Datum, error) {
    60  	return binFn.Fn(dVec.(*datumVec).evalCtx, d.Datum, maybeUnwrapDatum(other))
    61  }
    62  
    63  // CompareDatum returns the comparison between d and other. The other is
    64  // assumed to be tree.Datum. dVec is the datumVec that stores either d or other
    65  // (it doesn't matter which one because it is used only to supply the eval
    66  // context).
    67  // Note that the method is named differently from "Compare" so that we do not
    68  // overload tree.Datum.Compare method.
    69  func (d *Datum) CompareDatum(dVec, other interface{}) int {
    70  	return d.Datum.Compare(dVec.(*datumVec).evalCtx, maybeUnwrapDatum(other))
    71  }
    72  
    73  // Hash returns the hash of the datum as a byte slice.
    74  func (d *Datum) Hash(da *sqlbase.DatumAlloc) []byte {
    75  	ed := sqlbase.EncDatum{Datum: maybeUnwrapDatum(d)}
    76  	b, err := ed.Fingerprint(d.ResolvedType(), da, nil /* appendTo */)
    77  	if err != nil {
    78  		colexecerror.InternalError(err)
    79  	}
    80  	return b
    81  }
    82  
    83  // Get implements coldata.DatumVec interface.
    84  func (dv *datumVec) Get(i int) coldata.Datum {
    85  	dv.maybeSetDNull(i)
    86  	return &Datum{Datum: dv.data[i]}
    87  }
    88  
    89  // Set implements coldata.DatumVec interface.
    90  func (dv *datumVec) Set(i int, v coldata.Datum) {
    91  	datum := maybeUnwrapDatum(v)
    92  	dv.assertValidDatum(datum)
    93  	dv.data[i] = datum
    94  }
    95  
    96  // Slice implements coldata.DatumVec interface.
    97  func (dv *datumVec) Slice(start, end int) coldata.DatumVec {
    98  	return &datumVec{
    99  		t:       dv.t,
   100  		data:    dv.data[start:end],
   101  		evalCtx: dv.evalCtx,
   102  	}
   103  }
   104  
   105  // CopySlice implements coldata.DatumVec interface.
   106  func (dv *datumVec) CopySlice(src coldata.DatumVec, destIdx, srcStartIdx, srcEndIdx int) {
   107  	castSrc := src.(*datumVec)
   108  	dv.assertSameTypeFamily(castSrc.t)
   109  	copy(dv.data[destIdx:], castSrc.data[srcStartIdx:srcEndIdx])
   110  }
   111  
   112  // AppendSlice implements coldata.DatumVec interface.
   113  func (dv *datumVec) AppendSlice(src coldata.DatumVec, destIdx, srcStartIdx, srcEndIdx int) {
   114  	castSrc := src.(*datumVec)
   115  	dv.assertSameTypeFamily(castSrc.t)
   116  	dv.data = append(dv.data[:destIdx], castSrc.data[srcStartIdx:srcEndIdx]...)
   117  }
   118  
   119  // AppendVal implements coldata.DatumVec interface.
   120  func (dv *datumVec) AppendVal(v coldata.Datum) {
   121  	datum := maybeUnwrapDatum(v)
   122  	dv.assertValidDatum(datum)
   123  	dv.data = append(dv.data, datum)
   124  }
   125  
   126  // SetLength implements coldata.DatumVec interface.
   127  func (dv *datumVec) SetLength(l int) {
   128  	dv.data = dv.data[:l]
   129  }
   130  
   131  // Len implements coldata.DatumVec interface.
   132  func (dv *datumVec) Len() int {
   133  	return len(dv.data)
   134  }
   135  
   136  // Cap implements coldata.DatumVec interface.
   137  func (dv *datumVec) Cap() int {
   138  	return cap(dv.data)
   139  }
   140  
   141  // MarshalAt implements coldata.DatumVec interface.
   142  func (dv *datumVec) MarshalAt(i int) ([]byte, error) {
   143  	dv.maybeSetDNull(i)
   144  	return sqlbase.EncodeTableValue(
   145  		nil /* appendTo */, sqlbase.ColumnID(encoding.NoColumnID), dv.data[i], dv.scratch,
   146  	)
   147  }
   148  
   149  // UnmarshalTo implements coldata.DatumVec interface.
   150  // index i.
   151  func (dv *datumVec) UnmarshalTo(i int, b []byte) error {
   152  	var err error
   153  	dv.data[i], _, err = sqlbase.DecodeTableValue(&dv.da, dv.t, b)
   154  	return err
   155  }
   156  
   157  // assertValidDatum asserts that the given datum is valid to be stored in this
   158  // datumVec.
   159  func (dv *datumVec) assertValidDatum(datum tree.Datum) {
   160  	if datum != tree.DNull {
   161  		dv.assertSameTypeFamily(datum.ResolvedType())
   162  	}
   163  }
   164  
   165  // assertSameTypeFamily asserts that the provided type is of the same type
   166  // family as the datums this datumVec stores.
   167  func (dv *datumVec) assertSameTypeFamily(t *types.T) {
   168  	if dv.t.Family() != t.Family() {
   169  		colexecerror.InternalError(
   170  			fmt.Sprintf("cannot use value of type %+v on a datumVec of type %+v", t, dv.t),
   171  		)
   172  	}
   173  }
   174  
   175  // maybeSetDNull checks whether the datum at index i is nil, and if so, sets it
   176  // to DNull. This is needed because we store whether a value is NULL in a
   177  // separate Nulls vector, but we also might be accessing the garbage value from
   178  // the vectors in certain code paths (for example, in Vec.Append).
   179  func (dv *datumVec) maybeSetDNull(i int) {
   180  	if dv.data[i] == nil {
   181  		dv.data[i] = tree.DNull
   182  	}
   183  }
   184  
   185  // maybeUnwrapDatum possibly unwraps tree.Datum from inside of Datum. It also
   186  // checks whether v is nil and returns tree.DNull if it is.
   187  func maybeUnwrapDatum(v coldata.Datum) tree.Datum {
   188  	if v == nil {
   189  		return tree.DNull
   190  	}
   191  	if datum, ok := v.(*Datum); ok {
   192  		return datum.Datum
   193  	} else if datum, ok := v.(tree.Datum); ok {
   194  		return datum
   195  	}
   196  	colexecerror.InternalError(fmt.Sprintf("unexpected value: %v", v))
   197  	// This code is unreachable, but the compiler cannot infer that.
   198  	return nil
   199  }