github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/sem/tree/name_resolution.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 "fmt" 16 17 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgcode" 18 "github.com/cockroachdb/cockroachdb-parser/pkg/sql/pgwire/pgerror" 19 ) 20 21 // This file contains the two major components to name resolution: 22 // 23 // - classification algorithms. These are used when two different 24 // semantic constructs can appear in the same position in the SQL grammar. 25 // For example, table patterns and table names in GRANT. 26 // 27 // - resolution algorithms. These are used to map an unresolved name 28 // or pattern to something looked up from the database. 29 // 30 31 // classifyTablePattern distinguishes between a TableName (last name 32 // part is a table name) and an AllTablesSelector. 33 // Used e.g. for GRANT. 34 func classifyTablePattern(n *UnresolvedName) (TablePattern, error) { 35 if n.NumParts < 1 || n.NumParts > 3 { 36 return nil, newInvTableNameError(n) 37 } 38 // Check that all the parts specified are not empty. 39 firstCheck := 0 40 if n.Star { 41 firstCheck = 1 42 } 43 // It's OK if the catalog name is empty. 44 // We allow this in e.g. `select * from "".crdb_internal.tables`. 45 lastCheck := n.NumParts 46 if lastCheck > 2 { 47 lastCheck = 2 48 } 49 for i := firstCheck; i < lastCheck; i++ { 50 if len(n.Parts[i]) == 0 { 51 return nil, newInvTableNameError(n) 52 } 53 } 54 55 // Construct the result. 56 if n.Star { 57 return &AllTablesSelector{makeObjectNamePrefixFromUnresolvedName(n)}, nil 58 } 59 tb := makeTableNameFromUnresolvedName(n) 60 return &tb, nil 61 } 62 63 // classifyColumnItem distinguishes between a ColumnItem (last name 64 // part is a column name) and an AllColumnsSelector. 65 // 66 // Used e.g. in SELECT clauses. 67 func classifyColumnItem(n *UnresolvedName) (VarName, error) { 68 if n.NumParts < 1 || n.NumParts > 4 { 69 return nil, newInvColRef(n) 70 } 71 72 // Check that all the parts specified are not empty. 73 firstCheck := 0 74 if n.Star { 75 firstCheck = 1 76 } 77 // It's OK if the catalog name is empty. 78 // We allow this in e.g. 79 // `select "".crdb_internal.tables.table_id from "".crdb_internal.tables`. 80 lastCheck := n.NumParts 81 if lastCheck > 3 { 82 lastCheck = 3 83 } 84 for i := firstCheck; i < lastCheck; i++ { 85 if len(n.Parts[i]) == 0 { 86 return nil, newInvColRef(n) 87 } 88 } 89 90 // Construct the result. 91 var tn *UnresolvedObjectName 92 if n.NumParts > 1 { 93 var err error 94 tn, err = NewUnresolvedObjectName( 95 n.NumParts-1, 96 [3]string{n.Parts[1], n.Parts[2], n.Parts[3]}, 97 NoAnnotation, 98 ) 99 if err != nil { 100 return nil, err 101 } 102 } 103 if n.Star { 104 return &AllColumnsSelector{TableName: tn}, nil 105 } 106 return &ColumnItem{TableName: tn, ColumnName: Name(n.Parts[0])}, nil 107 } 108 109 // Resolution algorithms follow. 110 111 // QualifiedNameResolver is the helper interface to resolve qualified 112 // table names given an ID and the required table kind, as well as the 113 // current database to determine whether or not to include the 114 // database in the qualification. 115 type QualifiedNameResolver interface { 116 GetQualifiedTableNameByID(ctx context.Context, id int64, requiredType RequiredTableKind) (*TableName, error) 117 GetQualifiedFunctionNameByID(ctx context.Context, id int64) (*RoutineName, error) 118 CurrentDatabase() string 119 } 120 121 // SearchPath encapsulates the ordered list of schemas in the current database 122 // to search during name resolution. 123 type SearchPath interface { 124 // NumElements returns the number of elements in the SearchPath. 125 NumElements() int 126 127 // GetSchema returns the schema at the ord offset in the SearchPath. 128 // Note that it will return the empty string if the ordinal is out of range. 129 GetSchema(ord int) string 130 } 131 132 // EmptySearchPath is a SearchPath with no members. 133 var EmptySearchPath SearchPath = emptySearchPath{} 134 135 type emptySearchPath struct{} 136 137 func (emptySearchPath) NumElements() int { return 0 } 138 func (emptySearchPath) GetSchema(i int) string { return "" } 139 140 func newInvColRef(n *UnresolvedName) error { 141 return pgerror.NewWithDepthf(1, pgcode.InvalidColumnReference, 142 "invalid column name: %s", n) 143 } 144 145 func newInvTableNameError(n fmt.Stringer) error { 146 return pgerror.NewWithDepthf(1, pgcode.InvalidName, 147 "invalid table name: %s", n) 148 } 149 150 // DesiredObjectKind represents what kind of object is desired in a name 151 // resolution attempt. 152 type DesiredObjectKind byte 153 154 const ( 155 _ DesiredObjectKind = iota 156 // TableObject is used when a table-like object is desired from resolution. 157 TableObject 158 // TypeObject is used when a type-like object is desired from resolution. 159 TypeObject 160 // AnyObject is used when any object is acceptable. This is primary used when 161 // looking for name conflicts. 162 AnyObject 163 ) 164 165 // RequiredTableKind controls what kind of TableDescriptor backed object is 166 // requested to be resolved. 167 type RequiredTableKind byte 168 169 // RequiredTableKind options have descriptive names. 170 const ( 171 ResolveAnyTableKind RequiredTableKind = iota 172 ResolveRequireTableDesc 173 ResolveRequireViewDesc 174 ResolveRequireTableOrViewDesc 175 ResolveRequireSequenceDesc 176 ) 177 178 var requiredTypeNames = [...]string{ 179 ResolveAnyTableKind: "any", 180 ResolveRequireTableDesc: "table", 181 ResolveRequireViewDesc: "view", 182 ResolveRequireTableOrViewDesc: "table or view", 183 ResolveRequireSequenceDesc: "sequence", 184 } 185 186 func (r RequiredTableKind) String() string { 187 return requiredTypeNames[r] 188 } 189 190 // ObjectLookupFlags is the flag struct suitable for GetObjectByName(). 191 type ObjectLookupFlags struct { 192 // Required specifies that the lookup will return an error if the item is 193 // not found. 194 Required bool 195 // RequireMutable specifies whether to return a mutable descriptor. 196 RequireMutable bool 197 // AssertNotLeased, if set, avoid the leased (possibly stale) version of the 198 // descriptor. It must be set when callers want consistent reads. 199 AssertNotLeased bool 200 // IncludeOffline specifies if offline descriptors should be visible. 201 IncludeOffline bool 202 // AllowWithoutPrimaryKey specifies if tables without PKs can be resolved. 203 AllowWithoutPrimaryKey bool 204 // Control what type of object is being requested. 205 DesiredObjectKind DesiredObjectKind 206 // Control what kind of table object is being requested. This field is 207 // only respected when DesiredObjectKind is TableObject. 208 DesiredTableDescKind RequiredTableKind 209 } 210 211 // IndexLookupFlags is the flag struct used for resolver.ResolveIndex() only. 212 type IndexLookupFlags struct { 213 // Required, if true, indicates lookup can return nil index without 214 // returning an error if the index does not exist. 215 Required bool 216 // IncludeNonActiveIndex expands the lookup to also consider 217 // non-active indexes. By default, only active indexes are 218 // considered. 219 IncludeNonActiveIndex bool 220 // IncludeOfflineTable expands the lookup to also consider offline 221 // tables. By default, only online tables are considered. 222 IncludeOfflineTable bool 223 }