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  }