Files
kubevpn/vendor/github.com/DataDog/go-sqllexer/sqllexer_utils.go
2025-04-19 10:06:56 +08:00

266 lines
5.6 KiB
Go

package sqllexer
import (
"strings"
"unicode"
)
type DBMSType string
const (
// DBMSSQLServer is a MS SQL
DBMSSQLServer DBMSType = "mssql"
// DBMSPostgres is a PostgreSQL Server
DBMSPostgres DBMSType = "postgresql"
// DBMSMySQL is a MySQL Server
DBMSMySQL DBMSType = "mysql"
// DBMSOracle is a Oracle Server
DBMSOracle DBMSType = "oracle"
// DBMSSnowflake is a Snowflake Server
DBMSSnowflake DBMSType = "snowflake"
)
var commands = map[string]bool{
"SELECT": true,
"INSERT": true,
"UPDATE": true,
"DELETE": true,
"CREATE": true,
"ALTER": true,
"DROP": true,
"JOIN": true,
"GRANT": true,
"REVOKE": true,
"COMMIT": true,
"BEGIN": true,
"TRUNCATE": true,
"MERGE": true,
"EXECUTE": true,
"EXEC": true,
"EXPLAIN": true,
"STRAIGHT_JOIN": true,
"USE": true,
"CLONE": true,
}
var tableIndicators = map[string]bool{
"FROM": true,
"JOIN": true,
"INTO": true,
"UPDATE": true,
"TABLE": true,
"EXISTS": true, // Drop Table If Exists
"STRAIGHT_JOIN": true, // MySQL
"CLONE": true, // Snowflake
"ONLY": true, // PostgreSQL
}
var keywords = map[string]bool{
"SELECT": true,
"INSERT": true,
"UPDATE": true,
"DELETE": true,
"CREATE": true,
"ALTER": true,
"DROP": true,
"GRANT": true,
"REVOKE": true,
"ADD": true,
"ALL": true,
"AND": true,
"ANY": true,
"AS": true,
"ASC": true,
"BEGIN": true,
"BETWEEN": true,
"BY": true,
"CASE": true,
"CHECK": true,
"COLUMN": true,
"COMMIT": true,
"CONSTRAINT": true,
"DATABASE": true,
"DECLARE": true,
"DEFAULT": true,
"DESC": true,
"DISTINCT": true,
"ELSE": true,
"END": true,
"EXEC": true,
"EXISTS": true,
"FOREIGN": true,
"FROM": true,
"GROUP": true,
"HAVING": true,
"IN": true,
"INDEX": true,
"INNER": true,
"INTO": true,
"IS": true,
"JOIN": true,
"KEY": true,
"LEFT": true,
"LIKE": true,
"LIMIT": true,
"NOT": true,
"ON": true,
"OR": true,
"ORDER": true,
"OUTER": true,
"PRIMARY": true,
"PROCEDURE": true,
"REPLACE": true,
"RETURNS": true,
"RIGHT": true,
"ROLLBACK": true,
"ROWNUM": true,
"SET": true,
"SOME": true,
"TABLE": true,
"TOP": true,
"TRUNCATE": true,
"UNION": true,
"UNIQUE": true,
"USE": true,
"VALUES": true,
"VIEW": true,
"WHERE": true,
"CUBE": true,
"ROLLUP": true,
"LITERAL": true,
"WINDOW": true,
"VACCUM": true,
"ANALYZE": true,
"ILIKE": true,
"USING": true,
"ASSERTION": true,
"DOMAIN": true,
"CLUSTER": true,
"COPY": true,
"EXPLAIN": true,
"PLPGSQL": true,
"TRIGGER": true,
"TEMPORARY": true,
"UNLOGGED": true,
"RECURSIVE": true,
"RETURNING": true,
"OFFSET": true,
"OF": true,
"SKIP": true,
"IF": true,
"ONLY": true,
}
func isWhitespace(ch rune) bool {
return ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r'
}
func isDigit(ch rune) bool {
return '0' <= ch && ch <= '9'
}
func isExpontent(ch rune) bool {
return ch == 'e' || ch == 'E'
}
func isLeadingSign(ch rune) bool {
return ch == '+' || ch == '-'
}
func isLetter(ch rune) bool {
return unicode.IsLetter(ch) || ch == '_'
}
func isAlphaNumeric(ch rune) bool {
return isLetter(ch) || isDigit(ch)
}
func isDoubleQuote(ch rune) bool {
return ch == '"'
}
func isSingleQuote(ch rune) bool {
return ch == '\''
}
func isOperator(ch rune) bool {
return ch == '+' || ch == '-' || ch == '*' || ch == '/' || ch == '=' || ch == '<' || ch == '>' || ch == '!' || ch == '&' || ch == '|' || ch == '^' || ch == '%' || ch == '~' || ch == '?' || ch == '@' || ch == ':' || ch == '#'
}
func isWildcard(ch rune) bool {
return ch == '*'
}
func isSingleLineComment(ch rune, nextCh rune) bool {
return ch == '-' && nextCh == '-'
}
func isMultiLineComment(ch rune, nextCh rune) bool {
return ch == '/' && nextCh == '*'
}
func isPunctuation(ch rune) bool {
return ch == '(' || ch == ')' || ch == ',' || ch == ';' || ch == '.' || ch == ':' || ch == '[' || ch == ']' || ch == '{' || ch == '}'
}
func isEOF(ch rune) bool {
return ch == 0
}
func isCommand(ident string) bool {
_, ok := commands[ident]
return ok
}
func isTableIndicator(ident string) bool {
_, ok := tableIndicators[ident]
return ok
}
func isSQLKeyword(token *Token) bool {
if token.Type != IDENT {
return false
}
_, ok := keywords[strings.ToUpper(token.Value)]
return ok
}
func isProcedure(token *Token) bool {
if token.Type != IDENT {
return false
}
return strings.ToUpper(token.Value) == "PROCEDURE" || strings.ToUpper(token.Value) == "PROC"
}
func isBoolean(ident string) bool {
return strings.ToUpper(ident) == "TRUE" || strings.ToUpper(ident) == "FALSE"
}
func isNull(ident string) bool {
return strings.ToUpper(ident) == "NULL"
}
func replaceDigits(input string, placeholder string) string {
var builder strings.Builder
i := 0
for i < len(input) {
if isDigit(rune(input[i])) {
builder.WriteString(placeholder)
for i < len(input) && isDigit(rune(input[i])) {
i++
}
} else {
builder.WriteByte(input[i])
i++
}
}
return builder.String()
}
func trimQuotes(input string, delim string, closingDelim string) string {
replacer := strings.NewReplacer(delim, "", closingDelim, "")
return replacer.Replace(input)
}