github.com/cockroachdb/cockroachdb-parser@v0.23.3-0.20240213214944-911057d40c9a/pkg/sql/lexbase/predicates.go (about)

     1  // Copyright 2017 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 lexbase
    12  
    13  import (
    14  	"unicode"
    15  	"unicode/utf8"
    16  )
    17  
    18  // isASCII returns true if all the characters in s are ASCII.
    19  func isASCII(s string) bool {
    20  	for _, c := range s {
    21  		if c > unicode.MaxASCII {
    22  			return false
    23  		}
    24  	}
    25  	return true
    26  }
    27  
    28  // IsDigit returns true if the character is between 0 and 9.
    29  func IsDigit(ch int) bool {
    30  	return ch >= '0' && ch <= '9'
    31  }
    32  
    33  // IsHexDigit returns true if the character is a valid hexadecimal digit.
    34  func IsHexDigit(ch int) bool {
    35  	return (ch >= '0' && ch <= '9') ||
    36  		(ch >= 'a' && ch <= 'f') ||
    37  		(ch >= 'A' && ch <= 'F')
    38  }
    39  
    40  // reservedOrLookaheadKeywords are the reserved keywords plus those keywords for
    41  // which we need one token of lookahead extra to determine their token type.
    42  var reservedOrLookaheadKeywords = make(map[string]struct{})
    43  
    44  func init() {
    45  	for s := range reservedKeywords {
    46  		reservedOrLookaheadKeywords[s] = struct{}{}
    47  	}
    48  	for _, s := range []string{
    49  		"between",
    50  		"ilike",
    51  		"in",
    52  		"like",
    53  		"of",
    54  		"ordinality",
    55  		"similar",
    56  		"time",
    57  		"generated",
    58  		"reset",
    59  		"role",
    60  		"user",
    61  		"on",
    62  		"tenant",
    63  		"set",
    64  	} {
    65  		reservedOrLookaheadKeywords[s] = struct{}{}
    66  	}
    67  }
    68  
    69  // isReservedKeyword returns true if the keyword is reserved, or needs
    70  // one extra token of lookahead.
    71  func isReservedKeyword(s string) bool {
    72  	_, ok := reservedOrLookaheadKeywords[s]
    73  	return ok
    74  }
    75  
    76  // IsBareIdentifier returns true if the input string is a permissible bare SQL
    77  // identifier.
    78  func IsBareIdentifier(s string) bool {
    79  	if len(s) == 0 || !IsIdentStart(int(s[0])) || (s[0] >= 'A' && s[0] <= 'Z') {
    80  		return false
    81  	}
    82  	// Keep track of whether the input string is all ASCII. If it is, we don't
    83  	// have to bother running the full Normalize() function at the end, which is
    84  	// quite expensive.
    85  	isASCII := s[0] < utf8.RuneSelf
    86  	for i := 1; i < len(s); i++ {
    87  		if !IsIdentMiddle(int(s[i])) {
    88  			return false
    89  		}
    90  		if s[i] >= 'A' && s[i] <= 'Z' {
    91  			// Non-lowercase identifiers aren't permissible.
    92  			return false
    93  		}
    94  		if s[i] >= utf8.RuneSelf {
    95  			isASCII = false
    96  		}
    97  	}
    98  	return isASCII || NormalizeName(s) == s
    99  }
   100  
   101  // IsIdentStart returns true if the character is valid at the start of an identifier.
   102  func IsIdentStart(ch int) bool {
   103  	return (ch >= 'A' && ch <= 'Z') ||
   104  		(ch >= 'a' && ch <= 'z') ||
   105  		(ch >= 128 && ch <= 255) ||
   106  		(ch == '_')
   107  }
   108  
   109  // IsIdentMiddle returns true if the character is valid inside an identifier.
   110  func IsIdentMiddle(ch int) bool {
   111  	return IsIdentStart(ch) || IsDigit(ch) || ch == '$'
   112  }