github.com/whtcorpsinc/MilevaDB-Prod@v0.0.0-20211104133533-f57f4be3b597/dbs/memristed/memex/generator/control_vec.go (about) 1 // Copyright 2020 WHTCORPS INC, Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // See the License for the specific language governing permissions and 12 // limitations under the License. 13 14 // +build ignore 15 16 package main 17 18 import ( 19 "bytes" 20 "go/format" 21 "io/ioutil" 22 "log" 23 "path/filepath" 24 "text/template" 25 26 . "github.com/whtcorpsinc/milevadb/memex/generator/helper" 27 ) 28 29 const header = `// Copyright 2020 WHTCORPS INC, Inc. 30 // 31 // Licensed under the Apache License, Version 2.0 (the "License"); 32 // you may not use this file except in compliance with the License. 33 // You may obtain a copy of the License at 34 // 35 // http://www.apache.org/licenses/LICENSE-2.0 36 // 37 // Unless required by applicable law or agreed to in writing, software 38 // distributed under the License is distributed on an "AS IS" BASIS, 39 // See the License for the specific language governing permissions and 40 // limitations under the License. 41 42 // Code generated by go generate in memex/generator; DO NOT EDIT. 43 44 package memex 45 46 import ( 47 "time" 48 49 "github.com/whtcorpsinc/milevadb/types" 50 "github.com/whtcorpsinc/milevadb/soliton/chunk" 51 ) 52 53 // NOTE: Control memexs optionally evaluate some branches depending on conditions, but vectorization executes all 54 // branches, during which the unnecessary branches may return errors or warnings. To avoid this case, when branches 55 // meet errors or warnings, the vectorization falls back the scalar execution. 56 57 ` 58 59 var builtinCaseWhenVec = template.Must(template.New("builtinCaseWhenVec").Parse(` 60 {{ range .Sigs }}{{ with .Arg0 }} 61 func (b *builtinCaseWhen{{ .TypeName }}Sig) fallbackEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 62 n := input.NumEvents() 63 {{- if .Fixed }} 64 result.Resize{{ .TypeNameInDeferredCauset }}(n, false) 65 x := result.{{ .TypeNameInDeferredCauset }}s() 66 for i := 0; i < n; i++ { 67 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 68 if err != nil { 69 return err 70 } 71 result.SetNull(i, isNull) 72 if isNull { 73 continue 74 } 75 {{ if eq .TypeName "Decimal" }} 76 x[i] = *res 77 {{ else if eq .TypeName "Duration" }} 78 x[i] = res.Duration 79 {{ else }} 80 x[i] = res 81 {{ end }} 82 } 83 {{ else }} 84 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 85 for i := 0; i < n; i++ { 86 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 87 if err != nil { 88 return err 89 } 90 if isNull { 91 result.AppendNull() 92 continue 93 } 94 result.Append{{ .TypeNameInDeferredCauset }}(res) 95 } 96 {{ end -}} 97 return nil 98 } 99 100 func (b *builtinCaseWhen{{ .TypeName }}Sig) vecEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 101 n := input.NumEvents() 102 args, l := b.getArgs(), len(b.getArgs()) 103 whens := make([]*chunk.DeferredCauset, l/2) 104 whensSlice := make([][]int64, l/2) 105 thens := make([]*chunk.DeferredCauset, l/2) 106 var eLse *chunk.DeferredCauset 107 {{- if .Fixed }} 108 thensSlice := make([][]{{.TypeNameGo}}, l/2) 109 var eLseSlice []{{.TypeNameGo}} 110 {{- end }} 111 sc := b.ctx.GetStochastikVars().StmtCtx 112 beforeWarns := sc.WarningCount() 113 114 for j := 0; j < l-1; j+=2 { 115 bufWhen, err := b.bufSlabPredictor.get(types.ETInt, n) 116 if err != nil { 117 return err 118 } 119 defer b.bufSlabPredictor.put(bufWhen) 120 err = args[j].VecEvalInt(b.ctx, input, bufWhen) 121 afterWarns := sc.WarningCount() 122 if err != nil || afterWarns > beforeWarns { 123 if afterWarns > beforeWarns { 124 sc.TruncateWarnings(int(beforeWarns)) 125 } 126 return b.fallbackEval{{ .TypeName }}(input, result) 127 } 128 whens[j/2] = bufWhen 129 whensSlice[j/2] = bufWhen.Int64s() 130 131 bufThen, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 132 if err != nil { 133 return err 134 } 135 defer b.bufSlabPredictor.put(bufThen) 136 err = args[j+1].VecEval{{ .TypeName }}(b.ctx, input, bufThen) 137 afterWarns = sc.WarningCount() 138 if err != nil || afterWarns > beforeWarns { 139 if afterWarns > beforeWarns { 140 sc.TruncateWarnings(int(beforeWarns)) 141 } 142 return b.fallbackEval{{ .TypeName }}(input, result) 143 } 144 thens[j/2] = bufThen 145 {{- if .Fixed }} 146 thensSlice[j/2] = bufThen.{{ .TypeNameInDeferredCauset }}s() 147 {{- end }} 148 } 149 // when clause(condition, result) -> args[i], args[i+1]; (i >= 0 && i+1 < l-1) 150 // else clause -> args[l-1] 151 // If case clause has else clause, l%2 == 1. 152 if l%2==1 { 153 bufElse, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 154 if err != nil { 155 return err 156 } 157 defer b.bufSlabPredictor.put(bufElse) 158 err = args[l-1].VecEval{{ .TypeName }}(b.ctx, input, bufElse) 159 afterWarns := sc.WarningCount() 160 if err != nil || afterWarns > beforeWarns { 161 if afterWarns > beforeWarns { 162 sc.TruncateWarnings(int(beforeWarns)) 163 } 164 return b.fallbackEval{{ .TypeName }}(input, result) 165 } 166 eLse = bufElse 167 {{- if .Fixed }} 168 eLseSlice = bufElse.{{ .TypeNameInDeferredCauset }}s() 169 {{- end }} 170 } 171 172 {{- if .Fixed }} 173 result.Resize{{ .TypeNameInDeferredCauset }}(n, false) 174 resultSlice := result.{{ .TypeNameInDeferredCauset }}s() 175 {{- else }} 176 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 177 {{- end }} 178 ROW: 179 for i := 0; i < n; i++ { 180 for j := 0; j < l/2; j++ { 181 if whens[j].IsNull(i) || whensSlice[j][i] == 0 { 182 continue 183 } 184 {{- if .Fixed }} 185 resultSlice[i] = thensSlice[j][i] 186 result.SetNull(i, thens[j].IsNull(i)) 187 {{- else }} 188 if thens[j].IsNull(i) { 189 result.AppendNull() 190 } else { 191 result.Append{{ .TypeNameInDeferredCauset }}(thens[j].Get{{ .TypeNameInDeferredCauset }}(i)) 192 } 193 {{- end }} 194 continue ROW 195 } 196 if eLse != nil { 197 {{- if .Fixed }} 198 resultSlice[i] = eLseSlice[i] 199 result.SetNull(i, eLse.IsNull(i)) 200 {{- else }} 201 if eLse.IsNull(i) { 202 result.AppendNull() 203 } else { 204 result.Append{{ .TypeNameInDeferredCauset }}(eLse.Get{{ .TypeNameInDeferredCauset }}(i)) 205 } 206 {{- end }} 207 } else { 208 {{- if .Fixed }} 209 result.SetNull(i, true) 210 {{- else }} 211 result.AppendNull() 212 {{- end }} 213 } 214 } 215 return nil 216 } 217 218 func (b *builtinCaseWhen{{ .TypeName }}Sig) vectorized() bool { 219 return true 220 } 221 {{ end }}{{/* with */}} 222 {{ end }}{{/* range .Sigs */}} 223 `)) 224 225 var builtinIfNullVec = template.Must(template.New("builtinIfNullVec").Parse(` 226 {{ range .Sigs }}{{ with .Arg0 }} 227 func (b *builtinIfNull{{ .TypeName }}Sig) fallbackEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 228 n := input.NumEvents() 229 {{- if .Fixed }} 230 x := result.{{ .TypeNameInDeferredCauset }}s() 231 for i := 0; i < n; i++ { 232 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 233 if err != nil { 234 return err 235 } 236 result.SetNull(i, isNull) 237 if isNull { 238 continue 239 } 240 {{ if eq .TypeName "Decimal" }} 241 x[i] = *res 242 {{ else if eq .TypeName "Duration" }} 243 x[i] = res.Duration 244 {{ else }} 245 x[i] = res 246 {{ end }} 247 } 248 {{ else }} 249 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 250 for i := 0; i < n; i++ { 251 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 252 if err != nil { 253 return err 254 } 255 if isNull { 256 result.AppendNull() 257 continue 258 } 259 result.Append{{ .TypeNameInDeferredCauset }}(res) 260 } 261 {{ end -}} 262 return nil 263 } 264 265 func (b *builtinIfNull{{ .TypeName }}Sig) vecEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 266 n := input.NumEvents() 267 {{- if .Fixed }} 268 if err := b.args[0].VecEval{{ .TypeName }}(b.ctx, input, result); err != nil { 269 return err 270 } 271 buf1, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 272 if err != nil { 273 return err 274 } 275 defer b.bufSlabPredictor.put(buf1) 276 sc := b.ctx.GetStochastikVars().StmtCtx 277 beforeWarns := sc.WarningCount() 278 err = b.args[1].VecEval{{ .TypeName }}(b.ctx, input, buf1) 279 afterWarns := sc.WarningCount() 280 if err != nil || afterWarns > beforeWarns { 281 if afterWarns > beforeWarns { 282 sc.TruncateWarnings(int(beforeWarns)) 283 } 284 return b.fallbackEval{{ .TypeName }}(input, result) 285 } 286 arg0 := result.{{ .TypeNameInDeferredCauset }}s() 287 arg1 := buf1.{{ .TypeNameInDeferredCauset }}s() 288 for i := 0; i < n; i++ { 289 if result.IsNull(i) && !buf1.IsNull(i) { 290 result.SetNull(i, false) 291 arg0[i] = arg1[i] 292 } 293 } 294 {{ else }} 295 buf0, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 296 if err != nil { 297 return err 298 } 299 defer b.bufSlabPredictor.put(buf0) 300 if err := b.args[0].VecEval{{ .TypeName }}(b.ctx, input, buf0); err != nil { 301 return err 302 } 303 buf1, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 304 if err != nil { 305 return err 306 } 307 defer b.bufSlabPredictor.put(buf1) 308 sc := b.ctx.GetStochastikVars().StmtCtx 309 beforeWarns := sc.WarningCount() 310 err = b.args[1].VecEval{{ .TypeName }}(b.ctx, input, buf1) 311 afterWarns := sc.WarningCount() 312 if err != nil || afterWarns > beforeWarns { 313 if afterWarns > beforeWarns { 314 sc.TruncateWarnings(int(beforeWarns)) 315 } 316 return b.fallbackEval{{ .TypeName }}(input,result) 317 } 318 319 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 320 for i := 0; i < n; i++ { 321 if !buf0.IsNull(i) { 322 result.Append{{ .TypeNameInDeferredCauset }}(buf0.Get{{ .TypeNameInDeferredCauset }}(i)) 323 } else if !buf1.IsNull(i) { 324 result.Append{{ .TypeNameInDeferredCauset }}(buf1.Get{{ .TypeNameInDeferredCauset }}(i)) 325 } else { 326 result.AppendNull() 327 } 328 } 329 {{ end -}} 330 return nil 331 } 332 333 func (b *builtinIfNull{{ .TypeName }}Sig) vectorized() bool { 334 return true 335 } 336 {{ end }}{{/* with */}} 337 {{ end }}{{/* range .Sigs */}} 338 `)) 339 340 var builtinIfVec = template.Must(template.New("builtinIfVec").Parse(` 341 {{ range .Sigs }}{{ with .Arg0 }} 342 func (b *builtinIf{{ .TypeName }}Sig) fallbackEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 343 n := input.NumEvents() 344 {{- if .Fixed }} 345 x := result.{{ .TypeNameInDeferredCauset }}s() 346 for i := 0; i < n; i++ { 347 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 348 if err != nil { 349 return err 350 } 351 result.SetNull(i, isNull) 352 if isNull { 353 continue 354 } 355 {{ if eq .TypeName "Decimal" }} 356 x[i] = *res 357 {{ else if eq .TypeName "Duration" }} 358 x[i] = res.Duration 359 {{ else }} 360 x[i] = res 361 {{ end }} 362 } 363 {{ else }} 364 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 365 for i := 0; i < n; i++ { 366 res, isNull, err := b.eval{{ .TypeName }}(input.GetEvent(i)) 367 if err != nil { 368 return err 369 } 370 if isNull { 371 result.AppendNull() 372 continue 373 } 374 result.Append{{ .TypeNameInDeferredCauset }}(res) 375 } 376 {{ end -}} 377 return nil 378 } 379 380 func (b *builtinIf{{ .TypeName }}Sig) vecEval{{ .TypeName }}(input *chunk.Chunk, result *chunk.DeferredCauset) error { 381 n := input.NumEvents() 382 buf0, err := b.bufSlabPredictor.get(types.ETInt, n) 383 if err != nil { 384 return err 385 } 386 defer b.bufSlabPredictor.put(buf0) 387 if err := b.args[0].VecEvalInt(b.ctx, input, buf0); err != nil { 388 return err 389 } 390 sc := b.ctx.GetStochastikVars().StmtCtx 391 beforeWarns := sc.WarningCount() 392 {{- if .Fixed }} 393 err = b.args[1].VecEval{{ .TypeName }}(b.ctx, input, result) 394 {{- else }} 395 buf1, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 396 if err != nil { 397 return err 398 } 399 defer b.bufSlabPredictor.put(buf1) 400 err = b.args[1].VecEval{{ .TypeName }}(b.ctx, input, buf1) 401 {{- end }} 402 afterWarns := sc.WarningCount() 403 if err != nil || afterWarns > beforeWarns { 404 if afterWarns > beforeWarns { 405 sc.TruncateWarnings(int(beforeWarns)) 406 } 407 return b.fallbackEval{{ .TypeName }}(input, result) 408 } 409 410 buf2, err := b.bufSlabPredictor.get(types.ET{{ .ETName }}, n) 411 if err != nil { 412 return err 413 } 414 defer b.bufSlabPredictor.put(buf2) 415 err = b.args[2].VecEval{{ .TypeName }}(b.ctx, input, buf2) 416 afterWarns = sc.WarningCount() 417 if err != nil || afterWarns > beforeWarns { 418 if afterWarns > beforeWarns { 419 sc.TruncateWarnings(int(beforeWarns)) 420 } 421 return b.fallbackEval{{ .TypeName }}(input, result) 422 } 423 {{ if not .Fixed }} 424 result.Reserve{{ .TypeNameInDeferredCauset }}(n) 425 {{- end }} 426 arg0 := buf0.Int64s() 427 {{- if .Fixed }} 428 arg2 := buf2.{{ .TypeNameInDeferredCauset }}s() 429 rs := result.{{ .TypeNameInDeferredCauset }}s() 430 {{- end }} 431 for i := 0; i < n; i++ { 432 arg := arg0[i] 433 isNull0 := buf0.IsNull(i) 434 switch { 435 case isNull0 || arg == 0: 436 {{- if .Fixed }} 437 if buf2.IsNull(i) { 438 result.SetNull(i, true) 439 } else { 440 result.SetNull(i, false) 441 rs[i] = arg2[i] 442 } 443 {{- else }} 444 if buf2.IsNull(i) { 445 result.AppendNull() 446 } else { 447 result.Append{{ .TypeNameInDeferredCauset }}(buf2.Get{{ .TypeNameInDeferredCauset }}(i)) 448 } 449 {{- end }} 450 case arg != 0: 451 {{- if .Fixed }} 452 {{- else }} 453 if buf1.IsNull(i) { 454 result.AppendNull() 455 } else { 456 result.Append{{ .TypeNameInDeferredCauset }}(buf1.Get{{ .TypeNameInDeferredCauset }}(i)) 457 } 458 {{- end }} 459 } 460 } 461 return nil 462 } 463 464 func (b *builtinIf{{ .TypeName }}Sig) vectorized() bool { 465 return true 466 } 467 {{ end }}{{/* with */}} 468 {{ end }}{{/* range .Sigs */}} 469 `)) 470 471 var testFile = template.Must(template.New("testFile").Parse(`// Copyright 2020 WHTCORPS INC, Inc. 472 // 473 // Licensed under the Apache License, Version 2.0 (the "License"); 474 // you may not use this file except in compliance with the License. 475 // You may obtain a copy of the License at 476 // 477 // http://www.apache.org/licenses/LICENSE-2.0 478 // 479 // Unless required by applicable law or agreed to in writing, software 480 // distributed under the License is distributed on an "AS IS" BASIS, 481 // See the License for the specific language governing permissions and 482 // limitations under the License. 483 484 // Code generated by go generate in memex/generator; DO NOT EDIT. 485 486 package memex 487 488 import ( 489 "math/rand" 490 "testing" 491 492 . "github.com/whtcorpsinc/check" 493 "github.com/whtcorpsinc/BerolinaSQL/ast" 494 "github.com/whtcorpsinc/milevadb/types" 495 ) 496 497 var defaultControlIntGener = &controlIntGener{zeroRation: 0.3, defaultGener: *newDefaultGener(0.3, types.ETInt)} 498 499 type controlIntGener struct { 500 zeroRation float64 501 defaultGener 502 } 503 504 func (g *controlIntGener) gen() interface{} { 505 if rand.Float64() < g.zeroRation { 506 return int64(0) 507 } 508 return g.defaultGener.gen() 509 } 510 511 {{/* Add more test cases here if we have more functions in this file */}} 512 var vecBuiltin{{.Category}}Cases = map[string][]vecExprBenchCase{ 513 {{ with index .Functions 0 }} 514 ast.Case: { 515 {{ range .Sigs }} 516 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ETInt, types.ET{{ .Arg0.ETName }}}, geners: []dataGenerator{defaultControlIntGener}}, 517 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ETInt, types.ET{{ .Arg0.ETName }}, types.ET{{ .Arg0.ETName }}}, geners: []dataGenerator{defaultControlIntGener}}, 518 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ETInt, types.ET{{ .Arg0.ETName }}, types.ETInt, types.ET{{ .Arg0.ETName }}}, geners: []dataGenerator{defaultControlIntGener, nil, defaultControlIntGener}}, 519 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ETInt, types.ET{{ .Arg0.ETName }}, types.ETInt, types.ET{{ .Arg0.ETName }}, types.ET{{ .Arg0.ETName }}}, geners: []dataGenerator{defaultControlIntGener, nil, defaultControlIntGener}}, 520 {{ end }} 521 }, 522 {{ end }} 523 524 {{ with index .Functions 1 }} 525 ast.Ifnull: { 526 {{ range .Sigs }} 527 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ET{{ .Arg0.ETName }}, types.ET{{ .Arg0.ETName }}}}, 528 {{ end }} 529 }, 530 {{ end }} 531 532 {{ with index .Functions 2 }} 533 ast.If: { 534 {{ range .Sigs }} 535 {retEvalType: types.ET{{ .Arg0.ETName }}, childrenTypes: []types.EvalType{types.ETInt, types.ET{{ .Arg0.ETName }}, types.ET{{ .Arg0.ETName }}}, geners: []dataGenerator{defaultControlIntGener}}, 536 {{ end }} 537 }, 538 {{ end }} 539 } 540 541 func (s *testEvaluatorSuite) TestVectorizedBuiltin{{.Category}}EvalOneVecGenerated(c *C) { 542 testVectorizedEvalOneVec(c, vecBuiltinControlCases) 543 } 544 545 func (s *testEvaluatorSuite) TestVectorizedBuiltin{{.Category}}FuncGenerated(c *C) { 546 testVectorizedBuiltinFunc(c, vecBuiltinControlCases) 547 } 548 549 func BenchmarkVectorizedBuiltin{{.Category}}EvalOneVecGenerated(b *testing.B) { 550 benchmarkVectorizedEvalOneVec(b, vecBuiltinControlCases) 551 } 552 553 func BenchmarkVectorizedBuiltin{{.Category}}FuncGenerated(b *testing.B) { 554 benchmarkVectorizedBuiltinFunc(b, vecBuiltinControlCases) 555 } 556 `)) 557 558 type typeContext struct { 559 // Describe the name of "github.com/whtcorpsinc/milevadb/types".ET{{ .ETName }} 560 ETName string 561 // Describe the name of "github.com/whtcorpsinc/milevadb/memex".VecExpr.VecEval{{ .TypeName }} 562 // If undefined, it's same as ETName. 563 TypeName string 564 // Describe the name of "github.com/whtcorpsinc/milevadb/soliton/chunk".*DeferredCauset.Append{{ .TypeNameInDeferredCauset }}, 565 // Resize{{ .TypeNameInDeferredCauset }}, Reserve{{ .TypeNameInDeferredCauset }}, Get{{ .TypeNameInDeferredCauset }} and 566 // {{ .TypeNameInDeferredCauset }}s. 567 // If undefined, it's same as TypeName. 568 TypeNameInDeferredCauset string 569 // Same as "github.com/whtcorpsinc/milevadb/soliton/chunk".getFixedLen() 570 Fixed bool 571 } 572 573 var caseWhenSigs = []sig{ 574 {Arg0: TypeInt}, 575 {Arg0: TypeReal}, 576 {Arg0: TypeDecimal}, 577 {Arg0: TypeString}, 578 {Arg0: TypeDatetime}, 579 {Arg0: TypeDuration}, 580 {Arg0: TypeJSON}, 581 } 582 583 var ifNullSigs = []sig{ 584 {Arg0: TypeInt}, 585 {Arg0: TypeReal}, 586 {Arg0: TypeDecimal}, 587 {Arg0: TypeString}, 588 {Arg0: TypeDatetime}, 589 {Arg0: TypeDuration}, 590 {Arg0: TypeJSON}, 591 } 592 593 var ifSigs = []sig{ 594 {Arg0: TypeInt}, 595 {Arg0: TypeReal}, 596 {Arg0: TypeDecimal}, 597 {Arg0: TypeString}, 598 {Arg0: TypeDatetime}, 599 {Arg0: TypeDuration}, 600 {Arg0: TypeJSON}, 601 } 602 603 type sig struct { 604 Arg0 TypeContext 605 } 606 607 type function struct { 608 FuncName string 609 Sigs []sig 610 Tmpl *template.Template 611 } 612 613 var tmplVal = struct { 614 Category string 615 Functions []function 616 }{ 617 Category: "Control", 618 Functions: []function{ 619 {FuncName: "Case", Sigs: caseWhenSigs, Tmpl: builtinCaseWhenVec}, 620 {FuncName: "Ifnull", Sigs: ifNullSigs, Tmpl: builtinIfNullVec}, 621 {FuncName: "If", Sigs: ifSigs, Tmpl: builtinIfVec}, 622 }, 623 } 624 625 func generateDotGo(fileName string) error { 626 w := new(bytes.Buffer) 627 w.WriteString(header) 628 for _, function := range tmplVal.Functions { 629 err := function.Tmpl.InterDircute(w, function) 630 if err != nil { 631 return err 632 } 633 } 634 data, err := format.Source(w.Bytes()) 635 if err != nil { 636 log.Println("[Warn]", fileName+": gofmt failed", err) 637 data = w.Bytes() // write original data for debugging 638 } 639 return ioutil.WriteFile(fileName, data, 0644) 640 } 641 642 func generateTestDotGo(fileName string) error { 643 w := new(bytes.Buffer) 644 err := testFile.InterDircute(w, tmplVal) 645 if err != nil { 646 return err 647 } 648 data, err := format.Source(w.Bytes()) 649 if err != nil { 650 log.Println("[Warn]", fileName+": gofmt failed", err) 651 data = w.Bytes() // write original data for debugging 652 } 653 return ioutil.WriteFile(fileName, data, 0644) 654 } 655 656 // generateOneFile generate one xxx.go file and the associated xxx_test.go file. 657 func generateOneFile(fileNamePrefix string) (err error) { 658 659 err = generateDotGo(fileNamePrefix + ".go") 660 if err != nil { 661 return 662 } 663 err = generateTestDotGo(fileNamePrefix + "_test.go") 664 return 665 } 666 667 func main() { 668 var err error 669 outputDir := "." 670 err = generateOneFile(filepath.Join(outputDir, "builtin_control_vec_generated")) 671 if err != nil { 672 log.Fatalln("generateOneFile", err) 673 } 674 }