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  }