github.com/apache/arrow/go/v14@v14.0.2/arrow/compute/exec/span.go (about)

     1  // Licensed to the Apache Software Foundation (ASF) under one
     2  // or more contributor license agreements.  See the NOTICE file
     3  // distributed with this work for additional information
     4  // regarding copyright ownership.  The ASF licenses this file
     5  // to you under the Apache License, Version 2.0 (the
     6  // "License"); you may not use this file except in compliance
     7  // with the License.  You may obtain a copy of the License at
     8  //
     9  // http://www.apache.org/licenses/LICENSE-2.0
    10  //
    11  // Unless required by applicable law or agreed to in writing, software
    12  // distributed under the License is distributed on an "AS IS" BASIS,
    13  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    14  // See the License for the specific language governing permissions and
    15  // limitations under the License.
    16  
    17  //go:build go1.18
    18  
    19  package exec
    20  
    21  import (
    22  	"reflect"
    23  	"sync/atomic"
    24  	"unsafe"
    25  
    26  	"github.com/apache/arrow/go/v14/arrow"
    27  	"github.com/apache/arrow/go/v14/arrow/array"
    28  	"github.com/apache/arrow/go/v14/arrow/bitutil"
    29  	"github.com/apache/arrow/go/v14/arrow/memory"
    30  	"github.com/apache/arrow/go/v14/arrow/scalar"
    31  )
    32  
    33  // BufferSpan is a lightweight Buffer holder for ArraySpans that does not
    34  // take ownership of the underlying memory.Buffer at all or could be
    35  // used to reference raw byte slices instead.
    36  type BufferSpan struct {
    37  	// Buf should be the byte slice representing this buffer, if this is
    38  	// nil then this bufferspan should be considered empty.
    39  	Buf []byte
    40  	// Owner should point to an underlying parent memory.Buffer if this
    41  	// memory is owned by a different, existing, buffer. Retain is not
    42  	// called on this buffer, so it must not be released as long as
    43  	// this BufferSpan refers to it.
    44  	Owner *memory.Buffer
    45  	// SelfAlloc tracks whether or not this bufferspan is the only owner
    46  	// of the Owning memory.Buffer. This happens when preallocating
    47  	// memory or if a kernel allocates it's own buffer for a result.
    48  	// In these cases, we have to know so we can properly maintain the
    49  	// refcount if this is later turned into an ArrayData object.
    50  	SelfAlloc bool
    51  }
    52  
    53  // SetBuffer sets the given buffer into this BufferSpan and marks
    54  // SelfAlloc as false. This should be called when setting a buffer
    55  // that is externally owned/created.
    56  func (b *BufferSpan) SetBuffer(buf *memory.Buffer) {
    57  	b.Buf = buf.Bytes()
    58  	b.Owner = buf
    59  	b.SelfAlloc = false
    60  }
    61  
    62  // WrapBuffer wraps this bufferspan around a buffer and marks
    63  // SelfAlloc as true. This should be called when setting a buffer
    64  // that was allocated as part of an execution rather than just
    65  // re-using an existing buffer from an input array.
    66  func (b *BufferSpan) WrapBuffer(buf *memory.Buffer) {
    67  	b.Buf = buf.Bytes()
    68  	b.Owner = buf
    69  	b.SelfAlloc = true
    70  }
    71  
    72  // ArraySpan is a light-weight, non-owning version of arrow.ArrayData
    73  // for more efficient handling with computation and engines. We use
    74  // explicit go Arrays to define the buffers and some scratch space
    75  // for easily populating and shifting around pointers to memory without
    76  // having to worry about and deal with retain/release during calculations.
    77  type ArraySpan struct {
    78  	Type    arrow.DataType
    79  	Len     int64
    80  	Nulls   int64
    81  	Offset  int64
    82  	Buffers [3]BufferSpan
    83  
    84  	// Scratch is a holding spot for things such as
    85  	// offsets or union type codes when converting from scalars
    86  	Scratch [2]uint64
    87  
    88  	Children []ArraySpan
    89  }
    90  
    91  // if an error is encountered, call Release on a preallocated span
    92  // to ensure it releases any self-allocated buffers, it will
    93  // not call release on buffers it doesn't own (SelfAlloc != true)
    94  func (a *ArraySpan) Release() {
    95  	for _, c := range a.Children {
    96  		c.Release()
    97  	}
    98  
    99  	for _, b := range a.Buffers {
   100  		if b.SelfAlloc {
   101  			b.Owner.Release()
   102  		}
   103  	}
   104  }
   105  
   106  func (a *ArraySpan) MayHaveNulls() bool {
   107  	return atomic.LoadInt64(&a.Nulls) != 0 && a.Buffers[0].Buf != nil
   108  }
   109  
   110  // UpdateNullCount will count the bits in the null bitmap and update the
   111  // number of nulls if the current null count is unknown, otherwise it just
   112  // returns the value of a.Nulls
   113  func (a *ArraySpan) UpdateNullCount() int64 {
   114  	curNulls := atomic.LoadInt64(&a.Nulls)
   115  	if curNulls != array.UnknownNullCount {
   116  		return curNulls
   117  	}
   118  
   119  	newNulls := a.Len - int64(bitutil.CountSetBits(a.Buffers[0].Buf, int(a.Offset), int(a.Len)))
   120  	atomic.StoreInt64(&a.Nulls, newNulls)
   121  	return newNulls
   122  }
   123  
   124  // Dictionary returns a pointer to the array span for the dictionary which
   125  // we will always place as the first (and only) child if it exists.
   126  func (a *ArraySpan) Dictionary() *ArraySpan { return &a.Children[0] }
   127  
   128  // NumBuffers returns the number of expected buffers for this type
   129  func (a *ArraySpan) NumBuffers() int { return getNumBuffers(a.Type) }
   130  
   131  // MakeData generates an arrow.ArrayData object for this ArraySpan,
   132  // properly updating the buffer ref count if necessary.
   133  func (a *ArraySpan) MakeData() arrow.ArrayData {
   134  	var bufs [3]*memory.Buffer
   135  	for i := range bufs {
   136  		b := a.GetBuffer(i)
   137  		bufs[i] = b
   138  		if b != nil && a.Buffers[i].SelfAlloc {
   139  			// if this buffer is just a pointer to another existing buffer
   140  			// then we never bumped the refcount for that buffer.
   141  			// As a result, we won't call release here so that the call
   142  			// to array.NewData properly updates the ref counts of the buffers.
   143  			// If instead this buffer was allocated during calculation
   144  			// (such as during prealloc or by a kernel itself)
   145  			// then we need to release after we create the ArrayData so that it
   146  			// maintains the correct refcount of 1, giving the resulting
   147  			// ArrayData object ownership of this buffer.
   148  			defer b.Release()
   149  		}
   150  	}
   151  
   152  	var (
   153  		nulls    = int(atomic.LoadInt64(&a.Nulls))
   154  		length   = int(a.Len)
   155  		off      = int(a.Offset)
   156  		dt       = a.Type
   157  		children []arrow.ArrayData
   158  	)
   159  
   160  	if a.Type.ID() == arrow.NULL {
   161  		nulls = length
   162  	} else if len(a.Buffers[0].Buf) == 0 {
   163  		nulls = 0
   164  	}
   165  
   166  	// we use a.Type for the NewData call at the end, so we can
   167  	// handle extension types by using dt to point to the storage type
   168  	// and let the proper extension type get set into the ArrayData
   169  	// object we return.
   170  	if dt.ID() == arrow.EXTENSION {
   171  		dt = dt.(arrow.ExtensionType).StorageType()
   172  	}
   173  
   174  	if dt.ID() == arrow.DICTIONARY {
   175  		result := array.NewData(a.Type, length, bufs[:a.NumBuffers()], nil, nulls, off)
   176  		dict := a.Dictionary().MakeData()
   177  		defer dict.Release()
   178  		result.SetDictionary(dict)
   179  		return result
   180  	} else if dt.ID() == arrow.DENSE_UNION || dt.ID() == arrow.SPARSE_UNION {
   181  		bufs[0] = nil
   182  		nulls = 0
   183  	}
   184  
   185  	if len(a.Children) > 0 {
   186  		children = make([]arrow.ArrayData, len(a.Children))
   187  		for i, c := range a.Children {
   188  			d := c.MakeData()
   189  			defer d.Release()
   190  			children[i] = d
   191  		}
   192  	}
   193  	return array.NewData(a.Type, length, bufs[:a.NumBuffers()], children, nulls, off)
   194  }
   195  
   196  // MakeArray is a convenience function for calling array.MakeFromData(a.MakeData())
   197  func (a *ArraySpan) MakeArray() arrow.Array {
   198  	d := a.MakeData()
   199  	defer d.Release()
   200  	return array.MakeFromData(d)
   201  }
   202  
   203  // SetSlice updates the offset and length of this ArraySpan to refer to
   204  // a specific slice of the underlying buffers.
   205  func (a *ArraySpan) SetSlice(off, length int64) {
   206  	if off == a.Offset && length == a.Len {
   207  		// don't modify the nulls if the slice is the entire span
   208  		return
   209  	}
   210  
   211  	if a.Type.ID() != arrow.NULL {
   212  		if a.Nulls != 0 {
   213  			if a.Nulls == a.Len {
   214  				a.Nulls = length
   215  			} else {
   216  				a.Nulls = array.UnknownNullCount
   217  			}
   218  		}
   219  	} else {
   220  		a.Nulls = length
   221  	}
   222  
   223  	a.Offset, a.Len = off, length
   224  }
   225  
   226  // GetBuffer returns the buffer for the requested index. If this buffer
   227  // is owned by another array/arrayspan the Owning buffer is returned,
   228  // otherwise if this slice has no owning buffer, we call NewBufferBytes
   229  // to wrap it as a memory.Buffer. Can also return nil if there is no
   230  // buffer in this index.
   231  func (a *ArraySpan) GetBuffer(idx int) *memory.Buffer {
   232  	buf := a.Buffers[idx]
   233  	switch {
   234  	case buf.Owner != nil:
   235  		return buf.Owner
   236  	case buf.Buf != nil:
   237  		return memory.NewBufferBytes(buf.Buf)
   238  	}
   239  	return nil
   240  }
   241  
   242  // convenience function to resize the children slice if necessary,
   243  // or just shrink the slice without re-allocating if there's enough
   244  // capacity already.
   245  func (a *ArraySpan) resizeChildren(i int) {
   246  	if cap(a.Children) >= i {
   247  		a.Children = a.Children[:i]
   248  	} else {
   249  		a.Children = make([]ArraySpan, i)
   250  	}
   251  }
   252  
   253  // convenience function for populating the offsets buffer from a scalar
   254  // value's size.
   255  func setOffsetsForScalar[T int32 | int64](span *ArraySpan, buf []T, valueSize int64, bufidx int) {
   256  	buf[0] = 0
   257  	buf[1] = T(valueSize)
   258  
   259  	b := (*reflect.SliceHeader)(unsafe.Pointer(&buf))
   260  	s := (*reflect.SliceHeader)(unsafe.Pointer(&span.Buffers[bufidx].Buf))
   261  	s.Data = b.Data
   262  	s.Len = 2 * int(unsafe.Sizeof(T(0)))
   263  	s.Cap = s.Len
   264  
   265  	span.Buffers[bufidx].Owner = nil
   266  	span.Buffers[bufidx].SelfAlloc = false
   267  }
   268  
   269  // FillFromScalar populates this ArraySpan as if it were a 1 length array
   270  // with the single value equal to the passed in Scalar.
   271  func (a *ArraySpan) FillFromScalar(val scalar.Scalar) {
   272  	var (
   273  		trueBit  byte = 0x01
   274  		falseBit byte = 0x00
   275  	)
   276  
   277  	a.Type = val.DataType()
   278  	a.Len = 1
   279  	typeID := a.Type.ID()
   280  	if val.IsValid() {
   281  		a.Nulls = 0
   282  	} else {
   283  		a.Nulls = 1
   284  	}
   285  
   286  	if !arrow.IsUnion(typeID) && typeID != arrow.NULL {
   287  		if val.IsValid() {
   288  			a.Buffers[0].Buf = []byte{trueBit}
   289  		} else {
   290  			a.Buffers[0].Buf = []byte{falseBit}
   291  		}
   292  		a.Buffers[0].Owner = nil
   293  		a.Buffers[0].SelfAlloc = false
   294  	}
   295  
   296  	switch {
   297  	case typeID == arrow.BOOL:
   298  		if val.(*scalar.Boolean).Value {
   299  			a.Buffers[1].Buf = []byte{trueBit}
   300  		} else {
   301  			a.Buffers[1].Buf = []byte{falseBit}
   302  		}
   303  		a.Buffers[1].Owner = nil
   304  		a.Buffers[1].SelfAlloc = false
   305  	case arrow.IsPrimitive(typeID) || arrow.IsDecimal(typeID):
   306  		sc := val.(scalar.PrimitiveScalar)
   307  		a.Buffers[1].Buf = sc.Data()
   308  		a.Buffers[1].Owner = nil
   309  		a.Buffers[1].SelfAlloc = false
   310  	case typeID == arrow.DICTIONARY:
   311  		sc := val.(scalar.PrimitiveScalar)
   312  		a.Buffers[1].Buf = sc.Data()
   313  		a.Buffers[1].Owner = nil
   314  		a.Buffers[1].SelfAlloc = false
   315  		a.resizeChildren(1)
   316  		a.Children[0].SetMembers(val.(*scalar.Dictionary).Value.Dict.Data())
   317  	case arrow.IsBaseBinary(typeID):
   318  		sc := val.(scalar.BinaryScalar)
   319  		a.Buffers[1].Buf = arrow.Uint64Traits.CastToBytes(a.Scratch[:])
   320  		a.Buffers[1].Owner = nil
   321  		a.Buffers[1].SelfAlloc = false
   322  
   323  		var dataBuffer []byte
   324  		if sc.IsValid() {
   325  			dataBuffer = sc.Data()
   326  			a.Buffers[2].Owner = sc.Buffer()
   327  			a.Buffers[2].SelfAlloc = false
   328  		}
   329  		if arrow.IsBinaryLike(typeID) {
   330  			setOffsetsForScalar(a,
   331  				unsafe.Slice((*int32)(unsafe.Pointer(&a.Scratch[0])), 2),
   332  				int64(len(dataBuffer)), 1)
   333  		} else {
   334  			// large_binary_like
   335  			setOffsetsForScalar(a,
   336  				unsafe.Slice((*int64)(unsafe.Pointer(&a.Scratch[0])), 2),
   337  				int64(len(dataBuffer)), 1)
   338  		}
   339  		a.Buffers[2].Buf = dataBuffer
   340  	case typeID == arrow.FIXED_SIZE_BINARY:
   341  		sc := val.(scalar.BinaryScalar)
   342  		if !sc.IsValid() {
   343  			a.Buffers[1].Buf = make([]byte, sc.DataType().(*arrow.FixedSizeBinaryType).ByteWidth)
   344  			a.Buffers[1].Owner = nil
   345  			a.Buffers[1].SelfAlloc = false
   346  			break
   347  		}
   348  		a.Buffers[1].Buf = sc.Data()
   349  		a.Buffers[1].Owner = sc.Buffer()
   350  		a.Buffers[1].SelfAlloc = false
   351  	case arrow.IsListLike(typeID):
   352  		sc := val.(scalar.ListScalar)
   353  		valueLen := 0
   354  		a.resizeChildren(1)
   355  
   356  		if sc.GetList() != nil {
   357  			a.Children[0].SetMembers(sc.GetList().Data())
   358  			valueLen = sc.GetList().Len()
   359  		} else {
   360  			// even when the value is null, we must populate
   361  			// child data to yield a valid array. ugh
   362  			FillZeroLength(sc.DataType().(arrow.NestedType).Fields()[0].Type, &a.Children[0])
   363  		}
   364  
   365  		switch typeID {
   366  		case arrow.LIST, arrow.MAP:
   367  			setOffsetsForScalar(a,
   368  				unsafe.Slice((*int32)(unsafe.Pointer(&a.Scratch[0])), 2),
   369  				int64(valueLen), 1)
   370  		case arrow.LARGE_LIST:
   371  			setOffsetsForScalar(a,
   372  				unsafe.Slice((*int64)(unsafe.Pointer(&a.Scratch[0])), 2),
   373  				int64(valueLen), 1)
   374  		default:
   375  			// fixed size list has no second buffer
   376  			a.Buffers[1].Buf, a.Buffers[1].Owner = nil, nil
   377  			a.Buffers[1].SelfAlloc = false
   378  		}
   379  	case typeID == arrow.STRUCT:
   380  		sc := val.(*scalar.Struct)
   381  		a.Buffers[1].Buf = nil
   382  		a.Buffers[1].Owner = nil
   383  		a.Buffers[1].SelfAlloc = false
   384  		a.resizeChildren(len(sc.Value))
   385  		for i, v := range sc.Value {
   386  			a.Children[i].FillFromScalar(v)
   387  		}
   388  	case arrow.IsUnion(typeID):
   389  		// first buffer is kept null since unions have no validity vector
   390  		a.Buffers[0].Buf, a.Buffers[0].Owner = nil, nil
   391  		a.Buffers[0].SelfAlloc = false
   392  
   393  		a.Buffers[1].Buf = arrow.Uint64Traits.CastToBytes(a.Scratch[:])[:1]
   394  		a.Buffers[1].Owner = nil
   395  		a.Buffers[1].SelfAlloc = false
   396  		codes := unsafe.Slice((*arrow.UnionTypeCode)(unsafe.Pointer(&a.Buffers[1].Buf[0])), 1)
   397  
   398  		a.resizeChildren(len(a.Type.(arrow.UnionType).Fields()))
   399  		switch sc := val.(type) {
   400  		case *scalar.DenseUnion:
   401  			codes[0] = sc.TypeCode
   402  			// has offset, start 4 bytes in so it's aligned to the 32-bit boundaries
   403  			off := unsafe.Slice((*int32)(unsafe.Add(unsafe.Pointer(&a.Scratch[0]), arrow.Int32SizeBytes)), 2)
   404  			setOffsetsForScalar(a, off, 1, 2)
   405  			// we can't "see" the other arrays in the union, but we put the "active"
   406  			// union array in the right place and fill zero-length arrays for
   407  			// the others.
   408  			childIDS := a.Type.(arrow.UnionType).ChildIDs()
   409  			for i, f := range a.Type.(arrow.UnionType).Fields() {
   410  				if i == childIDS[sc.TypeCode] {
   411  					a.Children[i].FillFromScalar(sc.Value)
   412  				} else {
   413  					FillZeroLength(f.Type, &a.Children[i])
   414  				}
   415  			}
   416  		case *scalar.SparseUnion:
   417  			codes[0] = sc.TypeCode
   418  			// sparse union scalars have a full complement of child values
   419  			// even though only one of them is relevant, so we just fill them
   420  			// in here
   421  			for i, v := range sc.Value {
   422  				a.Children[i].FillFromScalar(v)
   423  			}
   424  		}
   425  	case typeID == arrow.EXTENSION:
   426  		// pass through storage
   427  		sc := val.(*scalar.Extension)
   428  		a.FillFromScalar(sc.Value)
   429  		// restore the extension type
   430  		a.Type = val.DataType()
   431  	case typeID == arrow.NULL:
   432  		for i := range a.Buffers {
   433  			a.Buffers[i].Buf = nil
   434  			a.Buffers[i].Owner = nil
   435  			a.Buffers[i].SelfAlloc = false
   436  		}
   437  	}
   438  }
   439  
   440  func (a *ArraySpan) SetDictionary(span *ArraySpan) {
   441  	a.resizeChildren(1)
   442  	a.Children[0].Release()
   443  	a.Children[0] = *span
   444  }
   445  
   446  // TakeOwnership is like SetMembers only this takes ownership of
   447  // the buffers by calling Retain on them so that the passed in
   448  // ArrayData can be released without negatively affecting this
   449  // ArraySpan
   450  func (a *ArraySpan) TakeOwnership(data arrow.ArrayData) {
   451  	a.Type = data.DataType()
   452  	a.Len = int64(data.Len())
   453  	if a.Type.ID() == arrow.NULL {
   454  		a.Nulls = a.Len
   455  	} else {
   456  		a.Nulls = int64(data.NullN())
   457  	}
   458  	a.Offset = int64(data.Offset())
   459  
   460  	for i, b := range data.Buffers() {
   461  		if b != nil {
   462  			a.Buffers[i].WrapBuffer(b)
   463  			b.Retain()
   464  		} else {
   465  			a.Buffers[i].Buf = nil
   466  			a.Buffers[i].Owner = nil
   467  			a.Buffers[i].SelfAlloc = false
   468  		}
   469  	}
   470  
   471  	typeID := a.Type.ID()
   472  	if a.Buffers[0].Buf == nil {
   473  		switch typeID {
   474  		case arrow.NULL, arrow.SPARSE_UNION, arrow.DENSE_UNION:
   475  		default:
   476  			// should already be zero, but we make sure
   477  			a.Nulls = 0
   478  		}
   479  	}
   480  
   481  	for i := len(data.Buffers()); i < 3; i++ {
   482  		a.Buffers[i].Buf = nil
   483  		a.Buffers[i].Owner = nil
   484  		a.Buffers[i].SelfAlloc = false
   485  	}
   486  
   487  	if typeID == arrow.DICTIONARY {
   488  		a.resizeChildren(1)
   489  		dict := data.Dictionary()
   490  		if dict != (*array.Data)(nil) {
   491  			a.Children[0].TakeOwnership(dict)
   492  		}
   493  	} else {
   494  		a.resizeChildren(len(data.Children()))
   495  		for i, c := range data.Children() {
   496  			a.Children[i].TakeOwnership(c)
   497  		}
   498  	}
   499  }
   500  
   501  // SetMembers populates this ArraySpan from the given ArrayData object.
   502  // As this is a non-owning reference, the ArrayData object must not
   503  // be fully released while this ArraySpan is in use, otherwise any buffers
   504  // referenced will be released too
   505  func (a *ArraySpan) SetMembers(data arrow.ArrayData) {
   506  	a.Type = data.DataType()
   507  	a.Len = int64(data.Len())
   508  	if a.Type.ID() == arrow.NULL {
   509  		a.Nulls = a.Len
   510  	} else {
   511  		a.Nulls = int64(data.NullN())
   512  	}
   513  	a.Offset = int64(data.Offset())
   514  
   515  	for i, b := range data.Buffers() {
   516  		if b != nil {
   517  			a.Buffers[i].SetBuffer(b)
   518  		} else {
   519  			a.Buffers[i].Buf = nil
   520  			a.Buffers[i].Owner = nil
   521  			a.Buffers[i].SelfAlloc = false
   522  		}
   523  	}
   524  
   525  	typeID := a.Type.ID()
   526  	if a.Buffers[0].Buf == nil {
   527  		switch typeID {
   528  		case arrow.NULL, arrow.SPARSE_UNION, arrow.DENSE_UNION:
   529  		default:
   530  			// should already be zero, but we make sure
   531  			a.Nulls = 0
   532  		}
   533  	}
   534  
   535  	for i := len(data.Buffers()); i < 3; i++ {
   536  		a.Buffers[i].Buf = nil
   537  		a.Buffers[i].Owner = nil
   538  		a.Buffers[i].SelfAlloc = false
   539  	}
   540  
   541  	if typeID == arrow.DICTIONARY {
   542  		a.resizeChildren(1)
   543  		dict := data.Dictionary()
   544  		if dict != (*array.Data)(nil) {
   545  			a.Children[0].SetMembers(dict)
   546  		}
   547  	} else {
   548  		if cap(a.Children) >= len(data.Children()) {
   549  			a.Children = a.Children[:len(data.Children())]
   550  		} else {
   551  			a.Children = make([]ArraySpan, len(data.Children()))
   552  		}
   553  		for i, c := range data.Children() {
   554  			a.Children[i].SetMembers(c)
   555  		}
   556  	}
   557  }
   558  
   559  // ExecValue represents a single input to an execution which could
   560  // be either an Array (ArraySpan) or a Scalar value
   561  type ExecValue struct {
   562  	Array  ArraySpan
   563  	Scalar scalar.Scalar
   564  }
   565  
   566  func (e *ExecValue) IsArray() bool  { return e.Scalar == nil }
   567  func (e *ExecValue) IsScalar() bool { return !e.IsArray() }
   568  
   569  func (e *ExecValue) Type() arrow.DataType {
   570  	if e.IsArray() {
   571  		return e.Array.Type
   572  	}
   573  	return e.Scalar.DataType()
   574  }
   575  
   576  // ExecResult is the result of a kernel execution and should be populated
   577  // by the execution functions and/or a kernel. For now we're just going to
   578  // alias an ArraySpan.
   579  type ExecResult = ArraySpan
   580  
   581  // ExecSpan represents a slice of inputs and is used to provide slices
   582  // of input values to iterate over.
   583  //
   584  // Len is the length of the span (all elements in Values should either
   585  // be scalar or an array with a length + offset of at least Len).
   586  type ExecSpan struct {
   587  	Len    int64
   588  	Values []ExecValue
   589  }
   590  
   591  func getNumBuffers(dt arrow.DataType) int {
   592  	switch dt.ID() {
   593  	case arrow.RUN_END_ENCODED:
   594  		return 0
   595  	case arrow.NULL, arrow.STRUCT, arrow.FIXED_SIZE_LIST:
   596  		return 1
   597  	case arrow.BINARY, arrow.LARGE_BINARY, arrow.STRING, arrow.LARGE_STRING, arrow.DENSE_UNION:
   598  		return 3
   599  	case arrow.EXTENSION:
   600  		return getNumBuffers(dt.(arrow.ExtensionType).StorageType())
   601  	default:
   602  		return 2
   603  	}
   604  }
   605  
   606  // FillZeroLength fills an ArraySpan with the appropriate information for
   607  // a Zero Length Array of the provided type.
   608  func FillZeroLength(dt arrow.DataType, span *ArraySpan) {
   609  	span.Scratch[0], span.Scratch[1] = 0, 0
   610  	span.Type = dt
   611  	span.Len = 0
   612  	numBufs := getNumBuffers(dt)
   613  	for i := 0; i < numBufs; i++ {
   614  		span.Buffers[i].Buf = arrow.Uint64Traits.CastToBytes(span.Scratch[:])[:0]
   615  		span.Buffers[i].Owner = nil
   616  	}
   617  
   618  	for i := numBufs; i < 3; i++ {
   619  		span.Buffers[i].Buf, span.Buffers[i].Owner = nil, nil
   620  	}
   621  
   622  	if dt.ID() == arrow.DICTIONARY {
   623  		span.resizeChildren(1)
   624  		FillZeroLength(dt.(*arrow.DictionaryType).ValueType, &span.Children[0])
   625  		return
   626  	}
   627  
   628  	nt, ok := dt.(arrow.NestedType)
   629  	if !ok {
   630  		if len(span.Children) > 0 {
   631  			span.Children = span.Children[:0]
   632  		}
   633  		return
   634  	}
   635  
   636  	span.resizeChildren(len(nt.Fields()))
   637  	for i, f := range nt.Fields() {
   638  		FillZeroLength(f.Type, &span.Children[i])
   639  	}
   640  }
   641  
   642  // PromoteExecSpanScalars promotes the values of the passed in ExecSpan
   643  // from scalars to Arrays of length 1 for each value.
   644  func PromoteExecSpanScalars(span ExecSpan) {
   645  	for i := range span.Values {
   646  		if span.Values[i].Scalar != nil {
   647  			span.Values[i].Array.FillFromScalar(span.Values[i].Scalar)
   648  			span.Values[i].Scalar = nil
   649  		}
   650  	}
   651  }