github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/opt/memo/expr_name_gen.go (about) 1 // Copyright 2019 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 memo 12 13 import ( 14 "fmt" 15 "strings" 16 17 "github.com/cockroachdb/cockroach/pkg/sql/opt" 18 "github.com/cockroachdb/cockroach/pkg/sql/opt/props/physical" 19 ) 20 21 // ExprNameGenerator is used to generate a unique name for each relational 22 // expression in a query tree. See GenerateName for details. 23 type ExprNameGenerator struct { 24 prefix string 25 exprCount int 26 } 27 28 // NewExprNameGenerator creates a new instance of ExprNameGenerator, 29 // initialized with the given prefix. 30 func NewExprNameGenerator(prefix string) *ExprNameGenerator { 31 return &ExprNameGenerator{prefix: prefix} 32 } 33 34 // GenerateName generates a name for a relational expression with the given 35 // operator. It is used to generate names for each relational expression 36 // in a query tree, corresponding to the tables that will be created if the 37 // session variable `save_tables_prefix` is non-empty. 38 // 39 // Each invocation of GenerateName is guaranteed to produce a unique name for 40 // a given instance of ExprNameGenerator. This works because each name is 41 // appended with a unique, auto-incrementing number. For readability, the 42 // generated names also contain a common prefix and the name of the relational 43 // operator separated with underscores. For example: my_query_scan_2. 44 // 45 // Since the names are generated with an auto-incrementing number, the order 46 // of invocation is important. For a given query, the number assigned to each 47 // relational subexpression corresponds to the order in which the expression 48 // was encountered during tree traversal. Thus, in order to generate a 49 // consistent name, always call GenerateName in a pre-order traversal of the 50 // expression tree. 51 // 52 func (g *ExprNameGenerator) GenerateName(op opt.Operator) string { 53 // Replace all instances of "-" in the operator name with "_" in order to 54 // create a legal table name. 55 operator := strings.Replace(op.String(), "-", "_", -1) 56 g.exprCount++ 57 return fmt.Sprintf("%s_%s_%d", g.prefix, operator, g.exprCount) 58 } 59 60 // ColumnNameGenerator is used to generate a unique name for each column of a 61 // relational expression. See GenerateName for details. 62 type ColumnNameGenerator struct { 63 e RelExpr 64 pres physical.Presentation 65 seen map[string]int 66 } 67 68 // NewColumnNameGenerator creates a new instance of ColumnNameGenerator, 69 // initialized with the given relational expression. 70 func NewColumnNameGenerator(e RelExpr) *ColumnNameGenerator { 71 return &ColumnNameGenerator{ 72 e: e, 73 pres: e.RequiredPhysical().Presentation, 74 seen: make(map[string]int, e.Relational().OutputCols.Len()), 75 } 76 } 77 78 // GenerateName generates a unique name for each column in a relational 79 // expression. This function is used to generate consistent, unique names 80 // for the columns in the table that will be created if the session 81 // variable `save_tables_prefix` is non-empty. 82 func (g *ColumnNameGenerator) GenerateName(col opt.ColumnID) string { 83 colMeta := g.e.Memo().Metadata().ColumnMeta(col) 84 colName := colMeta.Alias 85 86 // Check whether the presentation has a different name for this column, and 87 // use it if available. 88 for i := range g.pres { 89 if g.pres[i].ID == col { 90 colName = g.pres[i].Alias 91 break 92 } 93 } 94 95 // Every column name must be unique. 96 if cnt, ok := g.seen[colName]; ok { 97 g.seen[colName]++ 98 colName = fmt.Sprintf("%s_%d", colName, cnt) 99 } else { 100 g.seen[colName] = 1 101 } 102 103 return colName 104 }