github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/sem/tree/object_name.go (about) 1 // Copyright 2020 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 // ObjectName is a common interface for qualified object names. 14 type ObjectName interface { 15 NodeFormatter 16 Object() string 17 Schema() string 18 Catalog() string 19 FQString() string 20 objectName() 21 } 22 23 var _ ObjectName = &TableName{} 24 var _ ObjectName = &TypeName{} 25 26 // objName is the internal type for a qualified object. 27 type objName struct { 28 // ObjectName is the unqualified name for the object 29 // (table/view/sequence/function/type). 30 ObjectName Name 31 32 // ObjectNamePrefix is the path to the object. This can be modified 33 // further by name resolution, see name_resolution.go. 34 ObjectNamePrefix 35 } 36 37 func (o *objName) Object() string { 38 return string(o.ObjectName) 39 } 40 41 // ToUnresolvedObjectName converts the type name to an unresolved object name. 42 // Schema and catalog are included if indicated by the ExplicitSchema and 43 // ExplicitCatalog flags. 44 func (o *objName) ToUnresolvedObjectName() *UnresolvedObjectName { 45 u := &UnresolvedObjectName{} 46 47 u.NumParts = 1 48 u.Parts[0] = string(o.ObjectName) 49 if o.ExplicitSchema { 50 u.Parts[u.NumParts] = string(o.SchemaName) 51 u.NumParts++ 52 } 53 if o.ExplicitCatalog { 54 u.Parts[u.NumParts] = string(o.CatalogName) 55 u.NumParts++ 56 } 57 return u 58 } 59 60 // ObjectNamePrefix corresponds to the path prefix of an object name. 61 type ObjectNamePrefix struct { 62 CatalogName Name 63 SchemaName Name 64 65 // ExplicitCatalog is true iff the catalog was explicitly specified 66 // or it needs to be rendered during pretty-printing. 67 ExplicitCatalog bool 68 // ExplicitSchema is true iff the schema was explicitly specified 69 // or it needs to be rendered during pretty-printing. 70 ExplicitSchema bool 71 } 72 73 // Format implements the NodeFormatter interface. 74 func (tp *ObjectNamePrefix) Format(ctx *FmtCtx) { 75 alwaysFormat := ctx.alwaysFormatTablePrefix() 76 if tp.ExplicitSchema || alwaysFormat { 77 if tp.ExplicitCatalog || alwaysFormat { 78 ctx.FormatNode(&tp.CatalogName) 79 ctx.WriteByte('.') 80 } 81 ctx.FormatNode(&tp.SchemaName) 82 } 83 } 84 85 func (tp *ObjectNamePrefix) String() string { return AsString(tp) } 86 87 // Schema retrieves the unqualified schema name. 88 func (tp *ObjectNamePrefix) Schema() string { 89 return string(tp.SchemaName) 90 } 91 92 // Catalog retrieves the unqualified catalog name. 93 func (tp *ObjectNamePrefix) Catalog() string { 94 return string(tp.CatalogName) 95 } 96 97 // UnresolvedObjectName is an unresolved qualified name for a database object 98 // (table, view, etc). It is like UnresolvedName but more restrictive. 99 // It should only be constructed via NewUnresolvedObjectName. 100 type UnresolvedObjectName struct { 101 // NumParts indicates the number of name parts specified; always 1 or greater. 102 NumParts int 103 104 // Parts are the name components, in reverse order. 105 // There are at most 3: object name, schema, catalog/db. 106 // 107 // Note: Parts has a fixed size so that we avoid a heap allocation for the 108 // slice every time we construct an UnresolvedObjectName. It does imply 109 // however that Parts does not have a meaningful "length"; its actual length 110 // (the number of parts specified) is populated in NumParts above. 111 Parts [3]string 112 113 // UnresolvedObjectName can be annotated with a *TableName. 114 AnnotatedNode 115 } 116 117 // UnresolvedObjectName implements TableExpr. 118 func (*UnresolvedObjectName) tableExpr() {} 119 120 // NewUnresolvedObjectName creates an unresolved object name, verifying that it 121 // is well-formed. 122 func NewUnresolvedObjectName( 123 numParts int, parts [3]string, annotationIdx AnnotationIdx, 124 ) (*UnresolvedObjectName, error) { 125 u := &UnresolvedObjectName{ 126 NumParts: numParts, 127 Parts: parts, 128 AnnotatedNode: AnnotatedNode{AnnIdx: annotationIdx}, 129 } 130 if u.NumParts < 1 { 131 return nil, newInvTableNameError(u) 132 } 133 134 // Check that all the parts specified are not empty. 135 // It's OK if the catalog name is empty. 136 // We allow this in e.g. `select * from "".crdb_internal.tables`. 137 lastCheck := u.NumParts 138 if lastCheck > 2 { 139 lastCheck = 2 140 } 141 for i := 0; i < lastCheck; i++ { 142 if len(u.Parts[i]) == 0 { 143 return nil, newInvTableNameError(u) 144 } 145 } 146 return u, nil 147 } 148 149 // Resolved returns the resolved name in the annotation for this node (or nil if 150 // there isn't one). 151 func (u *UnresolvedObjectName) Resolved(ann *Annotations) ObjectName { 152 r := u.GetAnnotation(ann) 153 if r == nil { 154 return nil 155 } 156 return r.(ObjectName) 157 } 158 159 // Format implements the NodeFormatter interface. 160 func (u *UnresolvedObjectName) Format(ctx *FmtCtx) { 161 // If we want to format the corresponding resolved name, look it up in the 162 // annotation. 163 if ctx.HasFlags(FmtAlwaysQualifyTableNames) || ctx.tableNameFormatter != nil { 164 if ctx.tableNameFormatter != nil && ctx.ann == nil { 165 // TODO(radu): this is a temporary hack while we transition to using 166 // unresolved names everywhere. We will need to revisit and see if we need 167 // to switch to (or add) an UnresolvedObjectName formatter. 168 tn := u.ToTableName() 169 tn.Format(ctx) 170 return 171 } 172 173 if n := u.Resolved(ctx.ann); n != nil { 174 n.Format(ctx) 175 return 176 } 177 } 178 179 for i := u.NumParts; i > 0; i-- { 180 // The first part to print is the last item in u.Parts. It is also 181 // a potentially restricted name to disambiguate from keywords in 182 // the grammar, so print it out as a "Name". Every part after that is 183 // necessarily an unrestricted name. 184 if i == u.NumParts { 185 ctx.FormatNode((*Name)(&u.Parts[i-1])) 186 } else { 187 ctx.WriteByte('.') 188 ctx.FormatNode((*UnrestrictedName)(&u.Parts[i-1])) 189 } 190 } 191 } 192 193 func (u *UnresolvedObjectName) String() string { return AsString(u) } 194 195 // ToTableName converts the unresolved name to a table name. 196 // 197 // TODO(radu): the schema and catalog names might not be in the right places; we 198 // would only figure that out during name resolution. This method is temporary, 199 // while we change all the code paths to only use TableName after resolution. 200 func (u *UnresolvedObjectName) ToTableName() TableName { 201 return TableName{objName{ 202 ObjectName: Name(u.Parts[0]), 203 ObjectNamePrefix: ObjectNamePrefix{ 204 SchemaName: Name(u.Parts[1]), 205 CatalogName: Name(u.Parts[2]), 206 ExplicitSchema: u.NumParts >= 2, 207 ExplicitCatalog: u.NumParts >= 3, 208 }, 209 }} 210 } 211 212 // ToUnresolvedName converts the unresolved object name to the more general 213 // unresolved name. 214 func (u *UnresolvedObjectName) ToUnresolvedName() *UnresolvedName { 215 return &UnresolvedName{ 216 NumParts: u.NumParts, 217 Parts: NameParts{u.Parts[0], u.Parts[1], u.Parts[2]}, 218 } 219 } 220 221 // Utility methods below for operating on UnresolvedObjectName more natural. 222 223 // Object returns the unqualified object name. 224 func (u *UnresolvedObjectName) Object() string { 225 return u.Parts[0] 226 } 227 228 // Schema returns the schema of the object. 229 func (u *UnresolvedObjectName) Schema() string { 230 return u.Parts[1] 231 } 232 233 // Catalog returns the catalog of the object. 234 func (u *UnresolvedObjectName) Catalog() string { 235 return u.Parts[2] 236 } 237 238 // HasExplicitSchema returns whether a schema is specified on the object. 239 func (u *UnresolvedObjectName) HasExplicitSchema() bool { 240 return u.NumParts >= 2 241 } 242 243 // HasExplicitCatalog returns whether a catalog is specified on the object. 244 func (u *UnresolvedObjectName) HasExplicitCatalog() bool { 245 return u.NumParts >= 3 246 }