github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/name_part.go (about) 1 // Copyright 2016 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/lex" 15 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgcode" 16 "github.com/cockroachdb/cockroach/pkg/sql/pgwire/pgerror" 17 ) 18 19 // A Name is an SQL identifier. 20 // 21 // In general, a Name is the result of parsing a name nonterminal, which is used 22 // in the grammar where reserved keywords cannot be distinguished from 23 // identifiers. A Name that matches a reserved keyword must thus be quoted when 24 // formatted. (Names also need quoting for a variety of other reasons; see 25 // isBareIdentifier.) 26 // 27 // For historical reasons, some Names are instead the result of parsing 28 // `unrestricted_name` nonterminals. See UnrestrictedName for details. 29 type Name string 30 31 // Format implements the NodeFormatter interface. 32 func (n *Name) Format(ctx *FmtCtx) { 33 f := ctx.flags 34 if f.HasFlags(FmtAnonymize) && !isArityIndicatorString(string(*n)) { 35 ctx.WriteByte('_') 36 } else { 37 lex.EncodeRestrictedSQLIdent(&ctx.Buffer, string(*n), f.EncodeFlags()) 38 } 39 } 40 41 // NameStringP escapes an identifier stored in a heap string to a SQL 42 // identifier, avoiding a heap allocation. 43 func NameStringP(s *string) string { 44 return ((*Name)(s)).String() 45 } 46 47 // NameString escapes an identifier stored in a string to a SQL 48 // identifier. 49 func NameString(s string) string { 50 return ((*Name)(&s)).String() 51 } 52 53 // ErrNameStringP escapes an identifier stored a string to a SQL 54 // identifier suitable for printing in error messages, avoiding a heap 55 // allocation. 56 func ErrNameStringP(s *string) string { 57 return ErrString(((*Name)(s))) 58 } 59 60 // ErrNameString escapes an identifier stored a string to a SQL 61 // identifier suitable for printing in error messages. 62 func ErrNameString(s string) string { 63 return ErrString(((*Name)(&s))) 64 } 65 66 // Normalize normalizes to lowercase and Unicode Normalization Form C 67 // (NFC). 68 func (n Name) Normalize() string { 69 return lex.NormalizeName(string(n)) 70 } 71 72 // An UnrestrictedName is a Name that does not need to be escaped when it 73 // matches a reserved keyword. 74 // 75 // In general, an UnrestrictedName is the result of parsing an unrestricted_name 76 // nonterminal, which is used in the grammar where reserved keywords can be 77 // unambiguously interpreted as identifiers. When formatted, an UnrestrictedName 78 // that matches a reserved keyword thus does not need to be quoted. 79 // 80 // For historical reasons, some unrestricted_name nonterminals are instead 81 // parsed as Names. The only user-visible impact of this is that we are too 82 // aggressive about quoting names in certain positions. New grammar rules should 83 // prefer to parse unrestricted_name nonterminals into UnrestrictedNames. 84 type UnrestrictedName string 85 86 // Format implements the NodeFormatter interface. 87 func (u *UnrestrictedName) Format(ctx *FmtCtx) { 88 f := ctx.flags 89 if f.HasFlags(FmtAnonymize) { 90 ctx.WriteByte('_') 91 } else { 92 lex.EncodeUnrestrictedSQLIdent(&ctx.Buffer, string(*u), f.EncodeFlags()) 93 } 94 } 95 96 // ToStrings converts the name list to an array of regular strings. 97 func (l NameList) ToStrings() []string { 98 if l == nil { 99 return nil 100 } 101 names := make([]string, len(l)) 102 for i, n := range l { 103 names[i] = string(n) 104 } 105 return names 106 } 107 108 // A NameList is a list of identifiers. 109 type NameList []Name 110 111 // Format implements the NodeFormatter interface. 112 func (l *NameList) Format(ctx *FmtCtx) { 113 for i := range *l { 114 if i > 0 { 115 ctx.WriteString(", ") 116 } 117 ctx.FormatNode(&(*l)[i]) 118 } 119 } 120 121 // ArraySubscript corresponds to the syntax `<name>[ ... ]`. 122 type ArraySubscript struct { 123 Begin Expr 124 End Expr 125 Slice bool 126 } 127 128 // Format implements the NodeFormatter interface. 129 func (a *ArraySubscript) Format(ctx *FmtCtx) { 130 ctx.WriteByte('[') 131 if a.Begin != nil { 132 ctx.FormatNode(a.Begin) 133 } 134 if a.Slice { 135 ctx.WriteByte(':') 136 if a.End != nil { 137 ctx.FormatNode(a.End) 138 } 139 } 140 ctx.WriteByte(']') 141 } 142 143 // UnresolvedName corresponds to an unresolved qualified name. 144 type UnresolvedName struct { 145 // NumParts indicates the number of name parts specified, including 146 // the star. Always 1 or greater. 147 NumParts int 148 149 // Star indicates the name ends with a star. 150 // In that case, Parts below is empty in the first position. 151 Star bool 152 153 // Parts are the name components, in reverse order. 154 // There are at most 4: column, table, schema, catalog/db. 155 // 156 // Note: NameParts has a fixed size so that we avoid a heap 157 // allocation for the slice every time we construct an 158 // UnresolvedName. It does imply however that Parts does not have 159 // a meaningful "length"; its actual length (the number of parts 160 // specified) is populated in NumParts above. 161 Parts NameParts 162 } 163 164 // NameParts is the array of strings that composes the path in an 165 // UnresolvedName. 166 type NameParts = [4]string 167 168 // Format implements the NodeFormatter interface. 169 func (u *UnresolvedName) Format(ctx *FmtCtx) { 170 stopAt := 1 171 if u.Star { 172 stopAt = 2 173 } 174 for i := u.NumParts; i >= stopAt; i-- { 175 // The first part to print is the last item in u.Parts. It is also 176 // a potentially restricted name to disambiguate from keywords in 177 // the grammar, so print it out as a "Name". Every part after that is 178 // necessarily an unrestricted name. 179 if i == u.NumParts { 180 ctx.FormatNode((*Name)(&u.Parts[i-1])) 181 } else { 182 ctx.FormatNode((*UnrestrictedName)(&u.Parts[i-1])) 183 } 184 if i > 1 { 185 ctx.WriteByte('.') 186 } 187 } 188 if u.Star { 189 ctx.WriteByte('*') 190 } 191 } 192 func (u *UnresolvedName) String() string { return AsString(u) } 193 194 // NewUnresolvedName constructs an UnresolvedName from some strings. 195 func NewUnresolvedName(args ...string) *UnresolvedName { 196 n := MakeUnresolvedName(args...) 197 return &n 198 } 199 200 // MakeUnresolvedName constructs an UnresolvedName from some strings. 201 func MakeUnresolvedName(args ...string) UnresolvedName { 202 n := UnresolvedName{NumParts: len(args)} 203 for i := 0; i < len(args); i++ { 204 n.Parts[i] = args[len(args)-1-i] 205 } 206 return n 207 } 208 209 // ToUnresolvedObjectName converts an UnresolvedName to an UnresolvedObjectName. 210 func (u *UnresolvedName) ToUnresolvedObjectName(idx AnnotationIdx) (*UnresolvedObjectName, error) { 211 if u.NumParts == 4 { 212 return nil, pgerror.Newf(pgcode.Syntax, "improper qualified name (too many dotted names): %s", u) 213 } 214 return NewUnresolvedObjectName( 215 u.NumParts, 216 [3]string{u.Parts[0], u.Parts[1], u.Parts[2]}, 217 idx, 218 ) 219 }