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 }