github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/sql/lex/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 lex
    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  	} {
    59  		reservedOrLookaheadKeywords[s] = struct{}{}
    60  	}
    61  }
    62  
    63  // isReservedKeyword returns true if the keyword is reserved, or needs
    64  // one extra token of lookahead.
    65  func isReservedKeyword(s string) bool {
    66  	_, ok := reservedOrLookaheadKeywords[s]
    67  	return ok
    68  }
    69  
    70  // isBareIdentifier returns true if the input string is a permissible bare SQL
    71  // identifier.
    72  func isBareIdentifier(s string) bool {
    73  	if len(s) == 0 || !IsIdentStart(int(s[0])) || (s[0] >= 'A' && s[0] <= 'Z') {
    74  		return false
    75  	}
    76  	// Keep track of whether the input string is all ASCII. If it is, we don't
    77  	// have to bother running the full Normalize() function at the end, which is
    78  	// quite expensive.
    79  	isASCII := s[0] < utf8.RuneSelf
    80  	for i := 1; i < len(s); i++ {
    81  		if !IsIdentMiddle(int(s[i])) {
    82  			return false
    83  		}
    84  		if s[i] >= 'A' && s[i] <= 'Z' {
    85  			// Non-lowercase identifiers aren't permissible.
    86  			return false
    87  		}
    88  		if s[i] >= utf8.RuneSelf {
    89  			isASCII = false
    90  		}
    91  	}
    92  	return isASCII || NormalizeName(s) == s
    93  }
    94  
    95  // IsIdentStart returns true if the character is valid at the start of an identifier.
    96  func IsIdentStart(ch int) bool {
    97  	return (ch >= 'A' && ch <= 'Z') ||
    98  		(ch >= 'a' && ch <= 'z') ||
    99  		(ch >= 128 && ch <= 255) ||
   100  		(ch == '_')
   101  }
   102  
   103  // IsIdentMiddle returns true if the character is valid inside an identifier.
   104  func IsIdentMiddle(ch int) bool {
   105  	return IsIdentStart(ch) || IsDigit(ch) || ch == '$'
   106  }