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