Edit on GitHub

sqlglot.dialects.athena

  1from __future__ import annotations
  2
  3
  4from sqlglot import tokens
  5from sqlglot.dialects.dialect import DialectType
  6from sqlglot.errors import TokenError
  7from sqlglot.generators.athena import AthenaGenerator
  8from sqlglot.parsers.athena import AthenaParser
  9from sqlglot.tokens import TokenType, Token
 10from sqlglot.dialects.trino import Trino
 11from sqlglot.dialects.hive import Hive
 12
 13
 14class Athena(Trino):
 15    """
 16    Over the years, it looks like AWS has taken various execution engines, bolted on AWS-specific
 17    modifications and then built the Athena service around them.
 18
 19    Thus, Athena is not simply hosted Trino, it's more like a router that routes SQL queries to an
 20    execution engine depending on the query type.
 21
 22    As at 2024-09-10, assuming your Athena workgroup is configured to use "Athena engine version 3",
 23    the following engines exist:
 24
 25    Hive:
 26     - Accepts mostly the same syntax as Hadoop / Hive
 27     - Uses backticks to quote identifiers
 28     - Has a distinctive DDL syntax (around things like setting table properties, storage locations etc)
 29       that is different from Trino
 30     - Used for *most* DDL, with some exceptions that get routed to the Trino engine instead:
 31        - CREATE [EXTERNAL] TABLE (without AS SELECT)
 32        - ALTER
 33        - DROP
 34
 35    Trino:
 36      - Uses double quotes to quote identifiers
 37      - Used for DDL operations that involve SELECT queries, eg:
 38        - CREATE VIEW / DROP VIEW
 39        - CREATE TABLE... AS SELECT
 40      - Used for DML operations
 41        - SELECT, INSERT, UPDATE, DELETE, MERGE
 42
 43    The SQLGlot Athena dialect tries to identify which engine a query would be routed to and then uses the
 44    tokenizer / parser / generator for that engine. This is unfortunately necessary, as there are certain
 45    incompatibilities between the engines' dialects and thus can't be handled by a single, unifying dialect.
 46
 47    References:
 48    - https://docs.aws.amazon.com/athena/latest/ug/ddl-reference.html
 49    - https://docs.aws.amazon.com/athena/latest/ug/dml-queries-functions-operators.html
 50    """
 51
 52    # This Tokenizer consumes a combination of HiveQL and Trino SQL and then processes the tokens
 53    # to disambiguate which dialect needs to be actually used in order to tokenize correctly.
 54    class Tokenizer(tokens.Tokenizer):
 55        IDENTIFIERS = Trino.Tokenizer.IDENTIFIERS + Hive.Tokenizer.IDENTIFIERS
 56        STRING_ESCAPES = Trino.Tokenizer.STRING_ESCAPES + Hive.Tokenizer.STRING_ESCAPES
 57        HEX_STRINGS = Trino.Tokenizer.HEX_STRINGS + Hive.Tokenizer.HEX_STRINGS
 58        UNICODE_STRINGS = Trino.Tokenizer.UNICODE_STRINGS + Hive.Tokenizer.UNICODE_STRINGS
 59
 60        NUMERIC_LITERALS = {
 61            **Trino.Tokenizer.NUMERIC_LITERALS,
 62            **Hive.Tokenizer.NUMERIC_LITERALS,
 63        }
 64
 65        KEYWORDS = {
 66            **Hive.Tokenizer.KEYWORDS,
 67            **Trino.Tokenizer.KEYWORDS,
 68            "UNLOAD": TokenType.COMMAND,
 69        }
 70
 71        def __init__(self, dialect: DialectType = None) -> None:
 72            super().__init__(dialect=dialect)
 73
 74            self._hive_tokenizer = Hive().tokenizer()
 75            self._trino_tokenizer = _TrinoTokenizer(Trino())
 76
 77        def tokenize(self, sql: str) -> list[Token]:
 78            # DML only needs Trino's tokenizer; possible Hive statements need disambiguation.
 79            try:
 80                trino_tokens: list[Token] | None = self._trino_tokenizer.tokenize(sql)
 81            except TokenError:
 82                trino_tokens = None
 83
 84            if trino_tokens is not None and not _may_be_hive(trino_tokens):
 85                return trino_tokens
 86
 87            try:
 88                tokens = super().tokenize(sql)
 89            except TokenError:
 90                # Combined rules can reject literals valid in only one engine.
 91                if trino_tokens is not None and not _tokenize_as_hive(trino_tokens):
 92                    return trino_tokens
 93
 94                try:
 95                    tokens = self._hive_tokenizer.tokenize(sql)
 96                except TokenError:
 97                    pass
 98                else:
 99                    if _tokenize_as_hive(tokens):
100                        return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + tokens
101                raise
102
103            if _tokenize_as_hive(tokens):
104                return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + self._hive_tokenizer.tokenize(sql)
105
106            return trino_tokens if trino_tokens is not None else self._trino_tokenizer.tokenize(sql)
107
108    Parser = AthenaParser
109
110    Generator = AthenaGenerator
111
112
113_MAYBE_HIVE_TOKENS = {
114    TokenType.ALTER,
115    TokenType.CREATE,
116    TokenType.DESCRIBE,
117    TokenType.DROP,
118    TokenType.SHOW,
119}
120
121
122def _may_be_hive(tokens: list[Token]) -> bool:
123    return bool(tokens) and (
124        tokens[0].token_type in _MAYBE_HIVE_TOKENS or tokens[0].text.upper() == "MSCK"
125    )
126
127
128def _tokenize_as_hive(tokens: list[Token]) -> bool:
129    if len(tokens) < 2:
130        return False
131
132    first, second, *rest = tokens
133
134    first_type = first.token_type
135    first_text = first.text.upper()
136    second_type = second.token_type
137    second_text = second.text.upper()
138
139    if first_type in (TokenType.DESCRIBE, TokenType.SHOW) or first_text == "MSCK REPAIR":
140        return True
141
142    if first_type in (TokenType.ALTER, TokenType.CREATE, TokenType.DROP):
143        if second_text in ("DATABASE", "EXTERNAL", "SCHEMA"):
144            return True
145        if second_type == TokenType.VIEW:
146            return False
147
148        return all(t.token_type != TokenType.SELECT for t in rest)
149
150    return False
151
152
153# Athena extensions to Trino's tokenizer
154class _TrinoTokenizer(Trino.Tokenizer):
155    KEYWORDS = {
156        **Trino.Tokenizer.KEYWORDS,
157        "UNLOAD": TokenType.COMMAND,
158    }
class Athena(sqlglot.dialects.trino.Trino):
 15class Athena(Trino):
 16    """
 17    Over the years, it looks like AWS has taken various execution engines, bolted on AWS-specific
 18    modifications and then built the Athena service around them.
 19
 20    Thus, Athena is not simply hosted Trino, it's more like a router that routes SQL queries to an
 21    execution engine depending on the query type.
 22
 23    As at 2024-09-10, assuming your Athena workgroup is configured to use "Athena engine version 3",
 24    the following engines exist:
 25
 26    Hive:
 27     - Accepts mostly the same syntax as Hadoop / Hive
 28     - Uses backticks to quote identifiers
 29     - Has a distinctive DDL syntax (around things like setting table properties, storage locations etc)
 30       that is different from Trino
 31     - Used for *most* DDL, with some exceptions that get routed to the Trino engine instead:
 32        - CREATE [EXTERNAL] TABLE (without AS SELECT)
 33        - ALTER
 34        - DROP
 35
 36    Trino:
 37      - Uses double quotes to quote identifiers
 38      - Used for DDL operations that involve SELECT queries, eg:
 39        - CREATE VIEW / DROP VIEW
 40        - CREATE TABLE... AS SELECT
 41      - Used for DML operations
 42        - SELECT, INSERT, UPDATE, DELETE, MERGE
 43
 44    The SQLGlot Athena dialect tries to identify which engine a query would be routed to and then uses the
 45    tokenizer / parser / generator for that engine. This is unfortunately necessary, as there are certain
 46    incompatibilities between the engines' dialects and thus can't be handled by a single, unifying dialect.
 47
 48    References:
 49    - https://docs.aws.amazon.com/athena/latest/ug/ddl-reference.html
 50    - https://docs.aws.amazon.com/athena/latest/ug/dml-queries-functions-operators.html
 51    """
 52
 53    # This Tokenizer consumes a combination of HiveQL and Trino SQL and then processes the tokens
 54    # to disambiguate which dialect needs to be actually used in order to tokenize correctly.
 55    class Tokenizer(tokens.Tokenizer):
 56        IDENTIFIERS = Trino.Tokenizer.IDENTIFIERS + Hive.Tokenizer.IDENTIFIERS
 57        STRING_ESCAPES = Trino.Tokenizer.STRING_ESCAPES + Hive.Tokenizer.STRING_ESCAPES
 58        HEX_STRINGS = Trino.Tokenizer.HEX_STRINGS + Hive.Tokenizer.HEX_STRINGS
 59        UNICODE_STRINGS = Trino.Tokenizer.UNICODE_STRINGS + Hive.Tokenizer.UNICODE_STRINGS
 60
 61        NUMERIC_LITERALS = {
 62            **Trino.Tokenizer.NUMERIC_LITERALS,
 63            **Hive.Tokenizer.NUMERIC_LITERALS,
 64        }
 65
 66        KEYWORDS = {
 67            **Hive.Tokenizer.KEYWORDS,
 68            **Trino.Tokenizer.KEYWORDS,
 69            "UNLOAD": TokenType.COMMAND,
 70        }
 71
 72        def __init__(self, dialect: DialectType = None) -> None:
 73            super().__init__(dialect=dialect)
 74
 75            self._hive_tokenizer = Hive().tokenizer()
 76            self._trino_tokenizer = _TrinoTokenizer(Trino())
 77
 78        def tokenize(self, sql: str) -> list[Token]:
 79            # DML only needs Trino's tokenizer; possible Hive statements need disambiguation.
 80            try:
 81                trino_tokens: list[Token] | None = self._trino_tokenizer.tokenize(sql)
 82            except TokenError:
 83                trino_tokens = None
 84
 85            if trino_tokens is not None and not _may_be_hive(trino_tokens):
 86                return trino_tokens
 87
 88            try:
 89                tokens = super().tokenize(sql)
 90            except TokenError:
 91                # Combined rules can reject literals valid in only one engine.
 92                if trino_tokens is not None and not _tokenize_as_hive(trino_tokens):
 93                    return trino_tokens
 94
 95                try:
 96                    tokens = self._hive_tokenizer.tokenize(sql)
 97                except TokenError:
 98                    pass
 99                else:
100                    if _tokenize_as_hive(tokens):
101                        return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + tokens
102                raise
103
104            if _tokenize_as_hive(tokens):
105                return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + self._hive_tokenizer.tokenize(sql)
106
107            return trino_tokens if trino_tokens is not None else self._trino_tokenizer.tokenize(sql)
108
109    Parser = AthenaParser
110
111    Generator = AthenaGenerator

Over the years, it looks like AWS has taken various execution engines, bolted on AWS-specific modifications and then built the Athena service around them.

Thus, Athena is not simply hosted Trino, it's more like a router that routes SQL queries to an execution engine depending on the query type.

As at 2024-09-10, assuming your Athena workgroup is configured to use "Athena engine version 3", the following engines exist:

Hive:
  • Accepts mostly the same syntax as Hadoop / Hive
  • Uses backticks to quote identifiers
  • Has a distinctive DDL syntax (around things like setting table properties, storage locations etc) that is different from Trino
  • Used for most DDL, with some exceptions that get routed to the Trino engine instead:
    • CREATE [EXTERNAL] TABLE (without AS SELECT)
    • ALTER
    • DROP
Trino:
  • Uses double quotes to quote identifiers
  • Used for DDL operations that involve SELECT queries, eg:
    • CREATE VIEW / DROP VIEW
    • CREATE TABLE... AS SELECT
  • Used for DML operations
    • SELECT, INSERT, UPDATE, DELETE, MERGE

The SQLGlot Athena dialect tries to identify which engine a query would be routed to and then uses the tokenizer / parser / generator for that engine. This is unfortunately necessary, as there are certain incompatibilities between the engines' dialects and thus can't be handled by a single, unifying dialect.

References:

SUPPORTS_COLUMN_JOIN_MARKS = False

Whether the old-style outer join (+) syntax is supported.

UNESCAPED_SEQUENCES: dict[str, str] = {'\\a': '\x07', '\\b': '\x08', '\\f': '\x0c', '\\n': '\n', '\\r': '\r', '\\t': '\t', '\\v': '\x0b', '\\\\': '\\'}

Mapping of an escaped sequence (\n) to its unescaped version ( ).

STRINGS_SUPPORT_ESCAPED_SEQUENCES: bool = True

Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.

BYTE_STRINGS_SUPPORT_ESCAPED_SEQUENCES: bool = True

Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.

IDENTIFIER_ESCAPED_SEQUENCES: dict[str, str] = {}

Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.

INITCAP_SUPPORTS_CUSTOM_DELIMITERS = False
tokenizer_class = <class 'Athena.Tokenizer'>
jsonpath_tokenizer_class = <class 'sqlglot.dialects.dialect.JSONPathTokenizer'>
parser_class = <class 'sqlglot.parsers.athena.AthenaParser'>
generator_class = <class 'sqlglot.generators.athena.AthenaGenerator'>
TIME_TRIE: dict = {'%': {'M': {0: True}, 'c': {0: True}, 'e': {0: True}, 'h': {0: True}, 'i': {0: True}, 's': {0: True}, 'u': {0: True}, 'k': {0: True}, 'l': {0: True}, 'r': {0: True}, 'T': {0: True}, 'W': {0: True}, 'x': {0: True}}}
FORMAT_TRIE: dict = {'%': {'M': {0: True}, 'c': {0: True}, 'e': {0: True}, 'h': {0: True}, 'i': {0: True}, 's': {0: True}, 'u': {0: True}, 'k': {0: True}, 'l': {0: True}, 'r': {0: True}, 'T': {0: True}, 'W': {0: True}, 'x': {0: True}}}
INVERSE_TIME_MAPPING: dict[str, str] = {'%B': '%M', '%-m': '%c', '%-d': '%e', '%I': '%h', '%M': '%i', '%S': '%s', '%W': '%u', '%-H': '%k', '%-I': '%l', '%I:%M:%S %p': '%r', '%H:%M:%S': '%T', '%A': '%W', '%G': '%x', '%mstrict': '%m', '%dstrict': '%d', '%Hstrict': '%H', '%Istrict': '%h', '%Mstrict': '%i', '%Sstrict': '%s'}
INVERSE_TIME_TRIE: dict = {'%': {'B': {0: True}, '-': {'m': {0: True}, 'd': {0: True}, 'H': {0: True}, 'I': {0: True}}, 'I': {0: True, ':': {'%': {'M': {':': {'%': {'S': {' ': {'%': {'p': {0: True}}}}}}}}}, 's': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'M': {0: True, 's': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'S': {0: True, 's': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'W': {0: True}, 'H': {':': {'%': {'M': {':': {'%': {'S': {0: True}}}}}}, 's': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'A': {0: True}, 'G': {0: True}, 'm': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'd': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}}}
INVERSE_FORMAT_MAPPING: dict[str, str] = {'%mstrict': '%m', '%dstrict': '%d', '%Hstrict': '%H', '%Istrict': '%I', '%Mstrict': '%M', '%Sstrict': '%S'}
INVERSE_FORMAT_TRIE: dict = {'%': {'m': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'd': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'H': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'I': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'M': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}, 'S': {'s': {'t': {'r': {'i': {'c': {'t': {0: True}}}}}}}}}
INVERSE_CREATABLE_KIND_MAPPING: dict[str, str] = {}
ESCAPED_SEQUENCES: dict[str, str] = {'\x07': '\\a', '\x08': '\\b', '\x0c': '\\f', '\n': '\\n', '\r': '\\r', '\t': '\\t', '\x0b': '\\v', '\\': '\\\\'}
QUOTE_START = "'"
QUOTE_END = "'"
IDENTIFIER_START = '"'
IDENTIFIER_END = '"'
VALID_INTERVAL_UNITS: set[str] = {'QUARTER', 'D', 'QTR', 'MILLISEC', 'DD', 'WEEKDAY', 'DAYS', 'WEEKISO', 'MONS', 'TZM', 'NS', 'DEC', 'NANOSEC', 'YYY', 'QUARTERS', 'CENTS', 'EPOCH_NANOSECOND', 'MON', 'TIMEZONE_HOUR', 'MONTH', 'HOURS', 'NSEC', 'MSECS', 'MILLENNIUM', 'WOY', 'MILLISECOND', 'EPOCH_MICROSECONDS', 'DAYOFWEEKISO', 'WY', 'WEEKOFYEAR', 'MI', 'H', 'DW_ISO', 'M', 'Y', 'DOY', 'C', 'DAYOFWEEK', 'DAY OF WEEK', 'YYYY', 'USEC', 'TIMEZONE_MINUTE', 'YY', 'WEEKOFYEAR_ISO', 'HRS', 'MINUTES', 'DECS', 'NSECOND', 'MILLENIA', 'MILS', 'DOW_ISO', 'USECONDS', 'MSEC', 'DECADE', 'MICROSEC', 'MINUTE', 'MICROSECS', 'MILLISECONDS', 'YEAR', 'YR', 'NANOSECS', 'CENTURIES', 'CENTURY', 'WK', 'DW', 'YRS', 'DECADES', 'US', 'HH', 'DAY', 'EPOCH_MILLISECOND', 'MIL', 'YEARS', 'DAYOFMONTH', 'WEEKOFYEARISO', 'S', 'WEEK', 'SECS', 'EPOCH', 'MS', 'USECOND', 'QTRS', 'MILLISECON', 'SECOND', 'MINS', 'MSECONDS', 'DAYOFWEEK_ISO', 'SEC', 'MSECOND', 'NSECONDS', 'EPOCH_NANOSECONDS', 'W', 'MM', 'EPOCH_MICROSECOND', 'EPOCH_SECONDS', 'EPOCH_SECOND', 'EPOCH_MILLISECONDS', 'MONTHS', 'SECONDS', 'DAY OF YEAR', 'MILLISECS', 'Q', 'HR', 'DOW', 'MICROSECOND', 'WEEKDAY_ISO', 'HOUR', 'USECS', 'MIN', 'WEEK_ISO', 'MICROSECONDS', 'DAYOFYEAR', 'NANOSECOND', 'TZH', 'CENT', 'DY'}
BIT_START: str | None = None
BIT_END: str | None = None
HEX_START: str | None = "x'"
HEX_END: str | None = "'"
BYTE_START: str | None = None
BYTE_END: str | None = None
UNICODE_START: str | None = "U&'"
UNICODE_END: str | None = "'"
class Athena.Tokenizer(sqlglot.tokens.Tokenizer):
 55    class Tokenizer(tokens.Tokenizer):
 56        IDENTIFIERS = Trino.Tokenizer.IDENTIFIERS + Hive.Tokenizer.IDENTIFIERS
 57        STRING_ESCAPES = Trino.Tokenizer.STRING_ESCAPES + Hive.Tokenizer.STRING_ESCAPES
 58        HEX_STRINGS = Trino.Tokenizer.HEX_STRINGS + Hive.Tokenizer.HEX_STRINGS
 59        UNICODE_STRINGS = Trino.Tokenizer.UNICODE_STRINGS + Hive.Tokenizer.UNICODE_STRINGS
 60
 61        NUMERIC_LITERALS = {
 62            **Trino.Tokenizer.NUMERIC_LITERALS,
 63            **Hive.Tokenizer.NUMERIC_LITERALS,
 64        }
 65
 66        KEYWORDS = {
 67            **Hive.Tokenizer.KEYWORDS,
 68            **Trino.Tokenizer.KEYWORDS,
 69            "UNLOAD": TokenType.COMMAND,
 70        }
 71
 72        def __init__(self, dialect: DialectType = None) -> None:
 73            super().__init__(dialect=dialect)
 74
 75            self._hive_tokenizer = Hive().tokenizer()
 76            self._trino_tokenizer = _TrinoTokenizer(Trino())
 77
 78        def tokenize(self, sql: str) -> list[Token]:
 79            # DML only needs Trino's tokenizer; possible Hive statements need disambiguation.
 80            try:
 81                trino_tokens: list[Token] | None = self._trino_tokenizer.tokenize(sql)
 82            except TokenError:
 83                trino_tokens = None
 84
 85            if trino_tokens is not None and not _may_be_hive(trino_tokens):
 86                return trino_tokens
 87
 88            try:
 89                tokens = super().tokenize(sql)
 90            except TokenError:
 91                # Combined rules can reject literals valid in only one engine.
 92                if trino_tokens is not None and not _tokenize_as_hive(trino_tokens):
 93                    return trino_tokens
 94
 95                try:
 96                    tokens = self._hive_tokenizer.tokenize(sql)
 97                except TokenError:
 98                    pass
 99                else:
100                    if _tokenize_as_hive(tokens):
101                        return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + tokens
102                raise
103
104            if _tokenize_as_hive(tokens):
105                return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + self._hive_tokenizer.tokenize(sql)
106
107            return trino_tokens if trino_tokens is not None else self._trino_tokenizer.tokenize(sql)
Athena.Tokenizer( dialect: Union[str, sqlglot.dialects.Dialect, type[sqlglot.dialects.Dialect], NoneType] = None)
72        def __init__(self, dialect: DialectType = None) -> None:
73            super().__init__(dialect=dialect)
74
75            self._hive_tokenizer = Hive().tokenizer()
76            self._trino_tokenizer = _TrinoTokenizer(Trino())
IDENTIFIERS = ['"', '`']
STRING_ESCAPES = ["'", '\\']
HEX_STRINGS = [("x'", "'"), ("X'", "'")]
UNICODE_STRINGS = [("U&'", "'"), ("u&'", "'")]
NUMERIC_LITERALS = {'L': 'BIGINT', 'S': 'SMALLINT', 'Y': 'TINYINT', 'D': 'DOUBLE', 'F': 'FLOAT', 'BD': 'DECIMAL'}
KEYWORDS = {'{%': <TokenType.BLOCK_START: 73>, '{%+': <TokenType.BLOCK_START: 73>, '{%-': <TokenType.BLOCK_START: 73>, '%}': <TokenType.BLOCK_END: 74>, '+%}': <TokenType.BLOCK_END: 74>, '-%}': <TokenType.BLOCK_END: 74>, '{{+': <TokenType.BLOCK_START: 73>, '{{-': <TokenType.BLOCK_START: 73>, '+}}': <TokenType.BLOCK_END: 74>, '-}}': <TokenType.BLOCK_END: 74>, '/*+': <TokenType.HINT: 297>, '&<': <TokenType.AMP_LT: 63>, '&>': <TokenType.AMP_GT: 64>, '==': <TokenType.EQ: 28>, '::': <TokenType.DCOLON: 14>, '?::': <TokenType.QDCOLON: 375>, '||': <TokenType.DPIPE: 37>, '|>': <TokenType.PIPE_GT: 38>, '>=': <TokenType.GTE: 26>, '<=': <TokenType.LTE: 24>, '<>': <TokenType.NEQ: 29>, '!=': <TokenType.NEQ: 29>, ':=': <TokenType.COLON_EQ: 31>, '<=>': <TokenType.NULLSAFE_EQ: 30>, '->': <TokenType.ARROW: 45>, '->>': <TokenType.DARROW: 46>, '=>': <TokenType.FARROW: 47>, '#>': <TokenType.HASH_ARROW: 49>, '#>>': <TokenType.DHASH_ARROW: 50>, '<->': <TokenType.LR_ARROW: 51>, '<<->>': <TokenType.LLRR_ARROW: 52>, '&&': <TokenType.DAMP: 62>, '??': <TokenType.DQMARK: 18>, '~~~': <TokenType.GLOB: 291>, '~~': <TokenType.LIKE: 322>, '~~*': <TokenType.ILIKE: 299>, '~*': <TokenType.IRLIKE: 311>, '-|-': <TokenType.ADJACENT: 65>, 'ALL': <TokenType.ALL: 222>, 'AND': <TokenType.AND: 34>, 'ANTI': <TokenType.ANTI: 223>, 'ANY': <TokenType.ANY: 224>, 'ASC': <TokenType.ASC: 227>, 'AS': <TokenType.ALIAS: 220>, 'ASOF': <TokenType.ASOF: 228>, 'AUTOINCREMENT': <TokenType.AUTO_INCREMENT: 230>, 'AUTO_INCREMENT': <TokenType.AUTO_INCREMENT: 230>, 'BEGIN': <TokenType.BEGIN: 231>, 'BETWEEN': <TokenType.BETWEEN: 232>, 'CACHE': <TokenType.CACHE: 234>, 'UNCACHE': <TokenType.UNCACHE: 419>, 'CASE': <TokenType.CASE: 235>, 'CLUSTER BY': <TokenType.CLUSTER_BY: 237>, 'COLLATE': <TokenType.COLLATE: 238>, 'COLUMN': <TokenType.COLUMN: 81>, 'COMMIT': <TokenType.COMMIT: 241>, 'CONNECT BY': <TokenType.CONNECT_BY: 243>, 'CONSTRAINT': <TokenType.CONSTRAINT: 244>, 'COPY': <TokenType.COPY: 245>, 'CREATE': <TokenType.CREATE: 246>, 'CROSS': <TokenType.CROSS: 247>, 'CUBE': <TokenType.CUBE: 248>, 'CURRENT_DATE': <TokenType.CURRENT_DATE: 249>, 'CURRENT_SCHEMA': <TokenType.CURRENT_SCHEMA: 251>, 'CURRENT_TIME': <TokenType.CURRENT_TIME: 252>, 'CURRENT_TIMESTAMP': <TokenType.CURRENT_TIMESTAMP: 253>, 'CURRENT_USER': <TokenType.CURRENT_USER: 254>, 'CURRENT_CATALOG': <TokenType.CURRENT_CATALOG: 257>, 'DATABASE': <TokenType.DATABASE: 80>, 'DEFAULT': <TokenType.DEFAULT: 259>, 'DELETE': <TokenType.DELETE: 260>, 'DESC': <TokenType.DESC: 261>, 'DESCRIBE': <TokenType.DESCRIBE: 262>, 'DISTINCT': <TokenType.DISTINCT: 266>, 'DISTRIBUTE BY': <TokenType.DISTRIBUTE_BY: 267>, 'DIV': <TokenType.DIV: 268>, 'DROP': <TokenType.DROP: 269>, 'ELSE': <TokenType.ELSE: 270>, 'END': <TokenType.END: 271>, 'ENUM': <TokenType.ENUM: 207>, 'ESCAPE': <TokenType.ESCAPE: 272>, 'EXCEPT': <TokenType.EXCEPT: 273>, 'EXECUTE': <TokenType.EXECUTE: 274>, 'EXISTS': <TokenType.EXISTS: 275>, 'FALSE': <TokenType.FALSE: 276>, 'FETCH': <TokenType.FETCH: 277>, 'FILTER': <TokenType.FILTER: 280>, 'FILE': <TokenType.FILE: 278>, 'FIRST': <TokenType.FIRST: 282>, 'FULL': <TokenType.FULL: 288>, 'FUNCTION': <TokenType.FUNCTION: 289>, 'FOR': <TokenType.FOR: 283>, 'FOREIGN KEY': <TokenType.FOREIGN_KEY: 285>, 'FORMAT': <TokenType.FORMAT: 286>, 'FROM': <TokenType.FROM: 287>, 'GEOGRAPHY': <TokenType.GEOGRAPHY: 173>, 'GEOMETRY': <TokenType.GEOMETRY: 176>, 'GLOB': <TokenType.GLOB: 291>, 'GROUP BY': <TokenType.GROUP_BY: 294>, 'GROUPING SETS': <TokenType.GROUPING_SETS: 295>, 'HAVING': <TokenType.HAVING: 296>, 'ILIKE': <TokenType.ILIKE: 299>, 'IN': <TokenType.IN: 300>, 'INDEX': <TokenType.INDEX: 301>, 'INET': <TokenType.INET: 202>, 'INNER': <TokenType.INNER: 303>, 'INSERT': <TokenType.INSERT: 304>, 'INTERVAL': <TokenType.INTERVAL: 308>, 'INTERSECT': <TokenType.INTERSECT: 307>, 'INTO': <TokenType.INTO: 309>, 'IS': <TokenType.IS: 312>, 'ISNULL': <TokenType.ISNULL: 313>, 'JOIN': <TokenType.JOIN: 314>, 'KEEP': <TokenType.KEEP: 316>, 'KILL': <TokenType.KILL: 318>, 'LATERAL': <TokenType.LATERAL: 320>, 'LEFT': <TokenType.LEFT: 321>, 'LIKE': <TokenType.LIKE: 322>, 'LIMIT': <TokenType.LIMIT: 323>, 'LOAD': <TokenType.LOAD: 325>, 'LOCALTIME': <TokenType.LOCALTIME: 180>, 'LOCALTIMESTAMP': <TokenType.LOCALTIMESTAMP: 181>, 'LOCK': <TokenType.LOCK: 326>, 'MERGE': <TokenType.MERGE: 332>, 'NAMESPACE': <TokenType.NAMESPACE: 445>, 'NATURAL': <TokenType.NATURAL: 335>, 'NEXT': <TokenType.NEXT: 336>, 'NOT': <TokenType.NOT: 27>, 'NOTNULL': <TokenType.NOTNULL: 338>, 'NULL': <TokenType.NULL: 339>, 'OBJECT': <TokenType.OBJECT: 200>, 'REF': <TokenType.REF: 201>, 'OFFSET': <TokenType.OFFSET: 341>, 'ON': <TokenType.ON: 342>, 'OR': <TokenType.OR: 35>, 'XOR': <TokenType.XOR: 66>, 'ORDER BY': <TokenType.ORDER_BY: 345>, 'ORDINALITY': <TokenType.ORDINALITY: 348>, 'OUT': <TokenType.OUT: 349>, 'OUTER': <TokenType.OUTER: 351>, 'OVER': <TokenType.OVER: 352>, 'OVERLAPS': <TokenType.OVERLAPS: 353>, 'OVERWRITE': <TokenType.OVERWRITE: 354>, 'PARTITION': <TokenType.PARTITION: 356>, 'PARTITION BY': <TokenType.PARTITION_BY: 357>, 'PARTITIONED BY': <TokenType.PARTITION_BY: 357>, 'PARTITIONED_BY': <TokenType.PARTITION_BY: 357>, 'PERCENT': <TokenType.PERCENT: 359>, 'PIVOT': <TokenType.PIVOT: 360>, 'PRAGMA': <TokenType.PRAGMA: 365>, 'PRIMARY KEY': <TokenType.PRIMARY_KEY: 367>, 'PROCEDURE': <TokenType.PROCEDURE: 368>, 'OPERATOR': <TokenType.OPERATOR: 344>, 'QUALIFY': <TokenType.QUALIFY: 373>, 'RANGE': <TokenType.RANGE: 376>, 'RECURSIVE': <TokenType.RECURSIVE: 377>, 'REGEXP': <TokenType.RLIKE: 385>, 'RENAME': <TokenType.RENAME: 379>, 'REPLACE': <TokenType.REPLACE: 380>, 'RETURNING': <TokenType.RETURNING: 381>, 'REFERENCES': <TokenType.REFERENCES: 383>, 'RIGHT': <TokenType.RIGHT: 384>, 'RLIKE': <TokenType.RLIKE: 385>, 'ROLLBACK': <TokenType.ROLLBACK: 387>, 'ROLLUP': <TokenType.ROLLUP: 388>, 'ROW': <TokenType.STRUCT: 408>, 'ROWS': <TokenType.ROWS: 390>, 'SCHEMA': <TokenType.SCHEMA: 83>, 'SELECT': <TokenType.SELECT: 392>, 'SEMI': <TokenType.SEMI: 393>, 'SESSION': <TokenType.SESSION: 59>, 'SESSION_USER': <TokenType.SESSION_USER: 61>, 'SET': <TokenType.SET: 397>, 'SETTINGS': <TokenType.SETTINGS: 398>, 'SHOW': <TokenType.SHOW: 399>, 'SIMILAR TO': <TokenType.SIMILAR_TO: 400>, 'SOME': <TokenType.SOME: 401>, 'SORT BY': <TokenType.SORT_BY: 402>, 'SQL SECURITY': <TokenType.SQL_SECURITY: 404>, 'STRAIGHT_JOIN': <TokenType.STRAIGHT_JOIN: 407>, 'TABLE': <TokenType.TABLE: 84>, 'TABLESAMPLE': <TokenType.TABLE_SAMPLE: 410>, 'TEMP': <TokenType.TEMPORARY: 412>, 'TEMPORARY': <TokenType.TEMPORARY: 412>, 'THEN': <TokenType.THEN: 414>, 'TRUE': <TokenType.TRUE: 415>, 'TRUNCATE': <TokenType.TRUNCATE: 416>, 'TRIGGER': <TokenType.TRIGGER: 417>, 'UNION': <TokenType.UNION: 421>, 'UNKNOWN': <TokenType.UNKNOWN: 216>, 'UNNEST': <TokenType.UNNEST: 422>, 'UNPIVOT': <TokenType.UNPIVOT: 423>, 'UPDATE': <TokenType.UPDATE: 424>, 'USE': <TokenType.USE: 425>, 'USING': <TokenType.USING: 426>, 'UUID': <TokenType.UUID: 172>, 'VALUES': <TokenType.VALUES: 427>, 'VIEW': <TokenType.VIEW: 429>, 'VOLATILE': <TokenType.VOLATILE: 431>, 'WHEN': <TokenType.WHEN: 433>, 'WHERE': <TokenType.WHERE: 434>, 'WINDOW': <TokenType.WINDOW: 435>, 'WITH': <TokenType.WITH: 436>, 'APPLY': <TokenType.APPLY: 225>, 'ARRAY': <TokenType.ARRAY: 226>, 'BIT': <TokenType.BIT: 98>, 'BOOL': <TokenType.BOOLEAN: 99>, 'BOOLEAN': <TokenType.BOOLEAN: 99>, 'BYTE': <TokenType.TINYINT: 100>, 'MEDIUMINT': <TokenType.MEDIUMINT: 104>, 'INT1': <TokenType.TINYINT: 100>, 'TINYINT': <TokenType.TINYINT: 100>, 'INT16': <TokenType.SMALLINT: 102>, 'SHORT': <TokenType.SMALLINT: 102>, 'SMALLINT': <TokenType.SMALLINT: 102>, 'HUGEINT': <TokenType.INT128: 111>, 'UHUGEINT': <TokenType.UINT128: 112>, 'INT2': <TokenType.SMALLINT: 102>, 'INTEGER': <TokenType.INT: 106>, 'INT': <TokenType.INT: 106>, 'INT4': <TokenType.INT: 106>, 'INT32': <TokenType.INT: 106>, 'INT64': <TokenType.BIGINT: 108>, 'INT128': <TokenType.INT128: 111>, 'INT256': <TokenType.INT256: 113>, 'LONG': <TokenType.BIGINT: 108>, 'BIGINT': <TokenType.BIGINT: 108>, 'INT8': <TokenType.TINYINT: 100>, 'UINT': <TokenType.UINT: 107>, 'UINT128': <TokenType.UINT128: 112>, 'UINT256': <TokenType.UINT256: 114>, 'DEC': <TokenType.DECIMAL: 118>, 'DECIMAL': <TokenType.DECIMAL: 118>, 'DECIMAL32': <TokenType.DECIMAL32: 119>, 'DECIMAL64': <TokenType.DECIMAL64: 120>, 'DECIMAL128': <TokenType.DECIMAL128: 121>, 'DECIMAL256': <TokenType.DECIMAL256: 122>, 'DECFLOAT': <TokenType.DECFLOAT: 123>, 'BIGDECIMAL': <TokenType.BIGDECIMAL: 125>, 'BIGNUMERIC': <TokenType.BIGDECIMAL: 125>, 'BIGNUM': <TokenType.BIGNUM: 110>, 'LIST': <TokenType.LIST: 324>, 'MAP': <TokenType.MAP: 327>, 'NULLABLE': <TokenType.NULLABLE: 175>, 'NUMBER': <TokenType.DECIMAL: 118>, 'NUMERIC': <TokenType.DECIMAL: 118>, 'FIXED': <TokenType.DECIMAL: 118>, 'REAL': <TokenType.FLOAT: 115>, 'FLOAT': <TokenType.FLOAT: 115>, 'FLOAT4': <TokenType.FLOAT: 115>, 'FLOAT8': <TokenType.DOUBLE: 116>, 'DOUBLE': <TokenType.DOUBLE: 116>, 'DOUBLE PRECISION': <TokenType.DOUBLE: 116>, 'JSON': <TokenType.JSON: 142>, 'JSONB': <TokenType.JSONB: 143>, 'CHAR': <TokenType.CHAR: 126>, 'CHARACTER': <TokenType.CHAR: 126>, 'CHAR VARYING': <TokenType.VARCHAR: 128>, 'CHARACTER VARYING': <TokenType.VARCHAR: 128>, 'NCHAR': <TokenType.NCHAR: 127>, 'VARCHAR': <TokenType.VARCHAR: 128>, 'VARCHAR2': <TokenType.VARCHAR: 128>, 'NVARCHAR': <TokenType.NVARCHAR: 129>, 'NVARCHAR2': <TokenType.NVARCHAR: 129>, 'BPCHAR': <TokenType.BPCHAR: 130>, 'STR': <TokenType.TEXT: 131>, 'STRING': <TokenType.TEXT: 131>, 'TEXT': <TokenType.TEXT: 131>, 'LONGTEXT': <TokenType.LONGTEXT: 133>, 'MEDIUMTEXT': <TokenType.MEDIUMTEXT: 132>, 'TINYTEXT': <TokenType.TINYTEXT: 138>, 'CLOB': <TokenType.TEXT: 131>, 'LONGVARCHAR': <TokenType.TEXT: 131>, 'BINARY': <TokenType.BINARY: 140>, 'BLOB': <TokenType.VARBINARY: 141>, 'LONGBLOB': <TokenType.LONGBLOB: 136>, 'MEDIUMBLOB': <TokenType.MEDIUMBLOB: 135>, 'TINYBLOB': <TokenType.TINYBLOB: 137>, 'BYTEA': <TokenType.VARBINARY: 141>, 'VARBINARY': <TokenType.VARBINARY: 141>, 'TIME': <TokenType.TIME: 144>, 'TIMETZ': <TokenType.TIMETZ: 145>, 'TIME_NS': <TokenType.TIME_NS: 146>, 'TIMESTAMP': <TokenType.TIMESTAMP: 147>, 'TIMESTAMPTZ': <TokenType.TIMESTAMPTZ: 148>, 'TIMESTAMPLTZ': <TokenType.TIMESTAMPLTZ: 149>, 'TIMESTAMP_LTZ': <TokenType.TIMESTAMPLTZ: 149>, 'TIMESTAMPNTZ': <TokenType.TIMESTAMPNTZ: 150>, 'TIMESTAMP_NTZ': <TokenType.TIMESTAMPNTZ: 150>, 'DATE': <TokenType.DATE: 158>, 'DATETIME': <TokenType.DATETIME: 154>, 'INT4RANGE': <TokenType.INT4RANGE: 160>, 'INT4MULTIRANGE': <TokenType.INT4MULTIRANGE: 161>, 'INT8RANGE': <TokenType.INT8RANGE: 162>, 'INT8MULTIRANGE': <TokenType.INT8MULTIRANGE: 163>, 'NUMRANGE': <TokenType.NUMRANGE: 164>, 'NUMMULTIRANGE': <TokenType.NUMMULTIRANGE: 165>, 'TSRANGE': <TokenType.TSRANGE: 166>, 'TSMULTIRANGE': <TokenType.TSMULTIRANGE: 167>, 'TSTZRANGE': <TokenType.TSTZRANGE: 168>, 'TSTZMULTIRANGE': <TokenType.TSTZMULTIRANGE: 169>, 'DATERANGE': <TokenType.DATERANGE: 170>, 'DATEMULTIRANGE': <TokenType.DATEMULTIRANGE: 171>, 'UNIQUE': <TokenType.UNIQUE: 437>, 'VECTOR': <TokenType.VECTOR: 217>, 'STRUCT': <TokenType.STRUCT: 408>, 'SEQUENCE': <TokenType.SEQUENCE: 395>, 'VARIANT': <TokenType.VARIANT: 199>, 'ALTER': <TokenType.ALTER: 221>, 'ANALYZE': <TokenType.ANALYZE: 444>, 'CALL': <TokenType.COMMAND: 239>, 'COMMENT': <TokenType.COMMENT: 240>, 'EXPLAIN': <TokenType.COMMAND: 239>, 'GRANT': <TokenType.GRANT: 293>, 'REVOKE': <TokenType.REVOKE: 382>, 'OPTIMIZE': <TokenType.COMMAND: 239>, 'PREPARE': <TokenType.COMMAND: 239>, 'VACUUM': <TokenType.COMMAND: 239>, 'USER-DEFINED': <TokenType.USERDEFINED: 194>, 'ADD ARCHIVE': <TokenType.COMMAND: 239>, 'ADD ARCHIVES': <TokenType.COMMAND: 239>, 'ADD FILE': <TokenType.COMMAND: 239>, 'ADD FILES': <TokenType.COMMAND: 239>, 'ADD JAR': <TokenType.COMMAND: 239>, 'ADD JARS': <TokenType.COMMAND: 239>, 'MINUS': <TokenType.EXCEPT: 273>, 'MSCK REPAIR': <TokenType.COMMAND: 239>, 'REFRESH': <TokenType.REFRESH: 378>, 'SERDEPROPERTIES': <TokenType.SERDE_PROPERTIES: 396>, 'DEALLOCATE PREPARE': <TokenType.COMMAND: 239>, 'DESCRIBE INPUT': <TokenType.COMMAND: 239>, 'DESCRIBE OUTPUT': <TokenType.COMMAND: 239>, 'RESET SESSION': <TokenType.COMMAND: 239>, 'START': <TokenType.BEGIN: 231>, 'MATCH_RECOGNIZE': <TokenType.MATCH_RECOGNIZE: 330>, 'IPADDRESS': <TokenType.IPADDRESS: 203>, 'IPPREFIX': <TokenType.IPPREFIX: 204>, 'TDIGEST': <TokenType.TDIGEST: 215>, 'HYPERLOGLOG': <TokenType.HLLSKETCH: 186>, 'DECLARE': <TokenType.DECLARE: 258>, 'UNLOAD': <TokenType.COMMAND: 239>}
def tokenize(self, sql: str) -> list[sqlglot.tokenizer_core.Token]:
 78        def tokenize(self, sql: str) -> list[Token]:
 79            # DML only needs Trino's tokenizer; possible Hive statements need disambiguation.
 80            try:
 81                trino_tokens: list[Token] | None = self._trino_tokenizer.tokenize(sql)
 82            except TokenError:
 83                trino_tokens = None
 84
 85            if trino_tokens is not None and not _may_be_hive(trino_tokens):
 86                return trino_tokens
 87
 88            try:
 89                tokens = super().tokenize(sql)
 90            except TokenError:
 91                # Combined rules can reject literals valid in only one engine.
 92                if trino_tokens is not None and not _tokenize_as_hive(trino_tokens):
 93                    return trino_tokens
 94
 95                try:
 96                    tokens = self._hive_tokenizer.tokenize(sql)
 97                except TokenError:
 98                    pass
 99                else:
100                    if _tokenize_as_hive(tokens):
101                        return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + tokens
102                raise
103
104            if _tokenize_as_hive(tokens):
105                return [Token(TokenType.HIVE_TOKEN_STREAM, "")] + self._hive_tokenizer.tokenize(sql)
106
107            return trino_tokens if trino_tokens is not None else self._trino_tokenizer.tokenize(sql)

Returns a list of tokens corresponding to the SQL string sql.

BYTE_STRING_ESCAPES: ClassVar[list[str]] = ["'", '\\']