github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/col_name.go (about) 1 // Copyright 2018 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 tree 12 13 import ( 14 "github.com/cockroachdb/cockroach/pkg/sql/sessiondata" 15 "github.com/cockroachdb/cockroach/pkg/sql/types" 16 ) 17 18 // GetRenderColName computes a name for a result column. 19 // A name specified with AS takes priority, otherwise a name 20 // is derived from the expression. 21 // 22 // This function is meant to be used on untransformed syntax trees. 23 // 24 // The algorithm is borrowed from FigureColName() in PostgreSQL 10, to be 25 // found in src/backend/parser/parse_target.c. We reuse this algorithm 26 // to provide names more compatible with PostgreSQL. 27 func GetRenderColName(searchPath sessiondata.SearchPath, target SelectExpr) (string, error) { 28 if target.As != "" { 29 return string(target.As), nil 30 } 31 32 _, s, err := ComputeColNameInternal(searchPath, target.Expr) 33 if err != nil { 34 return s, err 35 } 36 if len(s) == 0 { 37 s = "?column?" 38 } 39 return s, nil 40 } 41 42 // ComputeColNameInternal is the workhorse for GetRenderColName. 43 // The return value indicates the strength of the confidence in the result: 44 // 0 - no information 45 // 1 - second-best name choice 46 // 2 - good name choice 47 // 48 // The algorithm is borrowed from FigureColnameInternal in PostgreSQL 10, 49 // to be found in src/backend/parser/parse_target.c. 50 func ComputeColNameInternal(sp sessiondata.SearchPath, target Expr) (int, string, error) { 51 // The order of the type cases below mirrors that of PostgreSQL's 52 // own code, so that code reviews can more easily compare the two 53 // implementations. 54 switch e := target.(type) { 55 case *UnresolvedName: 56 if e.Star { 57 return 0, "", nil 58 } 59 return 2, e.Parts[0], nil 60 61 case *ColumnItem: 62 return 2, e.Column(), nil 63 64 case *IndirectionExpr: 65 return ComputeColNameInternal(sp, e.Expr) 66 67 case *FuncExpr: 68 fd, err := e.Func.Resolve(sp) 69 if err != nil { 70 return 0, "", err 71 } 72 return 2, fd.Name, nil 73 74 case *NullIfExpr: 75 return 2, "nullif", nil 76 77 case *IfExpr: 78 return 2, "if", nil 79 80 case *ParenExpr: 81 return ComputeColNameInternal(sp, e.Expr) 82 83 case *CastExpr: 84 strength, s, err := ComputeColNameInternal(sp, e.Expr) 85 if err != nil { 86 return 0, "", err 87 } 88 if strength <= 1 { 89 if typ, ok := GetStaticallyKnownType(e.Type); ok { 90 return 0, computeCastName(typ), nil 91 } 92 return 1, e.Type.SQLString(), nil 93 } 94 return strength, s, nil 95 96 case *AnnotateTypeExpr: 97 // Ditto CastExpr. 98 strength, s, err := ComputeColNameInternal(sp, e.Expr) 99 if err != nil { 100 return 0, "", err 101 } 102 if strength <= 1 { 103 if typ, ok := GetStaticallyKnownType(e.Type); ok { 104 return 0, computeCastName(typ), nil 105 } 106 return 1, e.Type.SQLString(), nil 107 } 108 return strength, s, nil 109 110 case *CollateExpr: 111 return ComputeColNameInternal(sp, e.Expr) 112 113 case *ArrayFlatten: 114 return 2, "array", nil 115 116 case *Subquery: 117 if e.Exists { 118 return 2, "exists", nil 119 } 120 return computeColNameInternalSubquery(sp, e.Select) 121 122 case *CaseExpr: 123 strength, s, err := 0, "", error(nil) 124 if e.Else != nil { 125 strength, s, err = ComputeColNameInternal(sp, e.Else) 126 } 127 if strength <= 1 { 128 s = "case" 129 strength = 1 130 } 131 return strength, s, err 132 133 case *Array: 134 return 2, "array", nil 135 136 case *Tuple: 137 if e.Row { 138 return 2, "row", nil 139 } 140 if len(e.Exprs) == 1 { 141 if len(e.Labels) > 0 { 142 return 2, e.Labels[0], nil 143 } 144 return ComputeColNameInternal(sp, e.Exprs[0]) 145 } 146 147 case *CoalesceExpr: 148 return 2, "coalesce", nil 149 150 // CockroachDB-specific nodes follow. 151 case *IfErrExpr: 152 if e.Else == nil { 153 return 2, "iserror", nil 154 } 155 return 2, "iferror", nil 156 157 case *ColumnAccessExpr: 158 return 2, e.ColName, nil 159 160 case *DBool: 161 // PostgreSQL implements the "true" and "false" literals 162 // by generating the expressions 't'::BOOL and 'f'::BOOL, so 163 // the derived column name is just "bool". Do the same. 164 return 1, "bool", nil 165 } 166 167 return 0, "", nil 168 } 169 170 // computeColNameInternalSubquery handles the cases of subqueries that 171 // cannot be handled by the function above due to the Go typing 172 // differences. 173 func computeColNameInternalSubquery( 174 sp sessiondata.SearchPath, s SelectStatement, 175 ) (int, string, error) { 176 switch e := s.(type) { 177 case *ParenSelect: 178 return computeColNameInternalSubquery(sp, e.Select.Select) 179 case *ValuesClause: 180 if len(e.Rows) > 0 && len(e.Rows[0]) == 1 { 181 return 2, "column1", nil 182 } 183 case *SelectClause: 184 if len(e.Exprs) == 1 { 185 if len(e.Exprs[0].As) > 0 { 186 return 2, string(e.Exprs[0].As), nil 187 } 188 return ComputeColNameInternal(sp, e.Exprs[0].Expr) 189 } 190 } 191 return 0, "", nil 192 } 193 194 // computeCastName returns the name manufactured by Postgres for a computed (or 195 // annotated, in case of CRDB) column. 196 func computeCastName(typ *types.T) string { 197 // Postgres uses the array element type name in case of array casts. 198 if typ.Family() == types.ArrayFamily { 199 typ = typ.ArrayContents() 200 } 201 return typ.PGName() 202 203 }