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  }