github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/colexec/execgen/cmd/execgen/vec_to_datum_gen.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 main
    12  
    13  import (
    14  	"fmt"
    15  	"io"
    16  	"strings"
    17  	"text/template"
    18  
    19  	"github.com/cockroachdb/cockroachdb-parser/pkg/col/typeconv"
    20  	"github.com/cockroachdb/cockroachdb-parser/pkg/sql/types"
    21  )
    22  
    23  type vecToDatumTmplInfo struct {
    24  	// TypeFamily contains the type family this struct is handling, with
    25  	// "types." prefix.
    26  	TypeFamily string
    27  	// Widths contains all of the type widths that this struct is handling.
    28  	// Note that the entry with 'anyWidth' width must be last in the slice.
    29  	Widths []vecToDatumWidthTmplInfo
    30  }
    31  
    32  type vecToDatumWidthTmplInfo struct {
    33  	CanonicalTypeFamily types.Family
    34  	Width               int32
    35  	VecMethod           string
    36  	// ConversionTmpl is a "format string" for the conversion template. It has
    37  	// the same "signature" as AssignConverted, meaning that it should use
    38  	//   %[1]s for targetElem
    39  	//   %[2]s for sourceElem
    40  	//   %[3]s for datumAlloc.
    41  	ConversionTmpl string
    42  }
    43  
    44  // AssignConverted returns a string that performs a conversion of the element
    45  // sourceElem and assigns the result to the newly declared targetElem.
    46  // datumAlloc is the name of *tree.DatumAlloc struct that can be used to
    47  // allocate new datums.
    48  func (i vecToDatumWidthTmplInfo) AssignConverted(targetElem, sourceElem, datumAlloc string) string {
    49  	return fmt.Sprintf(i.ConversionTmpl, targetElem, sourceElem, datumAlloc)
    50  }
    51  
    52  // Sliceable returns whether the vector of i.CanonicalTypeFamily can be sliced
    53  // (i.e. whether it is a Golang's slice).
    54  func (i vecToDatumWidthTmplInfo) Sliceable() bool {
    55  	return sliceable(i.CanonicalTypeFamily)
    56  }
    57  
    58  // Remove unused warnings.
    59  var _ = vecToDatumWidthTmplInfo{}.AssignConverted
    60  var _ = vecToDatumWidthTmplInfo{}.Sliceable
    61  
    62  // vecToDatumConversionTmpls maps the type families to the corresponding
    63  // "format" strings (see comment above for details).
    64  // Note that the strings are formatted this way so that generated code doesn't
    65  // have empty lines.
    66  var vecToDatumConversionTmpls = map[types.Family]string{
    67  	types.BoolFamily: `%[1]s := tree.MakeDBool(tree.DBool(%[2]s))`,
    68  	// Note that currently, regardless of the integer's width, we always return
    69  	// INT8, so there is a single conversion template for IntFamily.
    70  	types.IntFamily:     `%[1]s := %[3]s.NewDInt(tree.DInt(%[2]s))`,
    71  	types.FloatFamily:   `%[1]s := %[3]s.NewDFloat(tree.DFloat(%[2]s))`,
    72  	types.DecimalFamily: `%[1]s := %[3]s.NewDDecimal(tree.DDecimal{Decimal: %[2]s})`,
    73  	types.DateFamily:    `%[1]s := %[3]s.NewDDate(tree.DDate{Date: pgdate.MakeCompatibleDateFromDisk(%[2]s)})`,
    74  	types.BytesFamily: `// Note that there is no need for a copy since DBytes uses a string
    75  						// as underlying storage, which will perform the copy for us.
    76  						%[1]s := %[3]s.NewDBytes(tree.DBytes(%[2]s))`,
    77  	types.EncodedKeyFamily: `// Note that there is no need for a copy since DEncodedKey uses a string
    78  						// as underlying storage, which will perform the copy for us.
    79  						%[1]s := %[3]s.NewDEncodedKey(tree.DEncodedKey(%[2]s))`,
    80  	types.JsonFamily: `
    81              // The following operation deliberately copies the input JSON
    82              // bytes, since FromEncoding is lazy and keeps a handle on the bytes
    83              // it is passed in.
    84              _bytes, _err := json.EncodeJSON(nil, %[2]s)
    85              if _err != nil {
    86                  colexecerror.ExpectedError(_err)
    87              }
    88              var _j json.JSON
    89              _j, _err = json.FromEncoding(_bytes)
    90              if _err != nil {
    91                  colexecerror.ExpectedError(_err)
    92              }
    93              %[1]s := %[3]s.NewDJSON(tree.DJSON{JSON: _j})`,
    94  	types.UuidFamily: ` // Note that there is no need for a copy because uuid.FromBytes
    95  						// will perform a copy.
    96  						id, err := uuid.FromBytes(%[2]s)
    97  						if err != nil {
    98  							colexecerror.InternalError(err)
    99  						}
   100  						%[1]s := %[3]s.NewDUuid(tree.DUuid{UUID: id})`,
   101  	types.TimestampFamily:   `%[1]s := %[3]s.NewDTimestamp(tree.DTimestamp{Time: %[2]s})`,
   102  	types.TimestampTZFamily: `%[1]s := %[3]s.NewDTimestampTZ(tree.DTimestampTZ{Time: %[2]s})`,
   103  	types.IntervalFamily:    `%[1]s := %[3]s.NewDInterval(tree.DInterval{Duration: %[2]s})`,
   104  	types.EnumFamily: `e, err := tree.MakeDEnumFromPhysicalRepresentation(ct, %[2]s)
   105  						if err != nil {
   106  							colexecerror.InternalError(err)
   107  						}
   108  						%[1]s := %[3]s.NewDEnum(e)`,
   109  	typeconv.DatumVecCanonicalTypeFamily: `%[1]s := %[2]s.(tree.Datum)`,
   110  }
   111  
   112  const vecToDatumTmpl = "pkg/sql/colconv/vec_to_datum_tmpl.go"
   113  
   114  func genVecToDatum(inputFileContents string, wr io.Writer) error {
   115  	r := strings.NewReplacer(
   116  		"_TYPE_FAMILY", "{{.TypeFamily}}",
   117  		"_TYPE_WIDTH", typeWidthReplacement,
   118  		"_VEC_METHOD", "{{.VecMethod}}",
   119  	)
   120  	s := r.Replace(inputFileContents)
   121  
   122  	assignConvertedRe := makeFunctionRegex("_ASSIGN_CONVERTED", 3)
   123  	s = assignConvertedRe.ReplaceAllString(s, makeTemplateFunctionCall("AssignConverted", 3))
   124  
   125  	tmpl, err := template.New("vec_to_datum").Funcs(template.FuncMap{"buildDict": buildDict}).Parse(s)
   126  	if err != nil {
   127  		return err
   128  	}
   129  
   130  	var tmplInfos []vecToDatumTmplInfo
   131  	// Note that String family is a special case that is handled separately by
   132  	// the template explicitly, so it is omitted from this slice.
   133  	optimizedTypeFamilies := []types.Family{
   134  		types.BoolFamily, types.IntFamily, types.FloatFamily, types.DecimalFamily,
   135  		types.DateFamily, types.BytesFamily, types.EncodedKeyFamily, types.JsonFamily,
   136  		types.UuidFamily, types.TimestampFamily, types.TimestampTZFamily, types.IntervalFamily,
   137  		types.EnumFamily,
   138  	}
   139  	for _, typeFamily := range optimizedTypeFamilies {
   140  		canonicalTypeFamily := typeconv.TypeFamilyToCanonicalTypeFamily(typeFamily)
   141  		tmplInfo := vecToDatumTmplInfo{TypeFamily: "types." + typeFamily.String()}
   142  		widths := supportedWidthsByCanonicalTypeFamily[canonicalTypeFamily]
   143  		if typeFamily != canonicalTypeFamily {
   144  			// We have a type family that is supported via another's physical
   145  			// representation (e.g. dates are the same as INT8s), so we
   146  			// override the widths to use only the default one.
   147  			widths = []int32{anyWidth}
   148  		}
   149  		for _, width := range widths {
   150  			tmplInfo.Widths = append(tmplInfo.Widths, vecToDatumWidthTmplInfo{
   151  				CanonicalTypeFamily: canonicalTypeFamily,
   152  				Width:               width,
   153  				VecMethod:           toVecMethod(canonicalTypeFamily, width),
   154  				ConversionTmpl:      vecToDatumConversionTmpls[typeFamily],
   155  			})
   156  		}
   157  		tmplInfos = append(tmplInfos, tmplInfo)
   158  	}
   159  
   160  	// Datum-backed types require special handling.
   161  	tmplInfos = append(tmplInfos, vecToDatumTmplInfo{
   162  		// This special "type family" value will result in matching all type
   163  		// families that haven't been matched explicitly, i.e a code like this
   164  		// will get generated:
   165  		//   switch typ.Family() {
   166  		//     case <all types that have optimized physical representation>
   167  		//       ...
   168  		//     case typeconv.DatumVecCanonicalTypeFamily:
   169  		//     default:
   170  		//       <datum-vec conversion>
   171  		//   }
   172  		// Such structure requires that datum-vec tmpl info is added last.
   173  		TypeFamily: "typeconv.DatumVecCanonicalTypeFamily: default",
   174  		Widths: []vecToDatumWidthTmplInfo{{
   175  			CanonicalTypeFamily: typeconv.DatumVecCanonicalTypeFamily,
   176  			Width:               anyWidth,
   177  			VecMethod:           toVecMethod(typeconv.DatumVecCanonicalTypeFamily, anyWidth),
   178  			ConversionTmpl:      vecToDatumConversionTmpls[typeconv.DatumVecCanonicalTypeFamily],
   179  		}},
   180  	})
   181  
   182  	return tmpl.Execute(wr, tmplInfos)
   183  }
   184  
   185  func init() {
   186  	registerGenerator(genVecToDatum, "vec_to_datum.eg.go", vecToDatumTmpl)
   187  }