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 }