package parquet

import (
	
	
	
	
	
	
	
	
	

	

	
	
	
	
)

// ConvertError is an error type returned by calls to Convert when the conversion
// of parquet schemas is impossible or the input row for the conversion is
// malformed.
type ConvertError struct {
	Path []string
	From Node
	To   Node
}

// Error satisfies the error interface.
func ( *ConvertError) () string {
	 := .From.Type()
	 := .To.Type()

	 := fieldRepetitionTypeOf(.From)
	 := fieldRepetitionTypeOf(.To)

	return fmt.Sprintf("cannot convert parquet column %q from %s %s to %s %s",
		columnPath(.Path),
		,
		,
		,
		,
	)
}

// Conversion is an interface implemented by types that provide conversion of
// parquet rows from one schema to another.
//
// Conversion instances must be safe to use concurrently from multiple goroutines.
type Conversion interface {
	// Applies the conversion logic on the src row, returning the result
	// appended to dst.
	Convert(rows []Row) (int, error)
	// Converts the given column index in the target schema to the original
	// column index in the source schema of the conversion.
	Column(int) int
	// Returns the target schema of the conversion.
	Schema() *Schema
}

type conversion struct {
	columns []conversionColumn
	schema  *Schema
	buffers sync.Pool
	// This field is used to size the column buffers held in the sync.Pool since
	// they are intended to store the source rows being converted from.
	numberOfSourceColumns int
}

type conversionBuffer struct {
	columns [][]Value
}

type conversionColumn struct {
	sourceIndex   int
	convertValues conversionFunc
}

type conversionFunc func([]Value) error

func convertToSelf( []Value) error { return nil }

//go:noinline
func convertToType(,  Type) conversionFunc {
	return func( []Value) error {
		for ,  := range  {
			,  := .ConvertValue(, )
			if  != nil {
				return 
			}
			[].ptr = .ptr
			[].u64 = .u64
			[].kind = .kind
		}
		return nil
	}
}

//go:noinline
func convertToValue( Value) conversionFunc {
	return func( []Value) error {
		for  := range  {
			[] = 
		}
		return nil
	}
}

//go:noinline
func convertToZero( Kind) conversionFunc {
	return func( []Value) error {
		for  := range  {
			[].ptr = nil
			[].u64 = 0
			[].kind = ^int8()
		}
		return nil
	}
}

//go:noinline
func convertToLevels(,  []byte) conversionFunc {
	return func( []Value) error {
		for  := range  {
			 := [].repetitionLevel
			 := [].definitionLevel
			[].repetitionLevel = []
			[].definitionLevel = []
		}
		return nil
	}
}

//go:noinline
func multiConversionFunc( []conversionFunc) conversionFunc {
	switch len() {
	case 0:
		return convertToSelf
	case 1:
		return [0]
	default:
		return func( []Value) error {
			for ,  := range  {
				if  := ();  != nil {
					return 
				}
			}
			return nil
		}
	}
}

func ( *conversion) () *conversionBuffer {
	,  := .buffers.Get().(*conversionBuffer)
	if  == nil {
		 = &conversionBuffer{
			columns: make([][]Value, .numberOfSourceColumns),
		}
		 := make([]Value, .numberOfSourceColumns)
		for  := range .columns {
			.columns[] = [ :  : +1]
		}
	}
	return 
}

func ( *conversion) ( *conversionBuffer) {
	.buffers.Put()
}

// Convert here satisfies the Conversion interface, and does the actual work
// to convert between the source and target Rows.
func ( *conversion) ( []Row) (int, error) {
	 := .getBuffer()
	defer .putBuffer()

	for ,  := range  {
		for ,  := range .columns {
			.columns[] = [:0]
		}
		.Range(func( int,  []Value) bool {
			.columns[] = append(.columns[], ...)
			return true
		})
		 = [:0]

		for ,  := range .columns {
			 := len()
			if .sourceIndex < 0 {
				// When there is no source column, we put a single value as
				// placeholder in the column. This is a condition where the
				// target contained a column which did not exist at had not
				// other columns existing at that same level.
				 = append(, Value{})
			} else {
				// We must copy to the output row first and not mutate the
				// source columns because multiple target columns may map to
				// the same source column.
				 = append(, .columns[.sourceIndex]...)
			}
			 := [:]

			if  := .convertValues();  != nil {
				return , 
			}

			// Since the column index may have changed between the source and
			// taget columns we ensure that the right value is always written
			// to the output row.
			for  := range  {
				[].columnIndex = ^int16()
			}
		}

		[] = 
	}

	return len(), nil
}

func ( *conversion) ( int) int {
	return .columns[].sourceIndex
}

func ( *conversion) () *Schema {
	return .schema
}

type identity struct{ schema *Schema }

func ( identity) ( []Row) (int, error) { return len(), nil }
func ( identity) ( int) int                { return  }
func ( identity) () *Schema                 { return .schema }

// Convert constructs a conversion function from one parquet schema to another.
//
// The function supports converting between schemas where the source or target
// have extra columns; if there are more columns in the source, they will be
// stripped out of the rows. Extra columns in the target schema will be set to
// null or zero values.
//
// The returned function is intended to be used to append the converted source
// row to the destination buffer.
func (,  Node) ( Conversion,  error) {
	,  := .(*Schema)
	if  == nil {
		 = NewSchema("", )
	}

	if nodesAreEqual(, ) {
		return identity{}, nil
	}

	,  := columnMappingOf()
	,  := columnMappingOf()
	 := make([]conversionColumn, len())

	for ,  := range  {
		 := .lookup()
		 := .lookup()

		 := []conversionFunc{}
		if .node != nil {
			 := .node.Type()
			 := .node.Type()
			if !typesAreEqual(, ) {
				 = append(,
					convertToType(, ),
				)
			}

			 := make([]byte, len()+1)
			 := make([]byte, len()+1)
			 := byte(0)
			 := byte(0)
			 := byte(0)
			 := byte(0)
			 := 
			 := 

			for  := 0;  < len(); ++ {
				 = fieldByName(, [])
				 = fieldByName(, [])

				,  = applyFieldRepetitionType(
					fieldRepetitionTypeOf(),
					,
					,
				)
				,  = applyFieldRepetitionType(
					fieldRepetitionTypeOf(),
					,
					,
				)

				[] = 
				[] = 
			}

			 = [:+1]
			 = [:+1]

			if !isDirectLevelMapping() || !isDirectLevelMapping() {
				 = append(,
					convertToLevels(, ),
				)
			}

		} else {
			 := .node.Type()
			 := .Kind()
			 = .lookupClosest()
			if .node != nil {
				 = append(,
					convertToZero(),
				)
			} else {
				 = append(,
					convertToValue(ZeroValue()),
				)
			}
		}

		[] = conversionColumn{
			sourceIndex:   int(.columnIndex),
			convertValues: multiConversionFunc(),
		}
	}

	 := &conversion{
		columns:               ,
		schema:                ,
		numberOfSourceColumns: len(),
	}
	return , nil
}

func isDirectLevelMapping( []byte) bool {
	for ,  := range  {
		if  != byte() {
			return false
		}
	}
	return true
}

// ConvertRowGroup constructs a wrapper of the given row group which applies
// the given schema conversion to its rows.
func ( RowGroup,  Conversion) RowGroup {
	 := .Schema()
	 := .NumRows()
	 := .ColumnChunks()

	 := make([]ColumnChunk, numLeafColumnsOf())
	forEachLeafColumnOf(, func( leafColumn) {
		 := .columnIndex
		 := .Column(int(.columnIndex))
		if  < 0 {
			[] = &missingColumnChunk{
				typ:    .node.Type(),
				column: ,
				// TODO: we assume the number of values is the same as the
				// number of rows, which may not be accurate when the column is
				// part of a repeated group; neighbor columns may be repeated in
				// which case it would be impossible for this chunk not to be.
				numRows:   ,
				numValues: ,
				numNulls:  ,
			}
		} else {
			[] = []
		}
	})

	// Sorting columns must exist on the conversion schema in order to be
	// advertised on the converted row group otherwise the resulting rows
	// would not be in the right order.
	 := []SortingColumn{}
	for ,  := range .SortingColumns() {
		if !hasColumnPath(, .Path()) {
			break
		}
		 = append(, )
	}

	return &convertedRowGroup{
		// The pair of rowGroup+conv is retained to construct a converted row
		// reader by wrapping the underlying row reader of the row group because
		// it allows proper reconstruction of the repetition and definition
		// levels.
		//
		// TODO: can we figure out how to set the repetition and definition
		// levels when reading values from missing column pages? At first sight
		// it appears complex to do, however:
		//
		// * It is possible that having these levels when reading values of
		//   missing column pages is not necessary in some scenarios (e.g. when
		//   merging row groups).
		//
		// * We may be able to assume the repetition and definition levels at
		//   the call site (e.g. in the functions reading rows from columns).
		//
		// Columns of the source row group which do not exist in the target are
		// masked to prevent loading unneeded pages when reading rows from the
		// converted row group.
		rowGroup: maskMissingRowGroupColumns(, len(), ),
		columns:  ,
		sorting:  ,
		conv:     ,
	}
}

func maskMissingRowGroupColumns( RowGroup,  int,  Conversion) RowGroup {
	 := .ColumnChunks()
	 := make([]ColumnChunk, len())
	 := make([]missingColumnChunk, len())
	 := .NumRows()

	for  := range  {
		[] = missingColumnChunk{
			typ:       [].Type(),
			column:    int16(),
			numRows:   ,
			numValues: ,
			numNulls:  ,
		}
	}

	for  := range  {
		[] = &[]
	}

	for  := 0;  < ; ++ {
		 := .Column()
		if  >= 0 &&  < len() {
			[] = []
		}
	}

	return &rowGroup{
		schema:  .Schema(),
		numRows: ,
		columns: ,
	}
}

type missingColumnChunk struct {
	typ       Type
	column    int16
	numRows   int64
	numValues int64
	numNulls  int64
}

func ( *missingColumnChunk) () Type                        { return .typ }
func ( *missingColumnChunk) () int                       { return int(.column) }
func ( *missingColumnChunk) () Pages                      { return onePage(missingPage{}) }
func ( *missingColumnChunk) () (ColumnIndex, error) { return missingColumnIndex{}, nil }
func ( *missingColumnChunk) () (OffsetIndex, error) { return missingOffsetIndex{}, nil }
func ( *missingColumnChunk) () BloomFilter          { return missingBloomFilter{} }
func ( *missingColumnChunk) () int64                  { return .numValues }

type missingColumnIndex struct{ *missingColumnChunk }

func ( missingColumnIndex) () int       { return 1 }
func ( missingColumnIndex) (int) int64 { return .numNulls }
func ( missingColumnIndex) (int) bool   { return true }
func ( missingColumnIndex) (int) Value  { return Value{} }
func ( missingColumnIndex) (int) Value  { return Value{} }
func ( missingColumnIndex) () bool   { return true }
func ( missingColumnIndex) () bool  { return false }

type missingOffsetIndex struct{}

func (missingOffsetIndex) () int                { return 1 }
func (missingOffsetIndex) (int) int64             { return 0 }
func (missingOffsetIndex) (int) int64 { return 0 }
func (missingOffsetIndex) (int) int64      { return 0 }

type missingBloomFilter struct{}

func (missingBloomFilter) ([]byte, int64) (int, error) { return 0, io.EOF }
func (missingBloomFilter) () int64                       { return 0 }
func (missingBloomFilter) (Value) (bool, error)         { return false, nil }

type missingPage struct{ *missingColumnChunk }

func ( missingPage) () int                       { return int(.column) }
func ( missingPage) () Dictionary            { return nil }
func ( missingPage) () int64                    { return .numRows }
func ( missingPage) () int64                  { return .numValues }
func ( missingPage) () int64                   { return .numNulls }
func ( missingPage) () (,  Value,  bool) { return }
func ( missingPage) (,  int64) Page {
	return missingPage{
		&missingColumnChunk{
			typ:       .typ,
			column:    .column,
			numRows:    - ,
			numValues:  - ,
			numNulls:   - ,
		},
	}
}
func ( missingPage) () int64              { return 0 }
func ( missingPage) () []byte { return nil }
func ( missingPage) () []byte { return nil }
func ( missingPage) () encoding.Values    { return .typ.NewValues(nil, nil) }
func ( missingPage) () ValueReader      { return &missingPageValues{page: } }

type missingPageValues struct {
	page missingPage
	read int64
}

func ( *missingPageValues) ( []Value) (int, error) {
	 := .page.numValues - .read
	if int64(len()) >  {
		 = [:]
	}
	for  := range  {
		// TODO: how do we set the repetition and definition levels here?
		[] = Value{columnIndex: ^.page.column}
	}
	if .read += int64(len()); .read == .page.numValues {
		return len(), io.EOF
	}
	return len(), nil
}

func ( *missingPageValues) () error {
	.read = .page.numValues
	return nil
}

type convertedRowGroup struct {
	rowGroup RowGroup
	columns  []ColumnChunk
	sorting  []SortingColumn
	conv     Conversion
}

func ( *convertedRowGroup) () int64                  { return .rowGroup.NumRows() }
func ( *convertedRowGroup) () []ColumnChunk     { return .columns }
func ( *convertedRowGroup) () *Schema                 { return .conv.Schema() }
func ( *convertedRowGroup) () []SortingColumn { return .sorting }
func ( *convertedRowGroup) () Rows {
	 := .rowGroup.Rows()
	return &convertedRows{
		Closer: ,
		rows:   ,
		conv:   .conv,
	}
}

// ConvertRowReader constructs a wrapper of the given row reader which applies
// the given schema conversion to the rows.
func ( RowReader,  Conversion) RowReaderWithSchema {
	return &convertedRows{rows: &forwardRowSeeker{rows: }, conv: }
}

type convertedRows struct {
	io.Closer
	rows RowReadSeeker
	conv Conversion
}

func ( *convertedRows) ( []Row) (int, error) {
	,  := .rows.ReadRows()
	if  > 0 {
		var  error
		,  = .conv.Convert([:])
		if  != nil {
			 = 
		}
	}
	return , 
}

func ( *convertedRows) () *Schema {
	return .conv.Schema()
}

func ( *convertedRows) ( int64) error {
	return .rows.SeekToRow()
}

var (
	trueBytes  = []byte(`true`)
	falseBytes = []byte(`false`)
	unixEpoch  = time.Date(1970, time.January, 1, 0, 0, 0, 0, time.UTC)
)

func convertBooleanToInt32( Value) (Value, error) {
	return .convertToInt32(int32(.byte())), nil
}

func convertBooleanToInt64( Value) (Value, error) {
	return .convertToInt64(int64(.byte())), nil
}

func convertBooleanToInt96( Value) (Value, error) {
	return .convertToInt96(deprecated.Int96{0: uint32(.byte())}), nil
}

func convertBooleanToFloat( Value) (Value, error) {
	return .convertToFloat(float32(.byte())), nil
}

func convertBooleanToDouble( Value) (Value, error) {
	return .convertToDouble(float64(.byte())), nil
}

func convertBooleanToByteArray( Value) (Value, error) {
	return .convertToByteArray([]byte{.byte()}), nil
}

func convertBooleanToFixedLenByteArray( Value,  int) (Value, error) {
	 := []byte{.byte()}
	 := make([]byte, )
	copy(, )
	return .convertToFixedLenByteArray(), nil
}

func convertBooleanToString( Value) (Value, error) {
	 := ([]byte)(nil)
	if .boolean() {
		 = trueBytes
	} else {
		 = falseBytes
	}
	return .convertToByteArray(), nil
}

func convertInt32ToBoolean( Value) (Value, error) {
	return .convertToBoolean(.int32() != 0), nil
}

func convertInt32ToInt64( Value) (Value, error) {
	return .convertToInt64(int64(.int32())), nil
}

func convertInt32ToInt96( Value) (Value, error) {
	return .convertToInt96(deprecated.Int32ToInt96(.int32())), nil
}

func convertInt32ToFloat( Value) (Value, error) {
	return .convertToFloat(float32(.int32())), nil
}

func convertInt32ToDouble( Value) (Value, error) {
	return .convertToDouble(float64(.int32())), nil
}

func convertInt32ToByteArray( Value) (Value, error) {
	 := make([]byte, 4)
	binary.LittleEndian.PutUint32(, .uint32())
	return .convertToByteArray(), nil
}

func convertInt32ToFixedLenByteArray( Value,  int) (Value, error) {
	 := make([]byte, 4)
	 := make([]byte, )
	binary.LittleEndian.PutUint32(, .uint32())
	copy(, )
	return .convertToFixedLenByteArray(), nil
}

func convertInt32ToString( Value) (Value, error) {
	return .convertToByteArray(strconv.AppendInt(nil, int64(.int32()), 10)), nil
}

func convertInt64ToBoolean( Value) (Value, error) {
	return .convertToBoolean(.int64() != 0), nil
}

func convertInt64ToInt32( Value) (Value, error) {
	return .convertToInt32(int32(.int64())), nil
}

func convertInt64ToInt96( Value) (Value, error) {
	return .convertToInt96(deprecated.Int64ToInt96(.int64())), nil
}

func convertInt64ToFloat( Value) (Value, error) {
	return .convertToFloat(float32(.int64())), nil
}

func convertInt64ToDouble( Value) (Value, error) {
	return .convertToDouble(float64(.int64())), nil
}

func convertInt64ToByteArray( Value) (Value, error) {
	 := make([]byte, 8)
	binary.LittleEndian.PutUint64(, .uint64())
	return .convertToByteArray(), nil
}

func convertInt64ToFixedLenByteArray( Value,  int) (Value, error) {
	 := make([]byte, 8)
	 := make([]byte, )
	binary.LittleEndian.PutUint64(, .uint64())
	copy(, )
	return .convertToFixedLenByteArray(), nil
}

func convertInt64ToString( Value) (Value, error) {
	return .convertToByteArray(strconv.AppendInt(nil, .int64(), 10)), nil
}

func convertInt96ToBoolean( Value) (Value, error) {
	return .convertToBoolean(!.int96().IsZero()), nil
}

func convertInt96ToInt32( Value) (Value, error) {
	return .convertToInt32(.int96().Int32()), nil
}

func convertInt96ToInt64( Value) (Value, error) {
	return .convertToInt64(.int96().Int64()), nil
}

func convertInt96ToFloat( Value) (Value, error) {
	return , invalidConversion(, "INT96", "FLOAT")
}

func convertInt96ToDouble( Value) (Value, error) {
	return , invalidConversion(, "INT96", "DOUBLE")
}

func convertInt96ToByteArray( Value) (Value, error) {
	return .convertToByteArray(.byteArray()), nil
}

func convertInt96ToFixedLenByteArray( Value,  int) (Value, error) {
	 := .byteArray()
	if len() <  {
		 := make([]byte, )
		copy(, )
		 = 
	} else {
		 = [:]
	}
	return .convertToFixedLenByteArray(), nil
}

func convertInt96ToString( Value) (Value, error) {
	return .convertToByteArray([]byte(.String())), nil
}

func convertFloatToBoolean( Value) (Value, error) {
	return .convertToBoolean(.float() != 0), nil
}

func convertFloatToInt32( Value) (Value, error) {
	return .convertToInt32(int32(.float())), nil
}

func convertFloatToInt64( Value) (Value, error) {
	return .convertToInt64(int64(.float())), nil
}

func convertFloatToInt96( Value) (Value, error) {
	return , invalidConversion(, "FLOAT", "INT96")
}

func convertFloatToDouble( Value) (Value, error) {
	return .convertToDouble(float64(.float())), nil
}

func convertFloatToByteArray( Value) (Value, error) {
	 := make([]byte, 4)
	binary.LittleEndian.PutUint32(, .uint32())
	return .convertToByteArray(), nil
}

func convertFloatToFixedLenByteArray( Value,  int) (Value, error) {
	 := make([]byte, 4)
	 := make([]byte, )
	binary.LittleEndian.PutUint32(, .uint32())
	copy(, )
	return .convertToFixedLenByteArray(), nil
}

func convertFloatToString( Value) (Value, error) {
	return .convertToByteArray(strconv.AppendFloat(nil, float64(.float()), 'g', -1, 32)), nil
}

func convertDoubleToBoolean( Value) (Value, error) {
	return .convertToBoolean(.double() != 0), nil
}

func convertDoubleToInt32( Value) (Value, error) {
	return .convertToInt32(int32(.double())), nil
}

func convertDoubleToInt64( Value) (Value, error) {
	return .convertToInt64(int64(.double())), nil
}

func convertDoubleToInt96( Value) (Value, error) {
	return , invalidConversion(, "FLOAT", "INT96")
}

func convertDoubleToFloat( Value) (Value, error) {
	return .convertToFloat(float32(.double())), nil
}

func convertDoubleToByteArray( Value) (Value, error) {
	 := make([]byte, 8)
	binary.LittleEndian.PutUint64(, .uint64())
	return .convertToByteArray(), nil
}

func convertDoubleToFixedLenByteArray( Value,  int) (Value, error) {
	 := make([]byte, 8)
	 := make([]byte, )
	binary.LittleEndian.PutUint64(, .uint64())
	copy(, )
	return .convertToFixedLenByteArray(), nil
}

func convertDoubleToString( Value) (Value, error) {
	return .convertToByteArray(strconv.AppendFloat(nil, .double(), 'g', -1, 64)), nil
}

func convertByteArrayToBoolean( Value) (Value, error) {
	return .convertToBoolean(!isZero(.byteArray())), nil
}

func convertByteArrayToInt32( Value) (Value, error) {
	 := make([]byte, 4)
	copy(, .byteArray())
	return .convertToInt32(int32(binary.LittleEndian.Uint32())), nil
}

func convertByteArrayToInt64( Value) (Value, error) {
	 := make([]byte, 8)
	copy(, .byteArray())
	return .convertToInt64(int64(binary.LittleEndian.Uint64())), nil
}

func convertByteArrayToInt96( Value) (Value, error) {
	 := make([]byte, 12)
	copy(, .byteArray())
	return .convertToInt96(deprecated.Int96{
		0: binary.LittleEndian.Uint32([0:4]),
		1: binary.LittleEndian.Uint32([4:8]),
		2: binary.LittleEndian.Uint32([8:12]),
	}), nil
}

func convertByteArrayToFloat( Value) (Value, error) {
	 := make([]byte, 4)
	copy(, .byteArray())
	return .convertToFloat(math.Float32frombits(binary.LittleEndian.Uint32())), nil
}

func convertByteArrayToDouble( Value) (Value, error) {
	 := make([]byte, 8)
	copy(, .byteArray())
	return .convertToDouble(math.Float64frombits(binary.LittleEndian.Uint64())), nil
}

func convertByteArrayToFixedLenByteArray( Value,  int) (Value, error) {
	 := .byteArray()
	if len() <  {
		 := make([]byte, )
		copy(, )
		 = 
	} else {
		 = [:]
	}
	return .convertToFixedLenByteArray(), nil
}

func convertFixedLenByteArrayToString( Value) (Value, error) {
	 := .byteArray()
	 := make([]byte, hex.EncodedLen(len()))
	hex.Encode(, )
	return .convertToByteArray(), nil
}

func convertStringToBoolean( Value) (Value, error) {
	,  := strconv.ParseBool(.string())
	if  != nil {
		return , conversionError(, "STRING", "BOOLEAN", )
	}
	return .convertToBoolean(), nil
}

func convertStringToInt32( Value) (Value, error) {
	,  := strconv.ParseInt(.string(), 10, 32)
	if  != nil {
		return , conversionError(, "STRING", "INT32", )
	}
	return .convertToInt32(int32()), nil
}

func convertStringToInt64( Value) (Value, error) {
	,  := strconv.ParseInt(.string(), 10, 64)
	if  != nil {
		return , conversionError(, "STRING", "INT64", )
	}
	return .convertToInt64(), nil
}

func convertStringToInt96( Value) (Value, error) {
	,  := new(big.Int).SetString(.string(), 10)
	if ! {
		return , conversionError(, "STRING", "INT96", strconv.ErrSyntax)
	}
	 := .Bytes()
	 := make([]byte, 12)
	copy(, )
	if cpu.IsBigEndian {
		 := len()
		for  := 0;  < ;  =  + 4 {
			for ,  := ( + 0), ( + 3);  < ; ,  = +1, -1 {
				[], [] = [], []
			}
		}
	}
	 := unsafecast.Slice[deprecated.Int96]()
	return .convertToInt96([0]), nil
}

func convertStringToFloat( Value) (Value, error) {
	,  := strconv.ParseFloat(.string(), 32)
	if  != nil {
		return , conversionError(, "STRING", "FLOAT", )
	}
	return .convertToFloat(float32()), nil
}

func convertStringToDouble( Value) (Value, error) {
	,  := strconv.ParseFloat(.string(), 64)
	if  != nil {
		return , conversionError(, "STRING", "DOUBLE", )
	}
	return .convertToDouble(), nil
}

func convertStringToFixedLenByteArray( Value,  int) (Value, error) {
	 := .byteArray()
	 := make([]byte, )
	,  := hex.Decode(, )
	if  != nil {
		return , conversionError(, "STRING", "BYTE_ARRAY", )
	}
	return .convertToFixedLenByteArray(), nil
}

func convertStringToDate( Value,  *time.Location) (Value, error) {
	,  := time.ParseInLocation("2006-01-02", .string(), )
	if  != nil {
		return , conversionError(, "STRING", "DATE", )
	}
	 := daysSinceUnixEpoch()
	return .convertToInt32(int32()), nil
}

func convertStringToTimeMillis( Value,  *time.Location) (Value, error) {
	,  := time.ParseInLocation("15:04:05.999", .string(), )
	if  != nil {
		return , conversionError(, "STRING", "TIME", )
	}
	 := nearestMidnightLessThan()
	 := .Sub().Milliseconds()
	return .convertToInt32(int32()), nil
}

func convertStringToTimeMicros( Value,  *time.Location) (Value, error) {
	,  := time.ParseInLocation("15:04:05.999999", .string(), )
	if  != nil {
		return , conversionError(, "STRING", "TIME", )
	}
	 := nearestMidnightLessThan()
	 := .Sub().Microseconds()
	return .convertToInt64(), nil
}

func convertDateToTimestamp( Value,  format.TimeUnit,  *time.Location) (Value, error) {
	 := unixEpoch.AddDate(0, 0, int(.int32()))
	 := timeUnitDuration()
	return .convertToInt64(int64(.In().Sub(unixEpoch) / )), nil
}

func convertDateToString( Value) (Value, error) {
	 := unixEpoch.AddDate(0, 0, int(.int32()))
	 := .AppendFormat(make([]byte, 0, 10), "2006-01-02")
	return .convertToByteArray(), nil
}

func convertTimeMillisToString( Value,  *time.Location) (Value, error) {
	 := time.UnixMilli(int64(.int32())).In()
	 := .AppendFormat(make([]byte, 0, 12), "15:04:05.999")
	return .convertToByteArray(), nil
}

func convertTimeMicrosToString( Value,  *time.Location) (Value, error) {
	 := time.UnixMicro(.int64()).In()
	 := .AppendFormat(make([]byte, 0, 15), "15:04:05.999999")
	return .convertToByteArray(), nil
}

func convertTimestampToDate( Value,  format.TimeUnit,  *time.Location) (Value, error) {
	 := timestamp(, , )
	 := daysSinceUnixEpoch()
	return .convertToInt32(int32()), nil
}

func convertTimestampToTimeMillis( Value,  format.TimeUnit, ,  *time.Location) (Value, error) {
	 := timestamp(, , )
	 := nearestMidnightLessThan()
	 := .In().Sub().Milliseconds()
	return .convertToInt32(int32()), nil
}

func convertTimestampToTimeMicros( Value,  format.TimeUnit, ,  *time.Location) (Value, error) {
	 := timestamp(, , )
	 := nearestMidnightLessThan()
	 := .In().Sub().Microseconds()
	return .convertToInt64(int64()), nil
}

func convertTimestampToTimestamp( Value, ,  format.TimeUnit) (Value, error) {
	 := timeUnitDuration().Nanoseconds()
	 := timeUnitDuration().Nanoseconds()
	 := (.int64() * ) / 
	return .convertToInt64(), nil
}

const nanosecondsPerDay = 24 * 60 * 60 * 1e9

func daysSinceUnixEpoch( time.Time) int {
	return int(.Sub(unixEpoch).Hours()) / 24
}

func nearestMidnightLessThan( time.Time) time.Time {
	, ,  := .Date()
	return time.Date(, , , 0, 0, 0, 0, .Location())
}

func timestamp( Value,  format.TimeUnit,  *time.Location) time.Time {
	return unixEpoch.In().Add(time.Duration(.int64()) * timeUnitDuration())
}

func timeUnitDuration( format.TimeUnit) time.Duration {
	switch {
	case .Millis != nil:
		return time.Millisecond
	case .Micros != nil:
		return time.Microsecond
	default:
		return time.Nanosecond
	}
}

func invalidConversion( Value, ,  string) error {
	return fmt.Errorf("%s to %s: %s: %w", , , , ErrInvalidConversion)
}

func conversionError( Value, ,  string,  error) error {
	return fmt.Errorf("%s to %s: %q: %s: %w", , , .string(), , ErrInvalidConversion)
}