Dialects
While there is a SQL standard, most SQL engines support a variation of that standard. This makes it difficult to write portable SQL code. SQLGlot bridges all the different variations, called "dialects", with an extensible SQL transpilation framework.
The base sqlglot.dialects.dialect.Dialect class implements a generic dialect that aims to be as universal as possible.
Each SQL variation has its own Dialect subclass, extending the corresponding Tokenizer, Parser and Generator
classes as needed.
Implementing a custom Dialect
Creating a new SQL dialect may seem complicated at first, but it is actually quite simple in SQLGlot:
from sqlglot import exp
from sqlglot.dialects.dialect import Dialect
from sqlglot.generator import Generator
from sqlglot.tokens import Tokenizer, TokenType
class Custom(Dialect):
class Tokenizer(Tokenizer):
QUOTES = ["'", '"'] # Strings can be delimited by either single or double quotes
IDENTIFIERS = ["`"] # Identifiers can be delimited by backticks
# Associates certain meaningful words with tokens that capture their intent
KEYWORDS = {
**Tokenizer.KEYWORDS,
"INT64": TokenType.BIGINT,
"FLOAT64": TokenType.DOUBLE,
}
class Generator(Generator):
# Specifies how AST nodes, i.e. subclasses of exp.Expr, should be converted into SQL
TRANSFORMS = {
exp.Array: lambda self, e: f"[{self.expressions(e)}]",
}
# Specifies how AST nodes representing data types should be converted into SQL
TYPE_MAPPING = {
exp.DType.TINYINT: "INT64",
exp.DType.SMALLINT: "INT64",
exp.DType.INT: "INT64",
exp.DType.BIGINT: "INT64",
exp.DType.DECIMAL: "NUMERIC",
exp.DType.FLOAT: "FLOAT64",
exp.DType.DOUBLE: "FLOAT64",
exp.DType.BOOLEAN: "BOOL",
exp.DType.TEXT: "STRING",
}
The above example demonstrates how certain parts of the base Dialect class can be overridden to match a different
specification. Even though it is a fairly realistic starting point, we strongly encourage the reader to study existing
dialect implementations in order to understand how their various components can be modified, depending on the use-case.
1# ruff: noqa: F401 2""" 3## Dialects 4 5While there is a SQL standard, most SQL engines support a variation of that standard. This makes it difficult 6to write portable SQL code. SQLGlot bridges all the different variations, called "dialects", with an extensible 7SQL transpilation framework. 8 9The base `sqlglot.dialects.dialect.Dialect` class implements a generic dialect that aims to be as universal as possible. 10 11Each SQL variation has its own `Dialect` subclass, extending the corresponding `Tokenizer`, `Parser` and `Generator` 12classes as needed. 13 14### Implementing a custom Dialect 15 16Creating a new SQL dialect may seem complicated at first, but it is actually quite simple in SQLGlot: 17 18```python 19from sqlglot import exp 20from sqlglot.dialects.dialect import Dialect 21from sqlglot.generator import Generator 22from sqlglot.tokens import Tokenizer, TokenType 23 24 25class Custom(Dialect): 26 class Tokenizer(Tokenizer): 27 QUOTES = ["'", '"'] # Strings can be delimited by either single or double quotes 28 IDENTIFIERS = ["`"] # Identifiers can be delimited by backticks 29 30 # Associates certain meaningful words with tokens that capture their intent 31 KEYWORDS = { 32 **Tokenizer.KEYWORDS, 33 "INT64": TokenType.BIGINT, 34 "FLOAT64": TokenType.DOUBLE, 35 } 36 37 class Generator(Generator): 38 # Specifies how AST nodes, i.e. subclasses of exp.Expr, should be converted into SQL 39 TRANSFORMS = { 40 exp.Array: lambda self, e: f"[{self.expressions(e)}]", 41 } 42 43 # Specifies how AST nodes representing data types should be converted into SQL 44 TYPE_MAPPING = { 45 exp.DType.TINYINT: "INT64", 46 exp.DType.SMALLINT: "INT64", 47 exp.DType.INT: "INT64", 48 exp.DType.BIGINT: "INT64", 49 exp.DType.DECIMAL: "NUMERIC", 50 exp.DType.FLOAT: "FLOAT64", 51 exp.DType.DOUBLE: "FLOAT64", 52 exp.DType.BOOLEAN: "BOOL", 53 exp.DType.TEXT: "STRING", 54 } 55``` 56 57The above example demonstrates how certain parts of the base `Dialect` class can be overridden to match a different 58specification. Even though it is a fairly realistic starting point, we strongly encourage the reader to study existing 59dialect implementations in order to understand how their various components can be modified, depending on the use-case. 60 61---- 62""" 63 64import importlib 65import threading 66 67DIALECTS = [ 68 "Athena", 69 "BigQuery", 70 "ClickHouse", 71 "Databricks", 72 "DAX", 73 "Doris", 74 "Dremio", 75 "Drill", 76 "Druid", 77 "DuckDB", 78 "Dune", 79 "Exasol", 80 "Fabric", 81 "Hive", 82 "Materialize", 83 "MySQL", 84 "Oracle", 85 "Postgres", 86 "Presto", 87 "PRQL", 88 "Redshift", 89 "RisingWave", 90 "SingleStore", 91 "Snowflake", 92 "Solr", 93 "Spark", 94 "Spark2", 95 "SQLite", 96 "StarRocks", 97 "Tableau", 98 "Teradata", 99 "Trino", 100 "TSQL", 101] 102 103MODULE_BY_DIALECT = {name: name.lower() for name in DIALECTS} 104DIALECT_MODULE_NAMES = MODULE_BY_DIALECT.values() 105 106MODULE_BY_ATTRIBUTE = { 107 **MODULE_BY_DIALECT, 108 "Dialect": "dialect", 109 "Dialects": "dialect", 110} 111 112__all__ = list(MODULE_BY_ATTRIBUTE) 113 114# We use a reentrant lock because a dialect may depend on (i.e., import) other dialects. 115# Without it, the first dialect import would never be completed, because subsequent 116# imports would be blocked on the lock held by the first import. 117_import_lock = threading.RLock() 118 119 120def __getattr__(name): 121 module_name = MODULE_BY_ATTRIBUTE.get(name) 122 if module_name: 123 with _import_lock: 124 module = importlib.import_module(f"sqlglot.dialects.{module_name}") 125 attr = getattr(module, name) 126 globals()[name] = attr 127 return attr 128 129 raise AttributeError(f"module {__name__} has no attribute {name}")
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:
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
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)
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.
Inherited Members
- sqlglot.tokens.Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- QUOTES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- sql
- size
- tokens
25class BigQuery(Dialect): 26 WEEK_OFFSET = -1 27 UNNEST_COLUMN_ONLY = True 28 SUPPORTS_USER_DEFINED_TYPES = False 29 LOG_BASE_FIRST = False 30 HEX_LOWERCASE = True 31 FORCE_EARLY_ALIAS_REF_EXPANSION = True 32 EXPAND_ONLY_GROUP_ALIAS_REF = True 33 ORIGINAL_NAME_META_KEY = "bigquery_name" 34 HEX_STRING_IS_INTEGER_TYPE = True 35 BYTE_STRING_IS_BYTES_TYPE = True 36 UUID_IS_STRING_TYPE = True 37 ANNOTATE_ALL_SCOPES = True 38 PROJECTION_ALIASES_SHADOW_SOURCE_NAMES = True 39 TABLES_REFERENCEABLE_AS_COLUMNS = True 40 TABLE_ALIASES_SHADOW_COLUMN_NAMES = True 41 SUPPORTS_STRUCT_STAR_EXPANSION = True 42 EXCLUDES_PSEUDOCOLUMNS_FROM_STAR = True 43 QUERY_RESULTS_ARE_STRUCTS = True 44 JSON_EXTRACT_SCALAR_SCALAR_ONLY = True 45 JSON_PATH_SINGLE_DOT_IS_WILDCARD = True 46 LEAST_GREATEST_IGNORES_NULLS = False 47 DEFAULT_NULL_TYPE = exp.DType.BIGINT 48 PRIORITIZE_NON_LITERAL_TYPES = True 49 ALIAS_POST_VERSION = False 50 51 # https://docs.cloud.google.com/bigquery/docs/reference/standard-sql/string_functions#initcap 52 INITCAP_DEFAULT_DELIMITER_CHARS = ' \t\n\r\f\v\\[\\](){}/|<>!?@"^#$&~_,.:;*%+\\-' 53 54 # https://cloud.google.com/bigquery/docs/reference/standard-sql/lexical#case_sensitivity 55 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 56 ASCII_ONLY_NORMALIZATION = True 57 58 # bigquery udfs are case sensitive 59 NORMALIZE_FUNCTIONS = False 60 61 # https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_elements_date_time 62 TIME_MAPPING = { 63 "%x": "%m/%d/%y", 64 "%D": "%m/%d/%y", 65 "%E6S": "%S.%f", 66 "%e": "%-d", 67 "%F": "%Y-%m-%d", 68 "%T": "%H:%M:%S", 69 "%c": "%a %b %e %H:%M:%S %Y", 70 } 71 72 INVERSE_TIME_MAPPING = { 73 # Preserve %E6S instead of expanding to %T.%f - since both %E6S & %T.%f are semantically different in BigQuery 74 # %E6S is semantically different from %T.%f: %E6S works as a single atomic specifier for seconds with microseconds, while %T.%f expands incorrectly and fails to parse. 75 "%H:%M:%S.%f": "%H:%M:%E6S", 76 } 77 78 FORMAT_MAPPING = { 79 "dd": "%d", 80 "DD": "%d", 81 "mm": "%m", 82 "MM": "%m", 83 "mon": "%b", 84 "MON": "%b", 85 "month": "%B", 86 "MONTH": "%B", 87 "yyyy": "%Y", 88 "YYYY": "%Y", 89 "yy": "%y", 90 "YY": "%y", 91 "HH": "%I", 92 "HH12": "%I", 93 "hh24": "%H", 94 "HH24": "%H", 95 "mi": "%M", 96 "MI": "%M", 97 "ss": "%S", 98 "SS": "%S", 99 "SSSSS": "%f", 100 "tzh": "%z", 101 "TZH": "%z", 102 } 103 104 # The _PARTITIONTIME and _PARTITIONDATE pseudo-columns are not returned by a SELECT * statement 105 # https://cloud.google.com/bigquery/docs/querying-partitioned-tables#query_an_ingestion-time_partitioned_table 106 # https://cloud.google.com/bigquery/docs/querying-wildcard-tables#scanning_a_range_of_tables_using_table_suffix 107 # https://cloud.google.com/bigquery/docs/query-cloud-storage-data#query_the_file_name_pseudo-column 108 PSEUDOCOLUMNS = { 109 "_PARTITIONTIME", 110 "_PARTITIONDATE", 111 "_TABLE_SUFFIX", 112 "_FILE_NAME", 113 "_DBT_MAX_PARTITION", 114 } 115 116 # All set operations require either a DISTINCT or ALL specifier 117 SET_OP_DISTINCT_BY_DEFAULT = dict.fromkeys((exp.Except, exp.Intersect, exp.Union), None) 118 119 # https://cloud.google.com/bigquery/docs/reference/standard-sql/navigation_functions#percentile_cont 120 COERCES_TO = { 121 **TypeAnnotator.COERCES_TO, 122 exp.DType.BIGDECIMAL: {exp.DType.DOUBLE}, 123 } 124 COERCES_TO[exp.DType.DECIMAL] |= {exp.DType.BIGDECIMAL} 125 COERCES_TO[exp.DType.BIGINT] |= {exp.DType.BIGDECIMAL} 126 COERCES_TO[exp.DType.VARCHAR] |= { 127 exp.DType.DATE, 128 exp.DType.DATETIME, 129 exp.DType.TIME, 130 exp.DType.TIMESTAMP, 131 exp.DType.TIMESTAMPTZ, 132 } 133 134 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 135 136 def normalize_identifier(self, expression: E) -> E: 137 if ( 138 isinstance(expression, exp.Identifier) 139 and self.normalization_strategy is NormalizationStrategy.CASE_INSENSITIVE 140 ): 141 parent = expression.parent 142 while isinstance(parent, exp.Dot): 143 parent = parent.parent 144 145 # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive 146 # by default. The following check uses a heuristic to detect tables based on whether 147 # they are qualified. This should generally be correct, because tables in BigQuery 148 # must be qualified with at least a dataset, unless @@dataset_id is set. 149 case_sensitive = ( 150 isinstance(parent, exp.UserDefinedFunction) 151 or ( 152 isinstance(parent, exp.Table) 153 and parent.db 154 and (parent.meta_get("quoted_table") or not parent.meta_get("maybe_column")) 155 ) 156 or expression.meta_get("is_table") 157 ) 158 if not case_sensitive: 159 expression.set("this", expression.this.translate(ASCII_LOWER)) 160 161 return t.cast(E, expression) 162 163 return super().normalize_identifier(expression) 164 165 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 166 VAR_TOKENS = { 167 *jsonpath.JSONPathTokenizer.VAR_TOKENS, 168 TokenType.DASH, 169 TokenType.NUMBER, 170 } 171 172 class Tokenizer(tokens.Tokenizer): 173 NUMERIC_ESCAPES = { 174 "x": (16, 2, 2, 0xFF), 175 "X": (16, 2, 2, 0xFF), 176 "u": (16, 4, 4, 0xFFFF), 177 "U": (16, 8, 8, 0x10FFFF), 178 "0": (8, 3, 3, 0xFF), 179 } 180 DROP_UNKNOWN_ESCAPES = True 181 QUOTES = ["'", '"', '"""', "'''"] 182 COMMENTS = ["--", "#", ("/*", "*/")] 183 IDENTIFIERS = ["`"] 184 STRING_ESCAPES = ["\\"] 185 186 HEX_STRINGS = [("0x", ""), ("0X", "")] 187 188 BYTE_STRINGS = [(prefix + q, q) for q in t.cast(list[str], QUOTES) for prefix in ("b", "B")] 189 190 RAW_STRINGS = [(prefix + q, q) for q in t.cast(list[str], QUOTES) for prefix in ("r", "R")] 191 192 NESTED_COMMENTS = False 193 194 KEYWORDS = { 195 **tokens.Tokenizer.KEYWORDS, 196 "ANY TYPE": TokenType.VARIANT, 197 "BEGIN": TokenType.COMMAND, 198 "BEGIN TRANSACTION": TokenType.BEGIN, 199 "BYTEINT": TokenType.INT, 200 "BYTES": TokenType.BINARY, 201 "CURRENT_DATETIME": TokenType.CURRENT_DATETIME, 202 "DATETIME": TokenType.TIMESTAMP, 203 "DECLARE": TokenType.DECLARE, 204 "ELSEIF": TokenType.COMMAND, 205 "EXCEPTION": TokenType.COMMAND, 206 "EXPORT": TokenType.EXPORT, 207 "FLOAT64": TokenType.DOUBLE, 208 "LOOP": TokenType.COMMAND, 209 "MODEL": TokenType.MODEL, 210 "RECORD": TokenType.STRUCT, 211 "REPEAT": TokenType.COMMAND, 212 "TIMESTAMP": TokenType.TIMESTAMPTZ, 213 "WHILE": TokenType.COMMAND, 214 } 215 KEYWORDS.pop("ISNULL") 216 KEYWORDS.pop("DIV") 217 KEYWORDS.pop("VALUES") 218 KEYWORDS.pop("/*+") 219 220 Parser = BigQueryParser 221 222 Generator = BigQueryGenerator
First day of the week in DATE_TRUNC(week). Defaults to 0 (Monday). -1 would be Sunday.
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Whether alias reference expansion (_expand_alias_refs()) should run before column qualification (_qualify_columns()).
For example:
WITH data AS ( SELECT 1 AS id, 2 AS my_id ) SELECT id AS my_id FROM data WHERE my_id = 1 GROUP BY my_id, HAVING my_id = 1
In most dialects, "my_id" would refer to "data.my_id" across the query, except: - BigQuery, which will forward the alias to GROUP BY + HAVING clauses i.e it resolves to "WHERE my_id = 1 GROUP BY id HAVING id = 1" - Clickhouse, which will forward the alias across the query i.e it resolves to "WHERE id = 1 GROUP BY id HAVING id = 1"
Whether alias reference expansion before qualification should only happen for the GROUP BY clause.
Dialect-specific metadata key for preserving original function names, or None to disable. Only generators using the same key reuse these names, allowing round trips of aliases that share an AST node, e.g. JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery.
Whether hex strings such as x'CC' evaluate to integer or binary/blob type
Whether byte string literals (ex: BigQuery's b'...') are typed as BYTES/BINARY
Whether to annotate all scopes during optimization. Used by BigQuery for UNNEST support.
Whether projection alias names can shadow table/source names in GROUP BY and HAVING clauses.
In BigQuery, when a projection alias has the same name as a source table, the alias takes precedence in GROUP BY and HAVING clauses, and the table becomes inaccessible by that name.
For example, in BigQuery: SELECT id, ARRAY_AGG(col) AS custom_fields FROM custom_fields GROUP BY id HAVING id >= 1
The "custom_fields" source is shadowed by the projection alias, so we cannot qualify "id" with "custom_fields" in GROUP BY/HAVING.
Whether table names can be referenced as columns (treated as structs).
BigQuery allows tables to be referenced as columns in queries, automatically treating them as struct values containing all the table's columns.
For example, in BigQuery: SELECT t FROM my_table AS t -- Returns entire row as a struct
Whether a whole-row reference to a table alias takes precedence over a same-named column.
Whether the dialect supports expanding struct fields using star notation (e.g., struct_col.*).
BigQuery allows struct fields to be expanded with the star operator:
SELECT t.struct_col.* FROM table t
RisingWave also allows struct field expansion with the star operator using parentheses:
SELECT (t.struct_col).* FROM table t
This expands to all fields within the struct.
Whether pseudocolumns should be excluded from star expansion (SELECT *).
Pseudocolumns are special dialect-specific columns (e.g., Oracle's ROWNUM, ROWID, LEVEL, or BigQuery's _PARTITIONTIME, _PARTITIONDATE) that are implicitly available but not part of the table schema. When this is True, SELECT * will not include these pseudocolumns; they must be explicitly selected.
Whether query results are typed as structs in metadata for type inference.
In BigQuery, subqueries store their column types as a STRUCT in metadata,
enabling special type inference for ARRAY(SELECT ...) expressions:
ARRAY(SELECT x, y FROM t) → ARRAY For single column subqueries, BigQuery unwraps the struct:
ARRAY(SELECT x FROM t) → ARRAY This is metadata-only for type inference.
Whether JSON_EXTRACT_SCALAR returns null if a non-scalar value is selected.
Whether a single DOT in a JSON path (e.g. $.) is treated as a valid wildcard key.
Whether LEAST/GREATEST functions ignore NULL values, e.g:
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
The default type of NULL for producing the correct projection type.
For example, in BigQuery the default type of the NULL value is INT64.
Whether to prioritize non-literal types over literals during type annotation.
Whether the table alias comes after version (timestamp or iceberg snapshot).
Specifies the strategy according to which identifiers should be normalized.
Whether identifiers are only normalized with respect to ASCII characters, e.g. Ä and
ä are different identifiers in DuckDB, but the same identifier in Spark.
Determines how function names are going to be normalized.
Possible values:
"upper" or True: Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
Associates this dialect's time formats with their equivalent Python strftime formats.
Helper which is used for parsing the special syntax CAST(x AS DATE FORMAT 'yyyy').
If empty, the corresponding trie will be constructed off of TIME_MAPPING.
Columns that are auto-generated by the engine corresponding to this dialect.
For example, such columns may be excluded from SELECT * queries.
Whether a set operation uses DISTINCT by default. This is None when either DISTINCT or ALL
must be explicitly specified.
136 def normalize_identifier(self, expression: E) -> E: 137 if ( 138 isinstance(expression, exp.Identifier) 139 and self.normalization_strategy is NormalizationStrategy.CASE_INSENSITIVE 140 ): 141 parent = expression.parent 142 while isinstance(parent, exp.Dot): 143 parent = parent.parent 144 145 # In BigQuery, CTEs are case-insensitive, but UDF and table names are case-sensitive 146 # by default. The following check uses a heuristic to detect tables based on whether 147 # they are qualified. This should generally be correct, because tables in BigQuery 148 # must be qualified with at least a dataset, unless @@dataset_id is set. 149 case_sensitive = ( 150 isinstance(parent, exp.UserDefinedFunction) 151 or ( 152 isinstance(parent, exp.Table) 153 and parent.db 154 and (parent.meta_get("quoted_table") or not parent.meta_get("maybe_column")) 155 ) 156 or expression.meta_get("is_table") 157 ) 158 if not case_sensitive: 159 expression.set("this", expression.this.translate(ASCII_LOWER)) 160 161 return t.cast(E, expression) 162 163 return super().normalize_identifier(expression)
Transforms an identifier in a way that resembles how it'd be resolved by this dialect.
For example, an identifier like FoO would be resolved as foo in Postgres, because it
lowercases all unquoted identifiers. On the other hand, Snowflake uppercases them, so
it would resolve it as FOO. If it was quoted, it'd need to be treated as case-sensitive,
and so any normalization would be prohibited in order to avoid "breaking" the identifier.
There are also dialects like Spark, which are case-insensitive even when quotes are present, and dialects like MySQL, whose resolution rules match those employed by the underlying operating system, for example they may always be case-sensitive in Linux.
Finally, the normalization behavior of some engines can even be controlled through flags, like in Redshift's case, where users can explicitly set enable_case_sensitive_identifier.
SQLGlot aims to understand and handle all of these different behaviors gracefully, so that it can analyze queries in the optimizer and successfully capture their semantics.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
165 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 166 VAR_TOKENS = { 167 *jsonpath.JSONPathTokenizer.VAR_TOKENS, 168 TokenType.DASH, 169 TokenType.NUMBER, 170 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- VAR_SINGLE_TOKENS
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
172 class Tokenizer(tokens.Tokenizer): 173 NUMERIC_ESCAPES = { 174 "x": (16, 2, 2, 0xFF), 175 "X": (16, 2, 2, 0xFF), 176 "u": (16, 4, 4, 0xFFFF), 177 "U": (16, 8, 8, 0x10FFFF), 178 "0": (8, 3, 3, 0xFF), 179 } 180 DROP_UNKNOWN_ESCAPES = True 181 QUOTES = ["'", '"', '"""', "'''"] 182 COMMENTS = ["--", "#", ("/*", "*/")] 183 IDENTIFIERS = ["`"] 184 STRING_ESCAPES = ["\\"] 185 186 HEX_STRINGS = [("0x", ""), ("0X", "")] 187 188 BYTE_STRINGS = [(prefix + q, q) for q in t.cast(list[str], QUOTES) for prefix in ("b", "B")] 189 190 RAW_STRINGS = [(prefix + q, q) for q in t.cast(list[str], QUOTES) for prefix in ("r", "R")] 191 192 NESTED_COMMENTS = False 193 194 KEYWORDS = { 195 **tokens.Tokenizer.KEYWORDS, 196 "ANY TYPE": TokenType.VARIANT, 197 "BEGIN": TokenType.COMMAND, 198 "BEGIN TRANSACTION": TokenType.BEGIN, 199 "BYTEINT": TokenType.INT, 200 "BYTES": TokenType.BINARY, 201 "CURRENT_DATETIME": TokenType.CURRENT_DATETIME, 202 "DATETIME": TokenType.TIMESTAMP, 203 "DECLARE": TokenType.DECLARE, 204 "ELSEIF": TokenType.COMMAND, 205 "EXCEPTION": TokenType.COMMAND, 206 "EXPORT": TokenType.EXPORT, 207 "FLOAT64": TokenType.DOUBLE, 208 "LOOP": TokenType.COMMAND, 209 "MODEL": TokenType.MODEL, 210 "RECORD": TokenType.STRUCT, 211 "REPEAT": TokenType.COMMAND, 212 "TIMESTAMP": TokenType.TIMESTAMPTZ, 213 "WHILE": TokenType.COMMAND, 214 } 215 KEYWORDS.pop("ISNULL") 216 KEYWORDS.pop("DIV") 217 KEYWORDS.pop("VALUES") 218 KEYWORDS.pop("/*+")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- NATIONAL_RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
16class ClickHouse(Dialect): 17 INDEX_OFFSET = 1 18 NORMALIZE_FUNCTIONS: bool | str = False 19 NULL_ORDERING = "nulls_are_last" 20 SUPPORTS_USER_DEFINED_TYPES = False 21 LOG_BASE_FIRST: bool | None = None 22 FORCE_EARLY_ALIAS_REF_EXPANSION = True 23 ORIGINAL_NAME_META_KEY = "clickhouse_name" 24 NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = True 25 IDENTIFIERS_CAN_START_WITH_DIGIT = True 26 HEX_STRING_IS_INTEGER_TYPE = True 27 28 # https://github.com/ClickHouse/ClickHouse/issues/33935#issue-1112165779 29 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_SENSITIVE 30 31 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 32 33 UNESCAPED_SEQUENCES = { 34 "\\0": "\0", 35 "\\e": "\x1b", 36 "\\N": "", 37 "\\/": "/", 38 '\\"': '"', 39 "\\=": "=", 40 "\\`": "`", 41 **{"\\" + chr(i): chr(i) for i in range(1, 32)}, 42 } 43 44 CREATABLE_KIND_MAPPING = {"DATABASE": "SCHEMA"} 45 46 SET_OP_DISTINCT_BY_DEFAULT: dict[type[exp.Expr], bool | None] = { 47 exp.Except: False, 48 exp.Intersect: False, 49 exp.Union: None, 50 } 51 52 def generate_values_aliases(self, expression: exp.Values) -> list[exp.Identifier]: 53 # Clickhouse allows VALUES to have an embedded structure e.g: 54 # VALUES('person String, place String', ('Noah', 'Paris'), ...) 55 # In this case, we don't want to qualify the columns 56 values = expression.expressions[0].expressions 57 58 structure = ( 59 values[0] 60 if (len(values) > 1 and values[0].is_string and isinstance(values[1], exp.Tuple)) 61 else None 62 ) 63 if structure: 64 # Split each column definition into the column name e.g: 65 # 'person String, place String' -> ['person', 'place'] 66 structure_coldefs = [coldef.strip() for coldef in structure.name.split(",")] 67 column_aliases = [ 68 exp.to_identifier(coldef.split(" ")[0]) for coldef in structure_coldefs 69 ] 70 else: 71 # Default column aliases in CH are "c1", "c2", etc. 72 column_aliases = [ 73 exp.to_identifier(f"c{i + 1}") for i in range(len(values[0].expressions)) 74 ] 75 76 return column_aliases 77 78 class Tokenizer(tokens.Tokenizer): 79 NUMERIC_ESCAPES = {"x": (16, 2, 2, 0xFF)} 80 NUMERIC_ESCAPES_ARE_BYTES = True 81 COMMENTS = ["--", "#", "#!", ("/*", "*/")] 82 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 83 IDENTIFIERS = ['"', "`"] 84 IDENTIFIER_ESCAPES = ["\\"] 85 STRING_ESCAPES = ["'", "\\"] 86 BIT_STRINGS = [("0b", "")] 87 HEX_STRINGS = [("0x", ""), ("0X", "")] 88 HEREDOC_STRINGS = ["$"] 89 90 KEYWORDS = { 91 **tokens.Tokenizer.KEYWORDS, 92 ".:": TokenType.DOTCOLON, 93 ".^": TokenType.DOTCARET, 94 "ATTACH": TokenType.COMMAND, 95 "DATE32": TokenType.DATE32, 96 "DETACH": TokenType.DETACH, 97 "DATETIME64": TokenType.DATETIME64, 98 "DICTIONARY": TokenType.DICTIONARY, 99 "DYNAMIC": TokenType.DYNAMIC, 100 "ENUM8": TokenType.ENUM8, 101 "ENUM16": TokenType.ENUM16, 102 "EXCHANGE": TokenType.COMMAND, 103 "FINAL": TokenType.FINAL, 104 "FIXEDSTRING": TokenType.FIXEDSTRING, 105 "FLOAT32": TokenType.FLOAT, 106 "FLOAT64": TokenType.DOUBLE, 107 "GLOBAL": TokenType.GLOBAL, 108 "LOWCARDINALITY": TokenType.LOWCARDINALITY, 109 "MAP": TokenType.MAP, 110 "NESTED": TokenType.NESTED, 111 "NOTHING": TokenType.NOTHING, 112 "SAMPLE": TokenType.TABLE_SAMPLE, 113 "TUPLE": TokenType.STRUCT, 114 "UINT16": TokenType.USMALLINT, 115 "UINT32": TokenType.UINT, 116 "UINT64": TokenType.UBIGINT, 117 "UINT8": TokenType.UTINYINT, 118 "IPV4": TokenType.IPV4, 119 "IPV6": TokenType.IPV6, 120 "PASTE": TokenType.PASTE, 121 "POINT": TokenType.POINT, 122 "PROJECTION": TokenType.PROJECTION, 123 "RING": TokenType.RING, 124 "LINESTRING": TokenType.LINESTRING, 125 "MULTILINESTRING": TokenType.MULTILINESTRING, 126 "POLYGON": TokenType.POLYGON, 127 "MULTIPOLYGON": TokenType.MULTIPOLYGON, 128 "AGGREGATEFUNCTION": TokenType.AGGREGATEFUNCTION, 129 "SIMPLEAGGREGATEFUNCTION": TokenType.SIMPLEAGGREGATEFUNCTION, 130 "SYSTEM": TokenType.COMMAND, 131 "PREWHERE": TokenType.PREWHERE, 132 } 133 134 KEYWORDS.pop("/*+") 135 136 SINGLE_TOKENS = { 137 **tokens.Tokenizer.SINGLE_TOKENS, 138 "$": TokenType.HEREDOC_STRING, 139 } 140 141 Parser = ClickHouseParser 142 143 Generator = ClickHouseGenerator
Determines how function names are going to be normalized.
Possible values:
"upper" or True: Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Whether alias reference expansion (_expand_alias_refs()) should run before column qualification (_qualify_columns()).
For example:
WITH data AS ( SELECT 1 AS id, 2 AS my_id ) SELECT id AS my_id FROM data WHERE my_id = 1 GROUP BY my_id, HAVING my_id = 1
In most dialects, "my_id" would refer to "data.my_id" across the query, except: - BigQuery, which will forward the alias to GROUP BY + HAVING clauses i.e it resolves to "WHERE my_id = 1 GROUP BY id HAVING id = 1" - Clickhouse, which will forward the alias across the query i.e it resolves to "WHERE id = 1 GROUP BY id HAVING id = 1"
Dialect-specific metadata key for preserving original function names, or None to disable. Only generators using the same key reuse these names, allowing round trips of aliases that share an AST node, e.g. JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery.
Whether number literals can include underscores for better readability
Whether hex strings such as x'CC' evaluate to integer or binary/blob type
Specifies the strategy according to which identifiers should be normalized.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Helper for dialects that use a different name for the same creatable kind. For example, the Clickhouse equivalent of CREATE SCHEMA is CREATE DATABASE.
Whether a set operation uses DISTINCT by default. This is None when either DISTINCT or ALL
must be explicitly specified.
52 def generate_values_aliases(self, expression: exp.Values) -> list[exp.Identifier]: 53 # Clickhouse allows VALUES to have an embedded structure e.g: 54 # VALUES('person String, place String', ('Noah', 'Paris'), ...) 55 # In this case, we don't want to qualify the columns 56 values = expression.expressions[0].expressions 57 58 structure = ( 59 values[0] 60 if (len(values) > 1 and values[0].is_string and isinstance(values[1], exp.Tuple)) 61 else None 62 ) 63 if structure: 64 # Split each column definition into the column name e.g: 65 # 'person String, place String' -> ['person', 'place'] 66 structure_coldefs = [coldef.strip() for coldef in structure.name.split(",")] 67 column_aliases = [ 68 exp.to_identifier(coldef.split(" ")[0]) for coldef in structure_coldefs 69 ] 70 else: 71 # Default column aliases in CH are "c1", "c2", etc. 72 column_aliases = [ 73 exp.to_identifier(f"c{i + 1}") for i in range(len(values[0].expressions)) 74 ] 75 76 return column_aliases
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
78 class Tokenizer(tokens.Tokenizer): 79 NUMERIC_ESCAPES = {"x": (16, 2, 2, 0xFF)} 80 NUMERIC_ESCAPES_ARE_BYTES = True 81 COMMENTS = ["--", "#", "#!", ("/*", "*/")] 82 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 83 IDENTIFIERS = ['"', "`"] 84 IDENTIFIER_ESCAPES = ["\\"] 85 STRING_ESCAPES = ["'", "\\"] 86 BIT_STRINGS = [("0b", "")] 87 HEX_STRINGS = [("0x", ""), ("0X", "")] 88 HEREDOC_STRINGS = ["$"] 89 90 KEYWORDS = { 91 **tokens.Tokenizer.KEYWORDS, 92 ".:": TokenType.DOTCOLON, 93 ".^": TokenType.DOTCARET, 94 "ATTACH": TokenType.COMMAND, 95 "DATE32": TokenType.DATE32, 96 "DETACH": TokenType.DETACH, 97 "DATETIME64": TokenType.DATETIME64, 98 "DICTIONARY": TokenType.DICTIONARY, 99 "DYNAMIC": TokenType.DYNAMIC, 100 "ENUM8": TokenType.ENUM8, 101 "ENUM16": TokenType.ENUM16, 102 "EXCHANGE": TokenType.COMMAND, 103 "FINAL": TokenType.FINAL, 104 "FIXEDSTRING": TokenType.FIXEDSTRING, 105 "FLOAT32": TokenType.FLOAT, 106 "FLOAT64": TokenType.DOUBLE, 107 "GLOBAL": TokenType.GLOBAL, 108 "LOWCARDINALITY": TokenType.LOWCARDINALITY, 109 "MAP": TokenType.MAP, 110 "NESTED": TokenType.NESTED, 111 "NOTHING": TokenType.NOTHING, 112 "SAMPLE": TokenType.TABLE_SAMPLE, 113 "TUPLE": TokenType.STRUCT, 114 "UINT16": TokenType.USMALLINT, 115 "UINT32": TokenType.UINT, 116 "UINT64": TokenType.UBIGINT, 117 "UINT8": TokenType.UTINYINT, 118 "IPV4": TokenType.IPV4, 119 "IPV6": TokenType.IPV6, 120 "PASTE": TokenType.PASTE, 121 "POINT": TokenType.POINT, 122 "PROJECTION": TokenType.PROJECTION, 123 "RING": TokenType.RING, 124 "LINESTRING": TokenType.LINESTRING, 125 "MULTILINESTRING": TokenType.MULTILINESTRING, 126 "POLYGON": TokenType.POLYGON, 127 "MULTIPOLYGON": TokenType.MULTIPOLYGON, 128 "AGGREGATEFUNCTION": TokenType.AGGREGATEFUNCTION, 129 "SIMPLEAGGREGATEFUNCTION": TokenType.SIMPLEAGGREGATEFUNCTION, 130 "SYSTEM": TokenType.COMMAND, 131 "PREWHERE": TokenType.PREWHERE, 132 } 133 134 KEYWORDS.pop("/*+") 135 136 SINGLE_TOKENS = { 137 **tokens.Tokenizer.SINGLE_TOKENS, 138 "$": TokenType.HEREDOC_STRING, 139 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- UNICODE_STRINGS
- QUOTES
- VAR_SINGLE_TOKENS
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- DROP_UNKNOWN_ESCAPES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
16class Databricks(Spark): 17 SAFE_DIVISION = False 18 COPY_PARAMS_ARE_CSV = False 19 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 20 21 COERCES_TO = defaultdict(set, deepcopy(TypeAnnotator.COERCES_TO)) 22 for text_type in exp.DataType.TEXT_TYPES: 23 COERCES_TO[text_type] |= { 24 *exp.DataType.NUMERIC_TYPES, 25 *exp.DataType.TEMPORAL_TYPES, 26 exp.DType.BINARY, 27 exp.DType.BOOLEAN, 28 exp.DType.INTERVAL, 29 } 30 31 class JSONPathTokenizer(Spark.JSONPathTokenizer): 32 IDENTIFIERS = ["`", '"'] 33 34 class Tokenizer(Spark.Tokenizer): 35 KEYWORDS = { 36 **Spark.Tokenizer.KEYWORDS, 37 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 38 "STREAM": TokenType.STREAM, 39 "VOID": TokenType.VOID, 40 } 41 42 Parser = DatabricksParser 43 44 Generator = DatabricksGenerator
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- QUOTES
- VAR_SINGLE_TOKENS
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
34 class Tokenizer(Spark.Tokenizer): 35 KEYWORDS = { 36 **Spark.Tokenizer.KEYWORDS, 37 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 38 "STREAM": TokenType.STREAM, 39 "VOID": TokenType.VOID, 40 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- NUMERIC_ESCAPES_ARE_BYTES
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
10class DAX(Dialect): 11 DPIPE_IS_STRING_CONCAT = False 12 13 Generator = DAXGenerator 14 15 class Tokenizer(tokens.Tokenizer): 16 IDENTIFIERS = ["'", ("[", "]")] 17 QUOTES = ['"'] 18 STRING_ESCAPES = ['"'] 19 COMMENTS = ["--", "//", ("/*", "*/")] 20 21 Parser = DAXParser
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
15 class Tokenizer(tokens.Tokenizer): 16 IDENTIFIERS = ["'", ("[", "]")] 17 QUOTES = ['"'] 18 STRING_ESCAPES = ['"'] 19 COMMENTS = ["--", "//", ("/*", "*/")]
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- KEYWORDS
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
9class Doris(MySQL): 10 DATE_FORMAT = "'yyyy-MM-dd'" 11 DATEINT_FORMAT = "'yyyyMMdd'" 12 TIME_FORMAT = "'yyyy-MM-dd HH:mm:ss'" 13 14 class Tokenizer(MySQL.Tokenizer): 15 DASH_COMMENT_REQUIRES_BOUNDARY = False 16 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = False 17 18 Parser = DorisParser 19 20 Generator = DorisGenerator
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
14 class Tokenizer(MySQL.Tokenizer): 15 DASH_COMMENT_REQUIRES_BOUNDARY = False 16 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = False
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
10class Dremio(Dialect): 11 SUPPORTS_USER_DEFINED_TYPES = False 12 CONCAT_COALESCE = True 13 CONCAT_WS_COALESCE = True 14 TYPED_DIVISION = True 15 NULL_ORDERING = "nulls_are_last" 16 SUPPORTS_VALUES_DEFAULT = False 17 18 TIME_MAPPING = { 19 # year 20 "YYYY": "%Y", 21 "yyyy": "%Y", 22 "YY": "%y", 23 "yy": "%y", 24 # month / day 25 "MM": "%m", 26 "mm": "%m", 27 "MON": "%b", 28 "mon": "%b", 29 "MONTH": "%B", 30 "month": "%B", 31 "DDD": "%j", 32 "ddd": "%j", 33 "DD": "%d", 34 "dd": "%d", 35 "DY": "%a", 36 "dy": "%a", 37 "DAY": "%A", 38 "day": "%A", 39 # hours / minutes / seconds 40 "HH24": "%H", 41 "hh24": "%H", 42 "HH12": "%I", 43 "hh12": "%I", 44 "HH": "%I", 45 "hh": "%I", # 24- / 12-hour 46 "MI": "%M", 47 "mi": "%M", 48 "SS": "%S", 49 "ss": "%S", 50 "FFF": "%f", 51 "fff": "%f", 52 "AMPM": "%p", 53 "ampm": "%p", 54 # ISO week / century etc. 55 "WW": "%W", 56 "ww": "%W", 57 "D": "%w", 58 "d": "%w", 59 "CC": "%C", 60 "cc": "%C", 61 # timezone 62 "TZD": "%Z", 63 "tzd": "%Z", # abbreviation (UTC, PST, ...) 64 "TZO": "%z", 65 "tzo": "%z", # numeric offset (+0200) 66 } 67 68 class Tokenizer(tokens.Tokenizer): 69 COMMENTS = ["--", "//", ("/*", "*/")] 70 71 Parser = DremioParser 72 73 Generator = DremioGenerator
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Associates this dialect's time formats with their equivalent Python strftime formats.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- KEYWORDS
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
11class Drill(Dialect): 12 NORMALIZE_FUNCTIONS: bool | str = False 13 ORIGINAL_NAME_META_KEY = "drill_name" 14 NULL_ORDERING = "nulls_are_last" 15 DATE_FORMAT = "'yyyy-MM-dd'" 16 DATEINT_FORMAT = "'yyyyMMdd'" 17 TIME_FORMAT = "'yyyy-MM-dd HH:mm:ss'" 18 SUPPORTS_USER_DEFINED_TYPES = False 19 TYPED_DIVISION = True 20 CONCAT_COALESCE = True 21 CONCAT_WS_COALESCE = True 22 23 TIME_MAPPING = { 24 "y": "%Y", 25 "Y": "%Y", 26 "YYYY": "%Y", 27 "yyyy": "%Y", 28 "YY": "%y", 29 "yy": "%y", 30 "MMMM": "%B", 31 "MMM": "%b", 32 "MM": "%m", 33 "M": "%-m", 34 "dd": "%d", 35 "d": "%-d", 36 "HH": "%H", 37 "H": "%-H", 38 "hh": "%I", 39 "h": "%-I", 40 "mm": "%M", 41 "m": "%-M", 42 "ss": "%S", 43 "s": "%-S", 44 "SSSSSS": "%f", 45 "a": "%p", 46 "DD": "%j", 47 "D": "%-j", 48 "E": "%a", 49 "EE": "%a", 50 "EEE": "%a", 51 "EEEE": "%A", 52 "''T''": "T", 53 } 54 55 class Tokenizer(tokens.Tokenizer): 56 IDENTIFIERS = ["`"] 57 STRING_ESCAPES = ["'"] 58 59 KEYWORDS = tokens.Tokenizer.KEYWORDS.copy() 60 KEYWORDS.pop("/*+") 61 62 Parser = DrillParser 63 64 Generator = DrillGenerator
Determines how function names are going to be normalized.
Possible values:
"upper" or True: Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
Dialect-specific metadata key for preserving original function names, or None to disable. Only generators using the same key reuse these names, allowing round trips of aliases that share an AST node, e.g. JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery.
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Associates this dialect's time formats with their equivalent Python strftime formats.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
55 class Tokenizer(tokens.Tokenizer): 56 IDENTIFIERS = ["`"] 57 STRING_ESCAPES = ["'"] 58 59 KEYWORDS = tokens.Tokenizer.KEYWORDS.copy() 60 KEYWORDS.pop("/*+")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- QUOTES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
18class DuckDB(Dialect): 19 NULL_ORDERING = "nulls_are_last" 20 SUPPORTS_USER_DEFINED_TYPES = True 21 INDEX_OFFSET = 1 22 CONCAT_COALESCE = True 23 CONCAT_WS_COALESCE = True 24 SUPPORTS_ORDER_BY_ALL = True 25 SUPPORTS_LIMIT_ALL = True 26 SUPPORTS_FIXED_SIZE_ARRAYS = True 27 TABLES_REFERENCEABLE_AS_COLUMNS = True 28 QUERY_RESULTS_ARE_STRUCTS = True 29 STRICT_JSON_PATH_SYNTAX = False 30 NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = True 31 UUID_IS_STRING_TYPE = False 32 USING_COLUMN_ORDER = UsingColumnOrder.IN_PLACE 33 34 # https://duckdb.org/docs/sql/introduction.html#creating-a-new-table 35 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 36 ASCII_ONLY_NORMALIZATION = True 37 38 DATE_PART_MAPPING = { 39 **Dialect.DATE_PART_MAPPING, 40 "DAYOFWEEKISO": "ISODOW", 41 } 42 43 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 44 45 DATE_PART_MAPPING.pop("WEEKDAY") 46 47 INVERSE_TIME_MAPPING = { 48 "%e": "%-d", # BigQuery's space-padded day (%e) -> DuckDB's no-padding day (%-d) 49 "%:z": "%z", # In DuckDB %z can represent +/-HH:MM, +/-HHMM, or +/-HH. 50 "%-z": "%z", 51 "%f_zero": "%n", 52 "%f_one": "%n", 53 "%f_two": "%n", 54 "%f_three": "%g", 55 "%f_four": "%n", 56 "%f_five": "%n", 57 "%f_seven": "%n", 58 "%f_eight": "%n", 59 "%f_nine": "%n", 60 } 61 62 def to_json_path(self, path: exp.Expr | None) -> exp.Expr | None: 63 if isinstance(path, exp.Literal): 64 # DuckDB also supports the JSON pointer syntax, where every path starts with a `/`. 65 # Additionally, it allows accessing the back of lists using the `[#-i]` syntax. 66 # This check ensures we'll avoid trying to parse these as JSON paths, which can 67 # either result in a noisy warning or in an invalid representation of the path. 68 path_text = path.name 69 if path_text.startswith("/") or "[#" in path_text: 70 return path 71 72 return super().to_json_path(path) 73 74 UNESCAPED_SEQUENCES = {"\\a": "a", "\\v": "v"} 75 76 class Tokenizer(tokens.Tokenizer): 77 NUMERIC_ESCAPES = {"x": (16, 1, 2, 0xFF), "0": (8, 1, 3, 0o777)} 78 NUMERIC_ESCAPES_ARE_BYTES = True 79 DROP_UNKNOWN_ESCAPES = True 80 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 81 BYTE_STRING_ESCAPES = ["'", "\\"] 82 HEREDOC_STRINGS = ["$"] 83 84 HEREDOC_TAG_IS_IDENTIFIER = True 85 HEREDOC_STRING_ALTERNATIVE = TokenType.PARAMETER 86 87 KEYWORDS = { 88 **tokens.Tokenizer.KEYWORDS, 89 "//": TokenType.DIV, 90 "**": TokenType.DSTAR, 91 "^@": TokenType.CARET_AT, 92 "@>": TokenType.AT_GT, 93 "<@": TokenType.LT_AT, 94 "ATTACH": TokenType.ATTACH, 95 "BINARY": TokenType.VARBINARY, 96 "BITSTRING": TokenType.BIT, 97 "BPCHAR": TokenType.TEXT, 98 "CHAR": TokenType.TEXT, 99 "CONNECT": TokenType.CONNECT, 100 "DATETIME": TokenType.TIMESTAMPNTZ, 101 "DETACH": TokenType.DETACH, 102 "DISCONNECT": TokenType.DISCONNECT, 103 "FORCE": TokenType.FORCE, 104 "INSTALL": TokenType.INSTALL, 105 "INT8": TokenType.BIGINT, 106 "LOGICAL": TokenType.BOOLEAN, 107 "MACRO": TokenType.FUNCTION, 108 "ONLY": TokenType.ONLY, 109 "PIVOT_WIDER": TokenType.PIVOT, 110 "POSITIONAL": TokenType.POSITIONAL, 111 "RESET": TokenType.COMMAND, 112 "ROW": TokenType.STRUCT, 113 "SIGNED": TokenType.INT, 114 "STRING": TokenType.TEXT, 115 "SUMMARIZE": TokenType.SUMMARIZE, 116 "TIMESTAMP": TokenType.TIMESTAMPNTZ, 117 "TIMESTAMP_S": TokenType.TIMESTAMP_S, 118 "TIMESTAMP_MS": TokenType.TIMESTAMP_MS, 119 "TIMESTAMP_NS": TokenType.TIMESTAMP_NS, 120 "TIMESTAMP_US": TokenType.TIMESTAMP, 121 "UBIGINT": TokenType.UBIGINT, 122 "UINTEGER": TokenType.UINT, 123 "USMALLINT": TokenType.USMALLINT, 124 "UTINYINT": TokenType.UTINYINT, 125 "VARCHAR": TokenType.TEXT, 126 } 127 KEYWORDS.pop("/*+") 128 KEYWORDS.pop("SORT BY") 129 130 SINGLE_TOKENS = { 131 **tokens.Tokenizer.SINGLE_TOKENS, 132 "$": TokenType.PARAMETER, 133 } 134 135 VAR_SINGLE_TOKENS = {"$"} 136 137 COMMANDS = tokens.Tokenizer.COMMANDS - {TokenType.SHOW} 138 139 Parser = DuckDBParser 140 141 Generator = DuckDBGenerator
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether ORDER BY ALL is supported (expands to all the selected columns) as in DuckDB, Spark3/Databricks
Whether expressions such as x::INT[5] should be parsed as fixed-size array defs/casts e.g. in DuckDB. In dialects which don't support fixed size arrays such as Snowflake, this should be interpreted as a subscript/index operator.
Whether table names can be referenced as columns (treated as structs).
BigQuery allows tables to be referenced as columns in queries, automatically treating them as struct values containing all the table's columns.
For example, in BigQuery: SELECT t FROM my_table AS t -- Returns entire row as a struct
Whether query results are typed as structs in metadata for type inference.
In BigQuery, subqueries store their column types as a STRUCT in metadata,
enabling special type inference for ARRAY(SELECT ...) expressions:
ARRAY(SELECT x, y FROM t) → ARRAY For single column subqueries, BigQuery unwraps the struct:
ARRAY(SELECT x FROM t) → ARRAY This is metadata-only for type inference.
Whether failing to parse a JSON path expression using the JSONPath dialect will log a warning.
Whether number literals can include underscores for better readability
Where star expansion places the columns of a USING or NATURAL join.
Given a(a_id, k1, k2) and b(k2, b_id, k1), SELECT * FROM a JOIN b USING (k2, k1) returns:
USING_LIST:k2, k1, a_id, b_idLEFT_TABLE:k1, k2, a_id, b_idIN_PLACE:a_id, k1, k2, b_id
When join columns come first, this applies at every join: each USING join moves its columns ahead of all the columns to its left.
Specifies the strategy according to which identifiers should be normalized.
Whether identifiers are only normalized with respect to ASCII characters, e.g. Ä and
ä are different identifiers in DuckDB, but the same identifier in Spark.
62 def to_json_path(self, path: exp.Expr | None) -> exp.Expr | None: 63 if isinstance(path, exp.Literal): 64 # DuckDB also supports the JSON pointer syntax, where every path starts with a `/`. 65 # Additionally, it allows accessing the back of lists using the `[#-i]` syntax. 66 # This check ensures we'll avoid trying to parse these as JSON paths, which can 67 # either result in a noisy warning or in an invalid representation of the path. 68 path_text = path.name 69 if path_text.startswith("/") or "[#" in path_text: 70 return path 71 72 return super().to_json_path(path)
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
76 class Tokenizer(tokens.Tokenizer): 77 NUMERIC_ESCAPES = {"x": (16, 1, 2, 0xFF), "0": (8, 1, 3, 0o777)} 78 NUMERIC_ESCAPES_ARE_BYTES = True 79 DROP_UNKNOWN_ESCAPES = True 80 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 81 BYTE_STRING_ESCAPES = ["'", "\\"] 82 HEREDOC_STRINGS = ["$"] 83 84 HEREDOC_TAG_IS_IDENTIFIER = True 85 HEREDOC_STRING_ALTERNATIVE = TokenType.PARAMETER 86 87 KEYWORDS = { 88 **tokens.Tokenizer.KEYWORDS, 89 "//": TokenType.DIV, 90 "**": TokenType.DSTAR, 91 "^@": TokenType.CARET_AT, 92 "@>": TokenType.AT_GT, 93 "<@": TokenType.LT_AT, 94 "ATTACH": TokenType.ATTACH, 95 "BINARY": TokenType.VARBINARY, 96 "BITSTRING": TokenType.BIT, 97 "BPCHAR": TokenType.TEXT, 98 "CHAR": TokenType.TEXT, 99 "CONNECT": TokenType.CONNECT, 100 "DATETIME": TokenType.TIMESTAMPNTZ, 101 "DETACH": TokenType.DETACH, 102 "DISCONNECT": TokenType.DISCONNECT, 103 "FORCE": TokenType.FORCE, 104 "INSTALL": TokenType.INSTALL, 105 "INT8": TokenType.BIGINT, 106 "LOGICAL": TokenType.BOOLEAN, 107 "MACRO": TokenType.FUNCTION, 108 "ONLY": TokenType.ONLY, 109 "PIVOT_WIDER": TokenType.PIVOT, 110 "POSITIONAL": TokenType.POSITIONAL, 111 "RESET": TokenType.COMMAND, 112 "ROW": TokenType.STRUCT, 113 "SIGNED": TokenType.INT, 114 "STRING": TokenType.TEXT, 115 "SUMMARIZE": TokenType.SUMMARIZE, 116 "TIMESTAMP": TokenType.TIMESTAMPNTZ, 117 "TIMESTAMP_S": TokenType.TIMESTAMP_S, 118 "TIMESTAMP_MS": TokenType.TIMESTAMP_MS, 119 "TIMESTAMP_NS": TokenType.TIMESTAMP_NS, 120 "TIMESTAMP_US": TokenType.TIMESTAMP, 121 "UBIGINT": TokenType.UBIGINT, 122 "UINTEGER": TokenType.UINT, 123 "USMALLINT": TokenType.USMALLINT, 124 "UTINYINT": TokenType.UTINYINT, 125 "VARCHAR": TokenType.TEXT, 126 } 127 KEYWORDS.pop("/*+") 128 KEYWORDS.pop("SORT BY") 129 130 SINGLE_TOKENS = { 131 **tokens.Tokenizer.SINGLE_TOKENS, 132 "$": TokenType.PARAMETER, 133 } 134 135 VAR_SINGLE_TOKENS = {"$"} 136 137 COMMANDS = tokens.Tokenizer.COMMANDS - {TokenType.SHOW}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
10class Dune(Trino): 11 Parser = DuneParser 12 13 class Tokenizer(Trino.Tokenizer): 14 HEX_STRINGS = ["0x", ("X'", "'")] 15 16 Generator = DuneGenerator
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
15class Exasol(Dialect): 16 # https://docs.exasol.com/db/latest/sql_references/basiclanguageelements.htm#SQLidentifier 17 NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE 18 # https://docs.exasol.com/db/latest/sql_references/data_types/datatypesoverview.htm 19 SUPPORTS_USER_DEFINED_TYPES = False 20 # https://docs.exasol.com/db/latest/sql/select.htm 21 SUPPORTS_COLUMN_JOIN_MARKS = True 22 NULL_ORDERING = "nulls_are_last" 23 # https://docs.exasol.com/db/latest/sql_references/literals.htm#StringLiterals 24 CONCAT_COALESCE = True 25 26 TIME_MAPPING = { 27 "yyyy": "%Y", 28 "YYYY": "%Y", 29 "yy": "%y", 30 "YY": "%y", 31 "mm": "%m", 32 "MM": "%m", 33 "MONTH": "%B", 34 "MON": "%b", 35 "dd": "%d", 36 "DD": "%d", 37 "DAY": "%A", 38 "DY": "%a", 39 "H12": "%I", 40 "H24": "%H", 41 "HH": "%H", 42 "ID": "%u", 43 "vW": "%V", 44 "IW": "%V", 45 "vYYY": "%G", 46 "IYYY": "%G", 47 "MI": "%M", 48 "SS": "%S", 49 "uW": "%W", 50 "UW": "%U", 51 "Z": "%z", 52 } 53 54 class Tokenizer(tokens.Tokenizer): 55 IDENTIFIERS = ['"', ("[", "]")] 56 KEYWORDS = { 57 **tokens.Tokenizer.KEYWORDS, 58 "USER": TokenType.CURRENT_USER, 59 # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/if.htm 60 "ENDIF": TokenType.END, 61 "LONG VARCHAR": TokenType.TEXT, 62 "REGEXP_LIKE": TokenType.RLIKE, 63 "SEPARATOR": TokenType.SEPARATOR, 64 "SYSTIMESTAMP": TokenType.SYSTIMESTAMP, 65 "MINUS": TokenType.EXCEPT, 66 } 67 KEYWORDS.pop("DIV") 68 69 Parser = ExasolParser 70 71 Generator = ExasolGenerator
Specifies the strategy according to which identifiers should be normalized.
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
Associates this dialect's time formats with their equivalent Python strftime formats.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
54 class Tokenizer(tokens.Tokenizer): 55 IDENTIFIERS = ['"', ("[", "]")] 56 KEYWORDS = { 57 **tokens.Tokenizer.KEYWORDS, 58 "USER": TokenType.CURRENT_USER, 59 # https://docs.exasol.com/db/latest/sql_references/functions/alphabeticallistfunctions/if.htm 60 "ENDIF": TokenType.END, 61 "LONG VARCHAR": TokenType.TEXT, 62 "REGEXP_LIKE": TokenType.RLIKE, 63 "SEPARATOR": TokenType.SEPARATOR, 64 "SYSTIMESTAMP": TokenType.SYSTIMESTAMP, 65 "MINUS": TokenType.EXCEPT, 66 } 67 KEYWORDS.pop("DIV")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
12class Fabric(TSQL): 13 """ 14 Microsoft Fabric Data Warehouse dialect that inherits from T-SQL. 15 16 Microsoft Fabric is a cloud-based analytics platform that provides a unified 17 data warehouse experience. While it shares much of T-SQL's syntax, it has 18 specific differences and limitations that this dialect addresses. 19 20 Key differences from T-SQL: 21 - Case-sensitive identifiers (unlike T-SQL which is case-insensitive) 22 - Limited data type support with mappings to supported alternatives 23 - Temporal types (DATETIME2, DATETIMEOFFSET, TIME) limited to 6 digits precision 24 - Certain legacy types (MONEY, SMALLMONEY, etc.) are not supported 25 - Unicode types (NCHAR, NVARCHAR) are mapped to non-unicode equivalents 26 27 References: 28 - Data Types: https://learn.microsoft.com/en-us/fabric/data-warehouse/data-types 29 - T-SQL Surface Area: https://learn.microsoft.com/en-us/fabric/data-warehouse/tsql-surface-area 30 """ 31 32 # Fabric is case-sensitive unlike T-SQL which is case-insensitive 33 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_SENSITIVE 34 35 class Tokenizer(TSQL.Tokenizer): 36 # Override T-SQL tokenizer to handle TIMESTAMP differently 37 # In T-SQL, TIMESTAMP is a synonym for ROWVERSION, but in Fabric we want it to be a datetime type 38 # Also add UTINYINT keyword mapping since T-SQL doesn't have it 39 KEYWORDS = { 40 **TSQL.Tokenizer.KEYWORDS, 41 "TIMESTAMP": TokenType.TIMESTAMP, 42 "UTINYINT": TokenType.UTINYINT, 43 } 44 45 Parser = FabricParser 46 47 Generator = FabricGenerator
Microsoft Fabric Data Warehouse dialect that inherits from T-SQL.
Microsoft Fabric is a cloud-based analytics platform that provides a unified data warehouse experience. While it shares much of T-SQL's syntax, it has specific differences and limitations that this dialect addresses.
Key differences from T-SQL:
- Case-sensitive identifiers (unlike T-SQL which is case-insensitive)
- Limited data type support with mappings to supported alternatives
- Temporal types (DATETIME2, DATETIMEOFFSET, TIME) limited to 6 digits precision
- Certain legacy types (MONEY, SMALLMONEY, etc.) are not supported
- Unicode types (NCHAR, NVARCHAR) are mapped to non-unicode equivalents
References:
Specifies the strategy according to which identifiers should be normalized.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
- TSQL
- WEEK_OFFSET
- LOG_BASE_FIRST
- TYPED_DIVISION
- CONCAT_COALESCE
- CONCAT_WS_COALESCE
- JSON_EXTRACT_SCALAR_SCALAR_ONLY
- ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN
- ALTER_TABLE_DROP_REQUIRED_FOR_EACH_COLUMN
- TIME_FORMAT
- EXPRESSION_METADATA
- DATE_PART_MAPPING
- TIME_MAPPING
- CONVERT_FORMAT_MAPPING
- FORMAT_TIME_MAPPING
35 class Tokenizer(TSQL.Tokenizer): 36 # Override T-SQL tokenizer to handle TIMESTAMP differently 37 # In T-SQL, TIMESTAMP is a synonym for ROWVERSION, but in Fabric we want it to be a datetime type 38 # Also add UTINYINT keyword mapping since T-SQL doesn't have it 39 KEYWORDS = { 40 **TSQL.Tokenizer.KEYWORDS, 41 "TIMESTAMP": TokenType.TIMESTAMP, 42 "UTINYINT": TokenType.UTINYINT, 43 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
19class Hive(Dialect): 20 ALIAS_POST_TABLESAMPLE = True 21 IDENTIFIERS_CAN_START_WITH_DIGIT = True 22 SUPPORTS_USER_DEFINED_TYPES = False 23 SAFE_DIVISION = True 24 CONCAT_WS_COALESCE = True 25 ARRAY_AGG_INCLUDES_NULLS = None 26 REGEXP_EXTRACT_DEFAULT_GROUP = 1 27 ALTER_TABLE_SUPPORTS_CASCADE = True 28 INTERSECT_BINDS_TIGHTER_THAN_UNION_AND_EXCEPT = False 29 30 # https://spark.apache.org/docs/latest/sql-ref-identifier.html#description 31 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 32 33 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 34 35 # https://cwiki.apache.org/confluence/pages/viewpage.action?pageId=27362046#LanguageManualUDF-StringFunctions 36 # https://github.com/apache/hive/blob/master/ql/src/java/org/apache/hadoop/hive/ql/exec/Utilities.java#L266-L269 37 INITCAP_DEFAULT_DELIMITER_CHARS = " \t\n\r\f\u000b\u001c\u001d\u001e\u001f" 38 39 # Support only the non-ANSI mode (default for Hive, Spark2, Spark) 40 COERCES_TO = defaultdict(set, deepcopy(TypeAnnotator.COERCES_TO)) 41 for target_type in { 42 *exp.DataType.NUMERIC_TYPES, 43 *exp.DataType.TEMPORAL_TYPES, 44 exp.DType.INTERVAL, 45 }: 46 COERCES_TO[target_type] |= exp.DataType.TEXT_TYPES 47 48 TIME_MAPPING = { 49 "y": "%Y", 50 "Y": "%Y", 51 "YYYY": "%Y", 52 "yyyy": "%Y", 53 "YY": "%y", 54 "yy": "%y", 55 "MMMM": "%B", 56 "MMM": "%b", 57 # Hive 4.0+ parses MM/dd/HH/hh/mm/ss strictly (java.time.DateTimeFormatter, see 58 # HIVE-25458/HIVE-25576) 59 "MM": "%mstrict", 60 "M": "%-m", 61 "dd": "%dstrict", 62 "d": "%-d", 63 "HH": "%Hstrict", 64 "H": "%-H", 65 "hh": "%Istrict", 66 "h": "%-I", 67 "mm": "%Mstrict", 68 "m": "%-M", 69 "ss": "%Sstrict", 70 "s": "%-S", 71 "SSSSSS": "%f", 72 "a": "%p", 73 "DD": "%j", 74 "D": "%-j", 75 "E": "%a", 76 "EE": "%a", 77 "EEE": "%a", 78 "EEEE": "%A", 79 "z": "%Z", 80 "Z": "%z", 81 } 82 83 DATE_FORMAT = "'yyyy-MM-dd'" 84 DATEINT_FORMAT = "'yyyyMMdd'" 85 TIME_FORMAT = "'yyyy-MM-dd HH:mm:ss'" 86 87 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 88 VAR_TOKENS = { 89 *jsonpath.JSONPathTokenizer.VAR_TOKENS, 90 TokenType.DASH, 91 } 92 93 UNESCAPED_SEQUENCES = { 94 "\\0": "\0", 95 "\\Z": "\x1a", 96 "\\%": "\\%", 97 "\\_": "\\_", 98 "\\a": "a", 99 "\\f": "f", 100 "\\v": "v", 101 } 102 103 class Tokenizer(tokens.Tokenizer): 104 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "0": (8, 3, 3, 0x7F)} 105 DROP_UNKNOWN_ESCAPES = True 106 LONE_SURROGATE_REPLACEMENT = "?" 107 QUOTES = ["'", '"'] 108 IDENTIFIERS = ["`"] 109 STRING_ESCAPES = ["\\"] 110 111 SINGLE_TOKENS = { 112 **tokens.Tokenizer.SINGLE_TOKENS, 113 "$": TokenType.PARAMETER, 114 } 115 116 KEYWORDS = { 117 **tokens.Tokenizer.KEYWORDS, 118 "ADD ARCHIVE": TokenType.COMMAND, 119 "ADD ARCHIVES": TokenType.COMMAND, 120 "ADD FILE": TokenType.COMMAND, 121 "ADD FILES": TokenType.COMMAND, 122 "ADD JAR": TokenType.COMMAND, 123 "ADD JARS": TokenType.COMMAND, 124 "MINUS": TokenType.EXCEPT, 125 "MSCK REPAIR": TokenType.COMMAND, 126 "REFRESH": TokenType.REFRESH, 127 "SERDEPROPERTIES": TokenType.SERDE_PROPERTIES, 128 } 129 130 NUMERIC_LITERALS = { 131 "L": "BIGINT", 132 "S": "SMALLINT", 133 "Y": "TINYINT", 134 "D": "DOUBLE", 135 "F": "FLOAT", 136 "BD": "DECIMAL", 137 } 138 139 Parser = HiveParser 140 141 Generator = HiveGenerator
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Hive by default does not update the schema of existing partitions when a column is changed. the CASCADE clause is used to indicate that the change should be propagated to all existing partitions. the Spark dialect, while derived from Hive, does not support the CASCADE clause.
Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't parenthesized. If False, all set operations have equal precedence and associate left to right.
Specifies the strategy according to which identifiers should be normalized.
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
87 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 88 VAR_TOKENS = { 89 *jsonpath.JSONPathTokenizer.VAR_TOKENS, 90 TokenType.DASH, 91 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- VAR_SINGLE_TOKENS
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
103 class Tokenizer(tokens.Tokenizer): 104 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "0": (8, 3, 3, 0x7F)} 105 DROP_UNKNOWN_ESCAPES = True 106 LONE_SURROGATE_REPLACEMENT = "?" 107 QUOTES = ["'", '"'] 108 IDENTIFIERS = ["`"] 109 STRING_ESCAPES = ["\\"] 110 111 SINGLE_TOKENS = { 112 **tokens.Tokenizer.SINGLE_TOKENS, 113 "$": TokenType.PARAMETER, 114 } 115 116 KEYWORDS = { 117 **tokens.Tokenizer.KEYWORDS, 118 "ADD ARCHIVE": TokenType.COMMAND, 119 "ADD ARCHIVES": TokenType.COMMAND, 120 "ADD FILE": TokenType.COMMAND, 121 "ADD FILES": TokenType.COMMAND, 122 "ADD JAR": TokenType.COMMAND, 123 "ADD JARS": TokenType.COMMAND, 124 "MINUS": TokenType.EXCEPT, 125 "MSCK REPAIR": TokenType.COMMAND, 126 "REFRESH": TokenType.REFRESH, 127 "SERDEPROPERTIES": TokenType.SERDE_PROPERTIES, 128 } 129 130 NUMERIC_LITERALS = { 131 "L": "BIGINT", 132 "S": "SMALLINT", 133 "Y": "TINYINT", 134 "D": "DOUBLE", 135 "F": "FLOAT", 136 "BD": "DECIMAL", 137 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES_ARE_BYTES
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
9class Materialize(Postgres): 10 NORMALIZE_NOT_NULL = True 11 12 UNESCAPED_SEQUENCES = {"\\a": "a", "\\v": "v"} 13 14 class Tokenizer(Postgres.Tokenizer): 15 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "U": (16, 8, 8, 0x10FFFF)} 16 17 Parser = MaterializeParser 18 19 Generator = MaterializeGenerator
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
14 class Tokenizer(Postgres.Tokenizer): 15 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "U": (16, 8, 8, 0x10FFFF)}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
16class MySQL(Dialect): 17 PROMOTE_TO_INFERRED_DATETIME_TYPE = True 18 USING_COLUMN_ORDER = UsingColumnOrder.LEFT_TABLE 19 20 # https://dev.mysql.com/doc/refman/8.0/en/identifiers.html 21 IDENTIFIERS_CAN_START_WITH_DIGIT = True 22 23 # We default to treating all identifiers as case-sensitive, since it matches MySQL's 24 # behavior on Linux systems. For MacOS and Windows systems, one can override this 25 # setting by specifying `dialect="mysql, normalization_strategy = lowercase"`. 26 # 27 # See also https://dev.mysql.com/doc/refman/8.2/en/identifier-case-sensitivity.html 28 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_SENSITIVE 29 30 TIME_FORMAT = "'%Y-%m-%d %T'" 31 DPIPE_IS_STRING_CONCAT = False 32 CONCAT_WS_COALESCE = True 33 SUPPORTS_USER_DEFINED_TYPES = False 34 SAFE_DIVISION = True 35 SAFE_TO_ELIMINATE_DOUBLE_NEGATION = False 36 LEAST_GREATEST_IGNORES_NULLS = False 37 38 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 39 40 # https://prestodb.io/docs/current/functions/datetime.html#mysql-date-functions 41 TIME_MAPPING = { 42 "%M": "%B", 43 "%c": "%-m", 44 "%e": "%-d", 45 "%h": "%I", 46 "%i": "%M", 47 "%s": "%S", 48 "%u": "%W", 49 "%k": "%-H", 50 "%l": "%-I", 51 "%r": "%I:%M:%S %p", 52 "%T": "%H:%M:%S", 53 "%W": "%A", 54 "%x": "%G", 55 # %v (ISO week) is unmapped due to collision with %V (roundtrip issue) 56 } 57 58 VALID_INTERVAL_UNITS = { 59 *Dialect.VALID_INTERVAL_UNITS, 60 "SECOND_MICROSECOND", 61 "MINUTE_MICROSECOND", 62 "MINUTE_SECOND", 63 "HOUR_MICROSECOND", 64 "HOUR_SECOND", 65 "HOUR_MINUTE", 66 "DAY_MICROSECOND", 67 "DAY_SECOND", 68 "DAY_MINUTE", 69 "DAY_HOUR", 70 "YEAR_MONTH", 71 } 72 73 UNESCAPED_SEQUENCES = { 74 "\\0": "\0", 75 "\\Z": "\x1a", 76 "\\%": "\\%", 77 "\\_": "\\_", 78 "\\a": "a", 79 "\\f": "f", 80 "\\v": "v", 81 } 82 83 class Tokenizer(tokens.Tokenizer): 84 QUOTES = ["'", '"'] 85 COMMENTS = ["--", "#", ("/*", "*/")] 86 IDENTIFIERS = ["`"] 87 STRING_ESCAPES = ["'", '"', "\\"] 88 BIT_STRINGS = [("b'", "'"), ("B'", "'"), ("0b", "")] 89 HEX_STRINGS = [("x'", "'"), ("X'", "'"), ("0x", "")] 90 # https://dev.mysql.com/doc/refman/8.4/en/string-literals.html 91 DROP_UNKNOWN_ESCAPES = True 92 93 NESTED_COMMENTS = False 94 DASH_COMMENT_REQUIRES_BOUNDARY = True 95 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 96 97 KEYWORDS = { 98 **tokens.Tokenizer.KEYWORDS, 99 "BLOB": TokenType.BLOB, 100 "CHARSET": TokenType.CHARACTER_SET, 101 "DISTINCTROW": TokenType.DISTINCT, 102 "EXPLAIN": TokenType.DESCRIBE, 103 "FORCE": TokenType.FORCE, 104 "IGNORE": TokenType.IGNORE, 105 "KEY": TokenType.KEY, 106 "LOCK TABLES": TokenType.COMMAND, 107 "LONGBLOB": TokenType.LONGBLOB, 108 "LONGTEXT": TokenType.LONGTEXT, 109 "MEDIUMBLOB": TokenType.MEDIUMBLOB, 110 "MEDIUMINT": TokenType.MEDIUMINT, 111 "MEDIUMTEXT": TokenType.MEDIUMTEXT, 112 "MEMBER OF": TokenType.MEMBER_OF, 113 "MOD": TokenType.MOD, 114 "SEPARATOR": TokenType.SEPARATOR, 115 "SERIAL": TokenType.SERIAL, 116 "SIGNED": TokenType.BIGINT, 117 "SIGNED INTEGER": TokenType.BIGINT, 118 "START": TokenType.BEGIN, 119 "TIMESTAMP": TokenType.TIMESTAMPTZ, 120 "TINYBLOB": TokenType.TINYBLOB, 121 "TINYTEXT": TokenType.TINYTEXT, 122 "UNLOCK TABLES": TokenType.COMMAND, 123 "UNSIGNED": TokenType.UBIGINT, 124 "UNSIGNED INTEGER": TokenType.UBIGINT, 125 "YEAR": TokenType.YEAR, 126 "_ARMSCII8": TokenType.INTRODUCER, 127 "_ASCII": TokenType.INTRODUCER, 128 "_BIG5": TokenType.INTRODUCER, 129 "_BINARY": TokenType.INTRODUCER, 130 "_CP1250": TokenType.INTRODUCER, 131 "_CP1251": TokenType.INTRODUCER, 132 "_CP1256": TokenType.INTRODUCER, 133 "_CP1257": TokenType.INTRODUCER, 134 "_CP850": TokenType.INTRODUCER, 135 "_CP852": TokenType.INTRODUCER, 136 "_CP866": TokenType.INTRODUCER, 137 "_CP932": TokenType.INTRODUCER, 138 "_DEC8": TokenType.INTRODUCER, 139 "_EUCJPMS": TokenType.INTRODUCER, 140 "_EUCKR": TokenType.INTRODUCER, 141 "_GB18030": TokenType.INTRODUCER, 142 "_GB2312": TokenType.INTRODUCER, 143 "_GBK": TokenType.INTRODUCER, 144 "_GEOSTD8": TokenType.INTRODUCER, 145 "_GREEK": TokenType.INTRODUCER, 146 "_HEBREW": TokenType.INTRODUCER, 147 "_HP8": TokenType.INTRODUCER, 148 "_KEYBCS2": TokenType.INTRODUCER, 149 "_KOI8R": TokenType.INTRODUCER, 150 "_KOI8U": TokenType.INTRODUCER, 151 "_LATIN1": TokenType.INTRODUCER, 152 "_LATIN2": TokenType.INTRODUCER, 153 "_LATIN5": TokenType.INTRODUCER, 154 "_LATIN7": TokenType.INTRODUCER, 155 "_MACCE": TokenType.INTRODUCER, 156 "_MACROMAN": TokenType.INTRODUCER, 157 "_SJIS": TokenType.INTRODUCER, 158 "_SWE7": TokenType.INTRODUCER, 159 "_TIS620": TokenType.INTRODUCER, 160 "_UCS2": TokenType.INTRODUCER, 161 "_UJIS": TokenType.INTRODUCER, 162 # https://dev.mysql.com/doc/refman/8.0/en/string-literals.html 163 "_UTF8": TokenType.INTRODUCER, 164 "_UTF16": TokenType.INTRODUCER, 165 "_UTF16LE": TokenType.INTRODUCER, 166 "_UTF32": TokenType.INTRODUCER, 167 "_UTF8MB3": TokenType.INTRODUCER, 168 "_UTF8MB4": TokenType.INTRODUCER, 169 "@@": TokenType.SESSION_PARAMETER, 170 } 171 172 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.REPLACE} - {TokenType.SHOW} 173 174 Parser = MySQLParser 175 176 Generator = MySQLGenerator
This flag is used in the optimizer's canonicalize rule and determines whether x will be promoted to the literal's type in x::DATE < '2020-01-01 12:05:03' (i.e., DATETIME). When false, the literal is cast to x's type to match it instead.
Where star expansion places the columns of a USING or NATURAL join.
Given a(a_id, k1, k2) and b(k2, b_id, k1), SELECT * FROM a JOIN b USING (k2, k1) returns:
USING_LIST:k2, k1, a_id, b_idLEFT_TABLE:k1, k2, a_id, b_idIN_PLACE:a_id, k1, k2, b_id
When join columns come first, this applies at every join: each USING join moves its columns ahead of all the columns to its left.
Specifies the strategy according to which identifiers should be normalized.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether LEAST/GREATEST functions ignore NULL values, e.g:
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
83 class Tokenizer(tokens.Tokenizer): 84 QUOTES = ["'", '"'] 85 COMMENTS = ["--", "#", ("/*", "*/")] 86 IDENTIFIERS = ["`"] 87 STRING_ESCAPES = ["'", '"', "\\"] 88 BIT_STRINGS = [("b'", "'"), ("B'", "'"), ("0b", "")] 89 HEX_STRINGS = [("x'", "'"), ("X'", "'"), ("0x", "")] 90 # https://dev.mysql.com/doc/refman/8.4/en/string-literals.html 91 DROP_UNKNOWN_ESCAPES = True 92 93 NESTED_COMMENTS = False 94 DASH_COMMENT_REQUIRES_BOUNDARY = True 95 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 96 97 KEYWORDS = { 98 **tokens.Tokenizer.KEYWORDS, 99 "BLOB": TokenType.BLOB, 100 "CHARSET": TokenType.CHARACTER_SET, 101 "DISTINCTROW": TokenType.DISTINCT, 102 "EXPLAIN": TokenType.DESCRIBE, 103 "FORCE": TokenType.FORCE, 104 "IGNORE": TokenType.IGNORE, 105 "KEY": TokenType.KEY, 106 "LOCK TABLES": TokenType.COMMAND, 107 "LONGBLOB": TokenType.LONGBLOB, 108 "LONGTEXT": TokenType.LONGTEXT, 109 "MEDIUMBLOB": TokenType.MEDIUMBLOB, 110 "MEDIUMINT": TokenType.MEDIUMINT, 111 "MEDIUMTEXT": TokenType.MEDIUMTEXT, 112 "MEMBER OF": TokenType.MEMBER_OF, 113 "MOD": TokenType.MOD, 114 "SEPARATOR": TokenType.SEPARATOR, 115 "SERIAL": TokenType.SERIAL, 116 "SIGNED": TokenType.BIGINT, 117 "SIGNED INTEGER": TokenType.BIGINT, 118 "START": TokenType.BEGIN, 119 "TIMESTAMP": TokenType.TIMESTAMPTZ, 120 "TINYBLOB": TokenType.TINYBLOB, 121 "TINYTEXT": TokenType.TINYTEXT, 122 "UNLOCK TABLES": TokenType.COMMAND, 123 "UNSIGNED": TokenType.UBIGINT, 124 "UNSIGNED INTEGER": TokenType.UBIGINT, 125 "YEAR": TokenType.YEAR, 126 "_ARMSCII8": TokenType.INTRODUCER, 127 "_ASCII": TokenType.INTRODUCER, 128 "_BIG5": TokenType.INTRODUCER, 129 "_BINARY": TokenType.INTRODUCER, 130 "_CP1250": TokenType.INTRODUCER, 131 "_CP1251": TokenType.INTRODUCER, 132 "_CP1256": TokenType.INTRODUCER, 133 "_CP1257": TokenType.INTRODUCER, 134 "_CP850": TokenType.INTRODUCER, 135 "_CP852": TokenType.INTRODUCER, 136 "_CP866": TokenType.INTRODUCER, 137 "_CP932": TokenType.INTRODUCER, 138 "_DEC8": TokenType.INTRODUCER, 139 "_EUCJPMS": TokenType.INTRODUCER, 140 "_EUCKR": TokenType.INTRODUCER, 141 "_GB18030": TokenType.INTRODUCER, 142 "_GB2312": TokenType.INTRODUCER, 143 "_GBK": TokenType.INTRODUCER, 144 "_GEOSTD8": TokenType.INTRODUCER, 145 "_GREEK": TokenType.INTRODUCER, 146 "_HEBREW": TokenType.INTRODUCER, 147 "_HP8": TokenType.INTRODUCER, 148 "_KEYBCS2": TokenType.INTRODUCER, 149 "_KOI8R": TokenType.INTRODUCER, 150 "_KOI8U": TokenType.INTRODUCER, 151 "_LATIN1": TokenType.INTRODUCER, 152 "_LATIN2": TokenType.INTRODUCER, 153 "_LATIN5": TokenType.INTRODUCER, 154 "_LATIN7": TokenType.INTRODUCER, 155 "_MACCE": TokenType.INTRODUCER, 156 "_MACROMAN": TokenType.INTRODUCER, 157 "_SJIS": TokenType.INTRODUCER, 158 "_SWE7": TokenType.INTRODUCER, 159 "_TIS620": TokenType.INTRODUCER, 160 "_UCS2": TokenType.INTRODUCER, 161 "_UJIS": TokenType.INTRODUCER, 162 # https://dev.mysql.com/doc/refman/8.0/en/string-literals.html 163 "_UTF8": TokenType.INTRODUCER, 164 "_UTF16": TokenType.INTRODUCER, 165 "_UTF16LE": TokenType.INTRODUCER, 166 "_UTF32": TokenType.INTRODUCER, 167 "_UTF8MB3": TokenType.INTRODUCER, 168 "_UTF8MB4": TokenType.INTRODUCER, 169 "@@": TokenType.SESSION_PARAMETER, 170 } 171 172 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.REPLACE} - {TokenType.SHOW}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
17class Oracle(Dialect): 18 ALIAS_POST_TABLESAMPLE = True 19 LOCKING_READS_SUPPORTED = True 20 TABLESAMPLE_SIZE_IS_PERCENT = True 21 NULL_ORDERING = "nulls_are_large" 22 ON_CONDITION_EMPTY_BEFORE_ERROR = False 23 ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False 24 DISABLES_ALIAS_REF_EXPANSION = True 25 INTERSECT_BINDS_TIGHTER_THAN_UNION_AND_EXCEPT = False 26 27 # See section 8: https://docs.oracle.com/cd/A97630_01/server.920/a96540/sql_elements9a.htm 28 NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE 29 30 # https://docs.oracle.com/database/121/SQLRF/sql_elements004.htm#SQLRF00212 31 # https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes 32 TIME_MAPPING = { 33 "D": "%u", # Day of week (1-7) 34 "DAY": "%A", # name of day 35 "DD": "%d", # day of month (1-31) 36 "DDD": "%j", # day of year (1-366) 37 "DY": "%a", # abbreviated name of day 38 "HH": "%I", # Hour of day (1-12) 39 "HH12": "%I", # alias for HH 40 "HH24": "%H", # Hour of day (0-23) 41 "IW": "%V", # Calendar week of year (1-52 or 1-53), as defined by the ISO 8601 standard 42 "IYYY": "%G", # 4-digit year of the ISO 8601 week-numbering calendar 43 "MI": "%M", # Minute (0-59) 44 "MM": "%m", # Month (01-12; January = 01) 45 "MON": "%b", # Abbreviated name of month 46 "MONTH": "%B", # Name of month 47 "SS": "%S", # Second (0-59) 48 "WW": "%W", # Week of year (1-53) 49 "YY": "%y", # 15 50 "YYYY": "%Y", # 2015 51 "FF6": "%f", # only 6 digits are supported in python formats 52 } 53 54 PSEUDOCOLUMNS = {"ROWNUM", "ROWID", "OBJECT_ID", "OBJECT_VALUE", "LEVEL"} 55 56 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 57 # Disable quoting for pseudocolumns as it may break queries e.g 58 # `WHERE "ROWNUM" = ...` does not work but `WHERE ROWNUM = ...` does 59 return ( 60 identifier.quoted or not isinstance(identifier.parent, exp.Pseudocolumn) 61 ) and super().can_quote(identifier, identify=identify) 62 63 class Tokenizer(tokens.Tokenizer): 64 VAR_SINGLE_TOKENS = {"@", "$", "#"} 65 66 UNICODE_STRINGS = [ 67 (prefix + q, q) 68 for q in t.cast(list[str], tokens.Tokenizer.QUOTES) 69 for prefix in ("U", "u") 70 ] 71 72 # https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Literals.html 73 # Alternative quoting, e.g. q'[it's]': the delimiters are part of the quote, so the 74 # text in between is taken as is, without escapes 75 RAW_STRINGS = [ 76 (f"{prefix}'{start}", f"{end}'") 77 for prefix in ("q", "Q") 78 for start, end in ( 79 ("[", "]"), 80 ("{", "}"), 81 ("(", ")"), 82 ("<", ">"), 83 *( 84 (c, c) 85 for c in string.ascii_letters + string.digits + string.punctuation 86 if c not in "[{(<" 87 ), 88 ) 89 ] 90 NATIONAL_RAW_STRINGS = [ 91 (prefix + start, end) 92 for start, end in t.cast(list[tuple[str, str]], RAW_STRINGS) 93 for prefix in ("n", "N") 94 ] 95 STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS = False 96 97 NESTED_COMMENTS = False 98 99 KEYWORDS = { 100 **tokens.Tokenizer.KEYWORDS, 101 "(+)": TokenType.JOIN_MARKER, 102 # https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Comparison-Conditions.html 103 "^=": TokenType.NEQ, 104 "BINARY_DOUBLE": TokenType.DOUBLE, 105 "BINARY_FLOAT": TokenType.FLOAT, 106 "BULK COLLECT INTO": TokenType.BULK_COLLECT_INTO, 107 "COLUMNS": TokenType.COLUMN, 108 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 109 "MINUS": TokenType.EXCEPT, 110 "NVARCHAR2": TokenType.NVARCHAR, 111 "ORDER SIBLINGS BY": TokenType.ORDER_SIBLINGS_BY, 112 "SAMPLE": TokenType.TABLE_SAMPLE, 113 "START": TokenType.BEGIN, 114 "SUBPARTITION": TokenType.PARTITION, 115 "TOP": TokenType.TOP, 116 "VARCHAR2": TokenType.VARCHAR, 117 "SYSTIMESTAMP": TokenType.SYSTIMESTAMP, 118 } 119 120 Parser = OracleParser 121 122 Generator = OracleGenerator
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether "X ON EMPTY" should come before "X ON ERROR" (for dialects like T-SQL, MySQL, Oracle).
Whether alias reference expansion is disabled for this dialect.
Some dialects like Oracle do NOT support referencing aliases in projections or WHERE clauses. The original expression must be repeated instead.
For example, in Oracle: SELECT y.foo AS bar, bar * 2 AS baz FROM y -- INVALID SELECT y.foo AS bar, y.foo * 2 AS baz FROM y -- VALID
Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't parenthesized. If False, all set operations have equal precedence and associate left to right.
Specifies the strategy according to which identifiers should be normalized.
Associates this dialect's time formats with their equivalent Python strftime formats.
Columns that are auto-generated by the engine corresponding to this dialect.
For example, such columns may be excluded from SELECT * queries.
56 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 57 # Disable quoting for pseudocolumns as it may break queries e.g 58 # `WHERE "ROWNUM" = ...` does not work but `WHERE ROWNUM = ...` does 59 return ( 60 identifier.quoted or not isinstance(identifier.parent, exp.Pseudocolumn) 61 ) and super().can_quote(identifier, identify=identify)
Checks if an identifier can be quoted
Arguments:
- identifier: The identifier to check.
- identify:
True: Always returnsTrueexcept for certain cases."safe": Only returnsTrueif the identifier is case-insensitive."unsafe": Only returnsTrueif the identifier is case-sensitive.
Returns:
Whether the given text can be identified.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
63 class Tokenizer(tokens.Tokenizer): 64 VAR_SINGLE_TOKENS = {"@", "$", "#"} 65 66 UNICODE_STRINGS = [ 67 (prefix + q, q) 68 for q in t.cast(list[str], tokens.Tokenizer.QUOTES) 69 for prefix in ("U", "u") 70 ] 71 72 # https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Literals.html 73 # Alternative quoting, e.g. q'[it's]': the delimiters are part of the quote, so the 74 # text in between is taken as is, without escapes 75 RAW_STRINGS = [ 76 (f"{prefix}'{start}", f"{end}'") 77 for prefix in ("q", "Q") 78 for start, end in ( 79 ("[", "]"), 80 ("{", "}"), 81 ("(", ")"), 82 ("<", ">"), 83 *( 84 (c, c) 85 for c in string.ascii_letters + string.digits + string.punctuation 86 if c not in "[{(<" 87 ), 88 ) 89 ] 90 NATIONAL_RAW_STRINGS = [ 91 (prefix + start, end) 92 for start, end in t.cast(list[tuple[str, str]], RAW_STRINGS) 93 for prefix in ("n", "N") 94 ] 95 STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS = False 96 97 NESTED_COMMENTS = False 98 99 KEYWORDS = { 100 **tokens.Tokenizer.KEYWORDS, 101 "(+)": TokenType.JOIN_MARKER, 102 # https://docs.oracle.com/en/database/oracle/oracle-database/19/sqlrf/Comparison-Conditions.html 103 "^=": TokenType.NEQ, 104 "BINARY_DOUBLE": TokenType.DOUBLE, 105 "BINARY_FLOAT": TokenType.FLOAT, 106 "BULK COLLECT INTO": TokenType.BULK_COLLECT_INTO, 107 "COLUMNS": TokenType.COLUMN, 108 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 109 "MINUS": TokenType.EXCEPT, 110 "NVARCHAR2": TokenType.NVARCHAR, 111 "ORDER SIBLINGS BY": TokenType.ORDER_SIBLINGS_BY, 112 "SAMPLE": TokenType.TABLE_SAMPLE, 113 "START": TokenType.BEGIN, 114 "SUBPARTITION": TokenType.PARTITION, 115 "TOP": TokenType.TOP, 116 "VARCHAR2": TokenType.VARCHAR, 117 "SYSTIMESTAMP": TokenType.SYSTIMESTAMP, 118 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- HEREDOC_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
12class Postgres(Dialect): 13 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 14 INDEX_OFFSET = 1 15 ASCII_ONLY_NORMALIZATION = True 16 # Normalizing `x IS NOT NULL` to `NOT x IS NULL` is unsafe due to row values, 17 # e.g. `ROW(1, NULL) IS NOT NULL` is false whereas `NOT ROW(1, NULL) IS NULL` is true 18 NORMALIZE_NOT_NULL = False 19 TYPED_DIVISION = True 20 CONCAT_COALESCE = True 21 CONCAT_WS_COALESCE = True 22 NULL_ORDERING = "nulls_are_large" 23 SUPPORTS_LIMIT_ALL = True 24 TIME_FORMAT = "'YYYY-MM-DD HH24:MI:SS'" 25 TABLESAMPLE_SIZE_IS_PERCENT = True 26 TABLES_REFERENCEABLE_AS_COLUMNS = True 27 28 DEFAULT_FUNCTIONS_COLUMN_NAMES = { 29 exp.ExplodingGenerateSeries: "generate_series", 30 } 31 32 TIME_MAPPING = { 33 "d": "%u", # 1-based day of week 34 "D": "%u", # 1-based day of week 35 "dd": "%d", # day of month 36 "DD": "%d", # day of month 37 "ddd": "%j", # zero padded day of year 38 "DDD": "%j", # zero padded day of year 39 "FMDD": "%-d", # - is no leading zero for Python; same for FM in postgres 40 "FMDDD": "%-j", # day of year 41 "FMHH12": "%-I", # 9 42 "FMHH24": "%-H", # 9 43 "FMMI": "%-M", # Minute 44 "FMMM": "%-m", # 1 45 "FMSS": "%-S", # Second 46 "HH12": "%I", # 09 47 "HH24": "%H", # 09 48 "iw": "%V", # ISO 8601 week of year 49 "IW": "%V", # ISO 8601 week of year 50 "iyyy": "%G", # ISO 8601 week-numbering year 51 "IYYY": "%G", # ISO 8601 week-numbering year 52 "mi": "%M", # zero padded minute 53 "MI": "%M", # zero padded minute 54 "mm": "%m", # 01 55 "MM": "%m", # 01 56 "OF": "%z", # utc offset 57 "ss": "%S", # zero padded second 58 "SS": "%S", # zero padded second 59 "TMDay": "%A", # TM is locale dependent 60 "TMDy": "%a", 61 "TMMon": "%b", # Sep 62 "TMMonth": "%B", # September 63 "day": "%Aenlower", # tuesday 64 "dy": "%aenlower", # tue 65 "TZ": "%Z", # uppercase timezone name 66 "US": "%f", # zero padded microsecond 67 "ww": "%U", # 1-based week of year 68 "WW": "%U", # 1-based week of year 69 "yy": "%y", # 15 70 "YY": "%y", # 15 71 "yyy": "%Ythree", # 015 72 "YYY": "%Ythree", # 015 73 "yyyy": "%Y", # 2015 74 "YYYY": "%Y", # 2015 75 } 76 77 UNESCAPED_SEQUENCES = {"\\a": "a"} 78 79 class Tokenizer(tokens.Tokenizer): 80 NUMERIC_ESCAPES = { 81 "x": (16, 1, 2, 0xFF), 82 "u": (16, 4, 4, 0xFFFF), 83 "U": (16, 8, 8, 0x10FFFF), 84 "0": (8, 1, 3, 0o777), 85 } 86 NUMERIC_ESCAPES_ARE_BYTES = True 87 DROP_UNKNOWN_ESCAPES = True 88 BIT_STRINGS = [("b'", "'"), ("B'", "'")] 89 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 90 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 91 UNICODE_STRINGS = [("U&'", "'"), ("u&'", "'")] 92 BYTE_STRING_ESCAPES = ["'", "\\"] 93 HEREDOC_STRINGS = ["$"] 94 95 HEREDOC_TAG_IS_IDENTIFIER = True 96 HEREDOC_STRING_ALTERNATIVE = TokenType.PARAMETER 97 98 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.LOCK} 99 100 KEYWORDS = { 101 **tokens.Tokenizer.KEYWORDS, 102 "~": TokenType.RLIKE, 103 "@@": TokenType.DAT, 104 "@?": TokenType.AT_QMARK, 105 "@>": TokenType.AT_GT, 106 "<@": TokenType.LT_AT, 107 "?&": TokenType.QMARK_AMP, 108 "?|": TokenType.QMARK_PIPE, 109 "#-": TokenType.HASH_DASH, 110 "|/": TokenType.PIPE_SLASH, 111 "||/": TokenType.DPIPE_SLASH, 112 "^@": TokenType.CARET_AT, 113 "BEGIN": TokenType.BEGIN, 114 "BIGSERIAL": TokenType.BIGSERIAL, 115 "CSTRING": TokenType.PSEUDO_TYPE, 116 "DECLARE": TokenType.COMMAND, 117 "DO": TokenType.COMMAND, 118 "EXEC": TokenType.COMMAND, 119 "HSTORE": TokenType.HSTORE, 120 "INT8": TokenType.BIGINT, 121 "MONEY": TokenType.MONEY, 122 "NAME": TokenType.NAME, 123 "OID": TokenType.OBJECT_IDENTIFIER, 124 "ONLY": TokenType.ONLY, 125 "POINT": TokenType.POINT, 126 "REFRESH": TokenType.COMMAND, 127 "REINDEX": TokenType.COMMAND, 128 "RESET": TokenType.COMMAND, 129 "SERIAL": TokenType.SERIAL, 130 "SMALLSERIAL": TokenType.SMALLSERIAL, 131 "TEMP": TokenType.TEMPORARY, 132 "TYPE": TokenType.TYPE, 133 "REGCLASS": TokenType.OBJECT_IDENTIFIER, 134 "REGCOLLATION": TokenType.OBJECT_IDENTIFIER, 135 "REGCONFIG": TokenType.OBJECT_IDENTIFIER, 136 "REGDICTIONARY": TokenType.OBJECT_IDENTIFIER, 137 "REGNAMESPACE": TokenType.OBJECT_IDENTIFIER, 138 "REGOPER": TokenType.OBJECT_IDENTIFIER, 139 "REGOPERATOR": TokenType.OBJECT_IDENTIFIER, 140 "REGPROC": TokenType.OBJECT_IDENTIFIER, 141 "REGPROCEDURE": TokenType.OBJECT_IDENTIFIER, 142 "REGROLE": TokenType.OBJECT_IDENTIFIER, 143 "REGTYPE": TokenType.OBJECT_IDENTIFIER, 144 "FLOAT": TokenType.DOUBLE, 145 "XML": TokenType.XML, 146 "VARIADIC": TokenType.VARIADIC, 147 "INOUT": TokenType.INOUT, 148 } 149 KEYWORDS.pop("/*+") 150 KEYWORDS.pop("DIV") 151 152 SINGLE_TOKENS = { 153 **tokens.Tokenizer.SINGLE_TOKENS, 154 "$": TokenType.HEREDOC_STRING, 155 } 156 157 VAR_SINGLE_TOKENS = {"$"} 158 159 Parser = PostgresParser 160 161 Generator = PostgresGenerator
Whether identifiers are only normalized with respect to ASCII characters, e.g. Ä and
ä are different identifiers in DuckDB, but the same identifier in Spark.
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether table names can be referenced as columns (treated as structs).
BigQuery allows tables to be referenced as columns in queries, automatically treating them as struct values containing all the table's columns.
For example, in BigQuery: SELECT t FROM my_table AS t -- Returns entire row as a struct
Maps function expressions to their default output column name(s).
For example, in Postgres, generate_series function outputs a column named "generate_series" by default, so we map the ExplodingGenerateSeries expression to "generate_series" string.
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
79 class Tokenizer(tokens.Tokenizer): 80 NUMERIC_ESCAPES = { 81 "x": (16, 1, 2, 0xFF), 82 "u": (16, 4, 4, 0xFFFF), 83 "U": (16, 8, 8, 0x10FFFF), 84 "0": (8, 1, 3, 0o777), 85 } 86 NUMERIC_ESCAPES_ARE_BYTES = True 87 DROP_UNKNOWN_ESCAPES = True 88 BIT_STRINGS = [("b'", "'"), ("B'", "'")] 89 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 90 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 91 UNICODE_STRINGS = [("U&'", "'"), ("u&'", "'")] 92 BYTE_STRING_ESCAPES = ["'", "\\"] 93 HEREDOC_STRINGS = ["$"] 94 95 HEREDOC_TAG_IS_IDENTIFIER = True 96 HEREDOC_STRING_ALTERNATIVE = TokenType.PARAMETER 97 98 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.LOCK} 99 100 KEYWORDS = { 101 **tokens.Tokenizer.KEYWORDS, 102 "~": TokenType.RLIKE, 103 "@@": TokenType.DAT, 104 "@?": TokenType.AT_QMARK, 105 "@>": TokenType.AT_GT, 106 "<@": TokenType.LT_AT, 107 "?&": TokenType.QMARK_AMP, 108 "?|": TokenType.QMARK_PIPE, 109 "#-": TokenType.HASH_DASH, 110 "|/": TokenType.PIPE_SLASH, 111 "||/": TokenType.DPIPE_SLASH, 112 "^@": TokenType.CARET_AT, 113 "BEGIN": TokenType.BEGIN, 114 "BIGSERIAL": TokenType.BIGSERIAL, 115 "CSTRING": TokenType.PSEUDO_TYPE, 116 "DECLARE": TokenType.COMMAND, 117 "DO": TokenType.COMMAND, 118 "EXEC": TokenType.COMMAND, 119 "HSTORE": TokenType.HSTORE, 120 "INT8": TokenType.BIGINT, 121 "MONEY": TokenType.MONEY, 122 "NAME": TokenType.NAME, 123 "OID": TokenType.OBJECT_IDENTIFIER, 124 "ONLY": TokenType.ONLY, 125 "POINT": TokenType.POINT, 126 "REFRESH": TokenType.COMMAND, 127 "REINDEX": TokenType.COMMAND, 128 "RESET": TokenType.COMMAND, 129 "SERIAL": TokenType.SERIAL, 130 "SMALLSERIAL": TokenType.SMALLSERIAL, 131 "TEMP": TokenType.TEMPORARY, 132 "TYPE": TokenType.TYPE, 133 "REGCLASS": TokenType.OBJECT_IDENTIFIER, 134 "REGCOLLATION": TokenType.OBJECT_IDENTIFIER, 135 "REGCONFIG": TokenType.OBJECT_IDENTIFIER, 136 "REGDICTIONARY": TokenType.OBJECT_IDENTIFIER, 137 "REGNAMESPACE": TokenType.OBJECT_IDENTIFIER, 138 "REGOPER": TokenType.OBJECT_IDENTIFIER, 139 "REGOPERATOR": TokenType.OBJECT_IDENTIFIER, 140 "REGPROC": TokenType.OBJECT_IDENTIFIER, 141 "REGPROCEDURE": TokenType.OBJECT_IDENTIFIER, 142 "REGROLE": TokenType.OBJECT_IDENTIFIER, 143 "REGTYPE": TokenType.OBJECT_IDENTIFIER, 144 "FLOAT": TokenType.DOUBLE, 145 "XML": TokenType.XML, 146 "VARIADIC": TokenType.VARIADIC, 147 "INOUT": TokenType.INOUT, 148 } 149 KEYWORDS.pop("/*+") 150 KEYWORDS.pop("DIV") 151 152 SINGLE_TOKENS = { 153 **tokens.Tokenizer.SINGLE_TOKENS, 154 "$": TokenType.HEREDOC_STRING, 155 } 156 157 VAR_SINGLE_TOKENS = {"$"}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
18class Presto(Dialect): 19 INDEX_OFFSET = 1 20 NULL_ORDERING = "nulls_are_last" 21 TIME_FORMAT = MySQL.TIME_FORMAT 22 STRICT_STRING_CONCAT = True 23 TYPED_DIVISION = True 24 TABLESAMPLE_SIZE_IS_PERCENT = True 25 LOG_BASE_FIRST: bool | None = None 26 SUPPORTS_LIMIT_ALL = True 27 SUPPORTS_VALUES_DEFAULT = False 28 LEAST_GREATEST_IGNORES_NULLS = False 29 UUID_IS_STRING_TYPE = False 30 31 TIME_MAPPING = MySQL.TIME_MAPPING 32 33 # https://github.com/trinodb/trino/issues/17 34 # https://github.com/trinodb/trino/issues/12289 35 # https://github.com/prestodb/presto/issues/2863 36 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 37 38 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 39 40 SUPPORTED_SETTINGS = { 41 *Dialect.SUPPORTED_SETTINGS, 42 "variant_extract_is_json_extract", 43 } 44 45 class Tokenizer(tokens.Tokenizer): 46 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 47 UNICODE_STRINGS = [ 48 (prefix + q, q) 49 for q in t.cast(list[str], tokens.Tokenizer.QUOTES) 50 for prefix in ("U&", "u&") 51 ] 52 53 NESTED_COMMENTS = False 54 55 KEYWORDS = { 56 **tokens.Tokenizer.KEYWORDS, 57 "DEALLOCATE PREPARE": TokenType.COMMAND, 58 "DESCRIBE INPUT": TokenType.COMMAND, 59 "DESCRIBE OUTPUT": TokenType.COMMAND, 60 "RESET SESSION": TokenType.COMMAND, 61 "START": TokenType.BEGIN, 62 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 63 "ROW": TokenType.STRUCT, 64 "IPADDRESS": TokenType.IPADDRESS, 65 "IPPREFIX": TokenType.IPPREFIX, 66 "TDIGEST": TokenType.TDIGEST, 67 "HYPERLOGLOG": TokenType.HLLSKETCH, 68 } 69 KEYWORDS.pop("/*+") 70 KEYWORDS.pop("QUALIFY") 71 72 Parser = PrestoParser 73 74 Generator = PrestoGenerator
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Whether LEAST/GREATEST functions ignore NULL values, e.g:
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
Associates this dialect's time formats with their equivalent Python strftime formats.
Specifies the strategy according to which identifiers should be normalized.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
45 class Tokenizer(tokens.Tokenizer): 46 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 47 UNICODE_STRINGS = [ 48 (prefix + q, q) 49 for q in t.cast(list[str], tokens.Tokenizer.QUOTES) 50 for prefix in ("U&", "u&") 51 ] 52 53 NESTED_COMMENTS = False 54 55 KEYWORDS = { 56 **tokens.Tokenizer.KEYWORDS, 57 "DEALLOCATE PREPARE": TokenType.COMMAND, 58 "DESCRIBE INPUT": TokenType.COMMAND, 59 "DESCRIBE OUTPUT": TokenType.COMMAND, 60 "RESET SESSION": TokenType.COMMAND, 61 "START": TokenType.BEGIN, 62 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 63 "ROW": TokenType.STRUCT, 64 "IPADDRESS": TokenType.IPADDRESS, 65 "IPPREFIX": TokenType.IPPREFIX, 66 "TDIGEST": TokenType.TDIGEST, 67 "HYPERLOGLOG": TokenType.HLLSKETCH, 68 } 69 KEYWORDS.pop("/*+") 70 KEYWORDS.pop("QUALIFY")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
11class PRQL(Dialect): 12 DPIPE_IS_STRING_CONCAT = False 13 14 Generator = PRQLGenerator 15 16 class Tokenizer(tokens.Tokenizer): 17 IDENTIFIERS = ["`"] 18 QUOTES = ["'", '"'] 19 20 SINGLE_TOKENS = { 21 **tokens.Tokenizer.SINGLE_TOKENS, 22 "=": TokenType.ALIAS, 23 "'": TokenType.QUOTE, 24 '"': TokenType.QUOTE, 25 "`": TokenType.IDENTIFIER, 26 "#": TokenType.COMMENT, 27 } 28 29 KEYWORDS = { 30 **tokens.Tokenizer.KEYWORDS, 31 } 32 33 Parser = PRQLParser
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
16 class Tokenizer(tokens.Tokenizer): 17 IDENTIFIERS = ["`"] 18 QUOTES = ["'", '"'] 19 20 SINGLE_TOKENS = { 21 **tokens.Tokenizer.SINGLE_TOKENS, 22 "=": TokenType.ALIAS, 23 "'": TokenType.QUOTE, 24 '"': TokenType.QUOTE, 25 "`": TokenType.IDENTIFIER, 26 "#": TokenType.COMMENT, 27 } 28 29 KEYWORDS = { 30 **tokens.Tokenizer.KEYWORDS, 31 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
12class Redshift(Postgres): 13 # https://docs.aws.amazon.com/redshift/latest/dg/r_names.html 14 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 15 16 NORMALIZE_NOT_NULL = True 17 18 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 19 SUPPORTS_USER_DEFINED_TYPES = False 20 INDEX_OFFSET = 0 21 COPY_PARAMS_ARE_CSV = False 22 HEX_LOWERCASE = True 23 HAS_DISTINCT_ARRAY_CONSTRUCTORS = True 24 COALESCE_COMPARISON_NON_STANDARD = True 25 REGEXP_EXTRACT_POSITION_OVERFLOW_RETURNS_NULL = False 26 ARRAY_FUNCS_PROPAGATES_NULLS = True 27 28 # ref: https://docs.aws.amazon.com/redshift/latest/dg/r_FORMAT_strings.html 29 TIME_FORMAT = "'YYYY-MM-DD HH24:MI:SS'" 30 31 TIME_MAPPING = { 32 **Postgres.TIME_MAPPING, 33 "MON": "%b", 34 "MONTH": "%B", 35 } 36 37 Parser = RedshiftParser 38 39 UNESCAPED_SEQUENCES = {"\\a": "a", "\\v": "v"} 40 41 class Tokenizer(Postgres.Tokenizer): 42 NUMERIC_ESCAPES = {"0": (8, 1, 3, 0o777)} 43 NUMERIC_ESCAPES_ARE_BYTES = True 44 DROP_UNKNOWN_ESCAPES = True 45 BIT_STRINGS = [] 46 HEX_STRINGS = [] 47 STRING_ESCAPES = ["\\", "'"] 48 49 KEYWORDS = { 50 **Postgres.Tokenizer.KEYWORDS, 51 "(+)": TokenType.JOIN_MARKER, 52 "BINARY VARYING": TokenType.VARBINARY, 53 "CURRENT_USER_ID": TokenType.CURRENT_USER_ID, 54 "HLLSKETCH": TokenType.HLLSKETCH, 55 "MINUS": TokenType.EXCEPT, 56 "SUPER": TokenType.SUPER, 57 "TOP": TokenType.TOP, 58 "UNLOAD": TokenType.COMMAND, 59 "USER": TokenType.CURRENT_USER, 60 "VARBYTE": TokenType.VARBINARY, 61 } 62 KEYWORDS.pop("VALUES") 63 64 # Redshift allows # to appear as a table identifier prefix 65 SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy() 66 SINGLE_TOKENS.pop("#") 67 68 Generator = RedshiftGenerator
Specifies the strategy according to which identifiers should be normalized.
Whether the ARRAY constructor is context-sensitive, i.e in Redshift ARRAY[1, 2, 3] != ARRAY(1, 2, 3) as the former is of type INT[] vs the latter which is SUPER
Whether COALESCE in comparisons has non-standard NULL semantics.
We can't convert COALESCE(x, 1) = 2 into NOT x IS NULL AND x = 2 for redshift,
because they are not always equivalent. For example, if x is NULL and it comes
from a table, then the result is NULL, despite FALSE AND NULL evaluating to FALSE.
In standard SQL and most dialects, these expressions are equivalent, but Redshift treats table NULLs differently in this context.
Whether REGEXP_EXTRACT returns NULL when the position arg exceeds the string length.
Whether Array update functions return NULL when the input array is NULL.
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
41 class Tokenizer(Postgres.Tokenizer): 42 NUMERIC_ESCAPES = {"0": (8, 1, 3, 0o777)} 43 NUMERIC_ESCAPES_ARE_BYTES = True 44 DROP_UNKNOWN_ESCAPES = True 45 BIT_STRINGS = [] 46 HEX_STRINGS = [] 47 STRING_ESCAPES = ["\\", "'"] 48 49 KEYWORDS = { 50 **Postgres.Tokenizer.KEYWORDS, 51 "(+)": TokenType.JOIN_MARKER, 52 "BINARY VARYING": TokenType.VARBINARY, 53 "CURRENT_USER_ID": TokenType.CURRENT_USER_ID, 54 "HLLSKETCH": TokenType.HLLSKETCH, 55 "MINUS": TokenType.EXCEPT, 56 "SUPER": TokenType.SUPER, 57 "TOP": TokenType.TOP, 58 "UNLOAD": TokenType.COMMAND, 59 "USER": TokenType.CURRENT_USER, 60 "VARBYTE": TokenType.VARBINARY, 61 } 62 KEYWORDS.pop("VALUES") 63 64 # Redshift allows # to appear as a table identifier prefix 65 SINGLE_TOKENS = Postgres.Tokenizer.SINGLE_TOKENS.copy() 66 SINGLE_TOKENS.pop("#")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- IDENTIFIERS
- QUOTES
- IDENTIFIER_ESCAPES
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
10class RisingWave(Postgres): 11 NORMALIZE_NOT_NULL = True 12 13 REQUIRES_PARENTHESIZED_STRUCT_ACCESS = True 14 SUPPORTS_STRUCT_STAR_EXPANSION = True 15 16 UNESCAPED_SEQUENCES = {"\\a": "a", "\\v": "v"} 17 18 class Tokenizer(Postgres.Tokenizer): 19 KEYWORDS = { 20 **Postgres.Tokenizer.KEYWORDS, 21 "SINK": TokenType.SINK, 22 "SOURCE": TokenType.SOURCE, 23 } 24 25 Parser = RisingWaveParser 26 27 Generator = RisingWaveGenerator
Whether struct field access requires parentheses around the expression.
RisingWave requires parentheses for struct field access in certain contexts:
SELECT (col.field).subfield FROM table -- Parentheses required
Without parentheses, the parser may not correctly interpret nested struct access.
Reference: sqlglot.dialects.risingwave.com/sql/data-types/struct#retrieve-data-in-a-struct">https://docssqlglot.dialects.risingwave.com/sql/data-types/struct#retrieve-data-in-a-struct
Whether the dialect supports expanding struct fields using star notation (e.g., struct_col.*).
BigQuery allows struct fields to be expanded with the star operator:
SELECT t.struct_col.* FROM table t
RisingWave also allows struct field expansion with the star operator using parentheses:
SELECT (t.struct_col).* FROM table t
This expands to all fields within the struct.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
18 class Tokenizer(Postgres.Tokenizer): 19 KEYWORDS = { 20 **Postgres.Tokenizer.KEYWORDS, 21 "SINK": TokenType.SINK, 22 "SOURCE": TokenType.SOURCE, 23 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
8class SingleStore(MySQL): 9 SUPPORTS_ORDER_BY_ALL = True 10 11 MYSQL_INVERSE_TIME_MAPPING = MySQL.INVERSE_TIME_MAPPING 12 MYSQL_INVERSE_TIME_TRIE = MySQL.INVERSE_TIME_TRIE 13 CAST_TO_TIME6 = staticmethod(cast_to_time6) 14 15 TIME_MAPPING: dict[str, str] = { 16 "D": "%u", # Day of week (1-7) 17 "DD": "%d", # day of month (01-31) 18 "DY": "%a", # abbreviated name of day 19 "HH": "%I", # Hour of day (01-12) 20 "HH12": "%I", # alias for HH 21 "HH24": "%H", # Hour of day (00-23) 22 "MI": "%M", # Minute (00-59) 23 "MM": "%m", # Month (01-12; January = 01) 24 "MON": "%b", # Abbreviated name of month 25 "MONTH": "%B", # Name of month 26 "SS": "%S", # Second (00-59) 27 "RR": "%y", # 15 28 "YY": "%y", # 15 29 "YYYY": "%Y", # 2015 30 "FF6": "%f", # only 6 digits are supported in python formats 31 } 32 33 VECTOR_TYPE_ALIASES = { 34 "I8": "TINYINT", 35 "I16": "SMALLINT", 36 "I32": "INT", 37 "I64": "BIGINT", 38 "F32": "FLOAT", 39 "F64": "DOUBLE", 40 } 41 42 INVERSE_VECTOR_TYPE_ALIASES = {v: k for k, v in VECTOR_TYPE_ALIASES.items()} 43 44 class Tokenizer(MySQL.Tokenizer): 45 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 46 47 KEYWORDS = { 48 **MySQL.Tokenizer.KEYWORDS, 49 "BSON": TokenType.JSONB, 50 "GEOGRAPHYPOINT": TokenType.GEOGRAPHYPOINT, 51 "TIMESTAMP": TokenType.TIMESTAMP, 52 "UTC_DATE": TokenType.UTC_DATE, 53 "UTC_TIME": TokenType.UTC_TIME, 54 "UTC_TIMESTAMP": TokenType.UTC_TIMESTAMP, 55 ":>": TokenType.COLON_GT, 56 "!:>": TokenType.NCOLON_GT, 57 "::$": TokenType.DCOLONDOLLAR, 58 "::%": TokenType.DCOLONPERCENT, 59 "::?": TokenType.DCOLONQMARK, 60 "RECORD": TokenType.STRUCT, 61 } 62 63 Parser = SingleStoreParser 64 65 Generator = SingleStoreGenerator
Whether ORDER BY ALL is supported (expands to all the selected columns) as in DuckDB, Spark3/Databricks
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of vector type aliases back to their canonical names. Overridden by dialects like SingleStore.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
44 class Tokenizer(MySQL.Tokenizer): 45 BYTE_STRINGS = [("e'", "'"), ("E'", "'")] 46 47 KEYWORDS = { 48 **MySQL.Tokenizer.KEYWORDS, 49 "BSON": TokenType.JSONB, 50 "GEOGRAPHYPOINT": TokenType.GEOGRAPHYPOINT, 51 "TIMESTAMP": TokenType.TIMESTAMP, 52 "UTC_DATE": TokenType.UTC_DATE, 53 "UTC_TIME": TokenType.UTC_TIME, 54 "UTC_TIMESTAMP": TokenType.UTC_TIMESTAMP, 55 ":>": TokenType.COLON_GT, 56 "!:>": TokenType.NCOLON_GT, 57 "::$": TokenType.DCOLONDOLLAR, 58 "::%": TokenType.DCOLONPERCENT, 59 "::?": TokenType.DCOLONQMARK, 60 "RECORD": TokenType.STRUCT, 61 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
19class Snowflake(Dialect): 20 # https://docs.snowflake.com/en/sql-reference/identifiers-syntax 21 NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE 22 # https://docs.snowflake.com/en/sql-reference/data-types-text#escape-sequences 23 UNESCAPED_SEQUENCES = {"\\a": "a", "\\v": "v"} 24 NULL_ORDERING = "nulls_are_large" 25 TIME_FORMAT = "'YYYY-MM-DD HH24:MI:SS'" 26 SUPPORTS_USER_DEFINED_TYPES = False 27 PREFER_CTE_ALIAS_COLUMN = True 28 SUPPORTS_POSITIONAL_COLUMN_REFS = True 29 TABLESAMPLE_SIZE_IS_PERCENT = True 30 COPY_PARAMS_ARE_CSV = False 31 ARRAY_AGG_INCLUDES_NULLS = None 32 ARRAY_FUNCS_PROPAGATES_NULLS = True 33 ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False 34 ALTER_TABLE_DROP_REQUIRED_FOR_EACH_COLUMN = False 35 TRY_CAST_REQUIRES_STRING = True 36 SUPPORTS_ALIAS_REFS_IN_JOIN_CONDITIONS = True 37 LEAST_GREATEST_IGNORES_NULLS = False 38 UUID_IS_STRING_TYPE = True 39 STAR_ILIKE_BACKSLASH_ESCAPE = True 40 41 # https://docs.snowflake.com/en/sql-reference/functions/split_to_table 42 DEFAULT_FUNCTIONS_COLUMN_NAMES = { 43 exp.SplitToTable: ("seq", "index", "value"), 44 exp.StrtokSplitToTable: ("seq", "index", "value"), 45 } 46 47 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 48 49 # https://docs.snowflake.com/en/en/sql-reference/functions/initcap 50 INITCAP_DEFAULT_DELIMITER_CHARS = ' \t\n\r\f\v!?@"^#$&~_,.:;+\\-*%/|\\[\\](){}<>' 51 52 INVERSE_TIME_MAPPING = { 53 "%d": "DD", 54 "%-d": "DD", 55 "%a": "DY", 56 "T": "T", # in TIME_MAPPING we map '"T"' with the double quotes to 'T', and we want to prevent 'T' from being mapped back to '"T"' so that 'AUTO' doesn't become 'AU"T"O' 57 } 58 59 TIME_MAPPING = { 60 "".join(chars): value 61 for key, value in { 62 "YYYY": "%Y", 63 "YY": "%y", 64 "MMMM": "%B", 65 "MON": "%b", 66 "MM": "%m", 67 "DD": "%d", 68 "DY": "%a", 69 "HH24": "%H", 70 "HH12": "%I", 71 "MI": "%M", 72 "SS": "%S", 73 "FF": "%f_nine", # %f_ internal representation with precision specified 74 "FF0": "%f_zero", 75 "FF1": "%f_one", 76 "FF2": "%f_two", 77 "FF3": "%f_three", 78 "FF4": "%f_four", 79 "FF5": "%f_five", 80 "FF6": "%f", 81 "FF7": "%f_seven", 82 "FF8": "%f_eight", 83 "FF9": "%f_nine", 84 "TZHTZM": "%z", 85 "TZH:TZM": "%:z", # internal representation for ±HH:MM 86 "TZH": "%-z", # internal representation ±HH 87 # Seems like Snowflake treats AM/PM in the format string as equivalent, 88 # only the time (stamp) value's AM/PM affects the output 89 "AM": "%p", 90 "PM": "%p", 91 }.items() 92 for chars in product(*zip(key.upper(), key.lower())) 93 } | {'"T"': "T"} 94 95 DATE_PART_MAPPING = { 96 **Dialect.DATE_PART_MAPPING, 97 "ISOWEEK": "WEEKISO", 98 # The base Dialect maps EPOCH_SECOND -> EPOCH, but we need to preserve 99 # EPOCH_SECOND as a distinct value for two reasons: 100 # 1. Type annotation: EPOCH_SECOND returns BIGINT, while EPOCH returns DOUBLE 101 # 2. Transpilation: DuckDB's EPOCH() returns float, so we cast EPOCH_SECOND 102 # to BIGINT to match Snowflake's integer behavior 103 # Without this override, EXTRACT(EPOCH_SECOND FROM ts) would be normalized 104 # to EXTRACT(EPOCH FROM ts) and lose the integer semantics. 105 "EPOCH_SECOND": "EPOCH_SECOND", 106 "EPOCH_SECONDS": "EPOCH_SECOND", 107 } 108 109 PSEUDOCOLUMNS = {"LEVEL"} 110 111 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 112 # This disables quoting DUAL in SELECT ... FROM DUAL, because Snowflake treats an 113 # unquoted DUAL keyword in a special way and does not map it to a user-defined table 114 return super().can_quote(identifier, identify) and not ( 115 isinstance(identifier.parent, exp.Table) 116 and not identifier.quoted 117 and identifier.name.lower() == "dual" 118 ) 119 120 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 121 SINGLE_TOKENS = jsonpath.JSONPathTokenizer.SINGLE_TOKENS.copy() 122 SINGLE_TOKENS.pop("$") 123 124 Parser = SnowflakeParser 125 126 class Tokenizer(tokens.Tokenizer): 127 STRING_ESCAPES = ["\\", "'"] 128 NUMERIC_ESCAPES = {"x": (16, 2, 2, 0xFF), "u": (16, 4, 4, 0xFFFF), "0": (8, 1, 3, 0xFF)} 129 DROP_UNKNOWN_ESCAPES = True 130 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 131 RAW_STRINGS = ["$$"] 132 COMMENTS = ["--", "//", ("/*", "*/")] 133 NESTED_COMMENTS = False 134 135 KEYWORDS = { 136 **tokens.Tokenizer.KEYWORDS, 137 "(+)": TokenType.JOIN_MARKER, 138 "BYTEINT": TokenType.INT, 139 "FILE://": TokenType.URI_START, 140 "FILE FORMAT": TokenType.FILE_FORMAT, 141 "GET": TokenType.GET, 142 "INTEGRATION": TokenType.INTEGRATION, 143 "LS": TokenType.LIST, 144 "MATCH_CONDITION": TokenType.MATCH_CONDITION, 145 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 146 "MINUS": TokenType.EXCEPT, 147 "NCHAR VARYING": TokenType.VARCHAR, 148 "PACKAGE": TokenType.PACKAGE, 149 "POLICY": TokenType.POLICY, 150 "POOL": TokenType.POOL, 151 "PUT": TokenType.PUT, 152 "UNDROP": TokenType.UNDROP, 153 "REMOVE": TokenType.COMMAND, 154 "RM": TokenType.COMMAND, 155 "ROLE": TokenType.ROLE, 156 "RULE": TokenType.RULE, 157 "SAMPLE": TokenType.TABLE_SAMPLE, 158 "SEMANTIC VIEW": TokenType.SEMANTIC_VIEW, 159 "SQL_DOUBLE": TokenType.DOUBLE, 160 "SQL_VARCHAR": TokenType.VARCHAR, 161 "STAGE": TokenType.STAGE, 162 "STORAGE INTEGRATION": TokenType.STORAGE_INTEGRATION, 163 "STREAMLIT": TokenType.STREAMLIT, 164 "TAG": TokenType.TAG, 165 "TIMESTAMP_TZ": TokenType.TIMESTAMPTZ, 166 "TOP": TokenType.TOP, 167 "VOLUME": TokenType.VOLUME, 168 "WAREHOUSE": TokenType.WAREHOUSE, 169 # https://docs.snowflake.com/en/sql-reference/data-types-numeric#float 170 # FLOAT is a synonym for DOUBLE in Snowflake 171 "FLOAT": TokenType.DOUBLE, 172 } 173 KEYWORDS.pop("/*+") 174 KEYWORDS.pop("GLOB") 175 KEYWORDS.pop("RETURNING") 176 177 SINGLE_TOKENS = { 178 **tokens.Tokenizer.SINGLE_TOKENS, 179 "$": TokenType.PARAMETER, 180 "!": TokenType.EXCLAMATION, 181 } 182 183 VAR_SINGLE_TOKENS = {"$"} 184 185 COMMANDS = tokens.Tokenizer.COMMANDS - {TokenType.SHOW} 186 187 Generator = SnowflakeGenerator
Specifies the strategy according to which identifiers should be normalized.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Some dialects, such as Snowflake, allow you to reference a CTE column alias in the HAVING clause of the CTE. This flag will cause the CTE alias columns to override any projection aliases in the subquery.
For example, WITH y(c) AS ( SELECT SUM(a) FROM (SELECT 1 a) AS x HAVING c > 0 ) SELECT c FROM y;
will be rewritten as
WITH y(c) AS (
SELECT SUM(a) AS c FROM (SELECT 1 AS a) AS x HAVING c > 0
) SELECT c FROM y;
Whether qualified $N references the Nth column of their source.
Whether Array update functions return NULL when the input array is NULL.
Whether alias references are allowed in JOIN ... ON clauses.
Most dialects do not support this, but Snowflake allows alias expansion in the JOIN ... ON clause (and almost everywhere else)
For example, in Snowflake: SELECT a.id AS user_id FROM a JOIN b ON user_id = b.id -- VALID
Reference: sqlglot.dialects.snowflake.com/en/sql-reference/sql/select#usage-notes">https://docssqlglot.dialects.snowflake.com/en/sql-reference/sql/select#usage-notes
Whether LEAST/GREATEST functions ignore NULL values, e.g:
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
Whether a backslash in a SELECT * ILIKE '<pattern>' filter escapes the following character,
so that e.g. \_ matches a literal underscore (Snowflake). When False, backslashes in the
pattern are matched literally (DuckDB).
Maps function expressions to their default output column name(s).
For example, in Postgres, generate_series function outputs a column named "generate_series" by default, so we map the ExplodingGenerateSeries expression to "generate_series" string.
Associates this dialect's time formats with their equivalent Python strftime formats.
Columns that are auto-generated by the engine corresponding to this dialect.
For example, such columns may be excluded from SELECT * queries.
111 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 112 # This disables quoting DUAL in SELECT ... FROM DUAL, because Snowflake treats an 113 # unquoted DUAL keyword in a special way and does not map it to a user-defined table 114 return super().can_quote(identifier, identify) and not ( 115 isinstance(identifier.parent, exp.Table) 116 and not identifier.quoted 117 and identifier.name.lower() == "dual" 118 )
Checks if an identifier can be quoted
Arguments:
- identifier: The identifier to check.
- identify:
True: Always returnsTrueexcept for certain cases."safe": Only returnsTrueif the identifier is case-insensitive."unsafe": Only returnsTrueif the identifier is case-sensitive.
Returns:
Whether the given text can be identified.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
120 class JSONPathTokenizer(jsonpath.JSONPathTokenizer): 121 SINGLE_TOKENS = jsonpath.JSONPathTokenizer.SINGLE_TOKENS.copy() 122 SINGLE_TOKENS.pop("$")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- VAR_SINGLE_TOKENS
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
126 class Tokenizer(tokens.Tokenizer): 127 STRING_ESCAPES = ["\\", "'"] 128 NUMERIC_ESCAPES = {"x": (16, 2, 2, 0xFF), "u": (16, 4, 4, 0xFFFF), "0": (8, 1, 3, 0xFF)} 129 DROP_UNKNOWN_ESCAPES = True 130 HEX_STRINGS = [("x'", "'"), ("X'", "'")] 131 RAW_STRINGS = ["$$"] 132 COMMENTS = ["--", "//", ("/*", "*/")] 133 NESTED_COMMENTS = False 134 135 KEYWORDS = { 136 **tokens.Tokenizer.KEYWORDS, 137 "(+)": TokenType.JOIN_MARKER, 138 "BYTEINT": TokenType.INT, 139 "FILE://": TokenType.URI_START, 140 "FILE FORMAT": TokenType.FILE_FORMAT, 141 "GET": TokenType.GET, 142 "INTEGRATION": TokenType.INTEGRATION, 143 "LS": TokenType.LIST, 144 "MATCH_CONDITION": TokenType.MATCH_CONDITION, 145 "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE, 146 "MINUS": TokenType.EXCEPT, 147 "NCHAR VARYING": TokenType.VARCHAR, 148 "PACKAGE": TokenType.PACKAGE, 149 "POLICY": TokenType.POLICY, 150 "POOL": TokenType.POOL, 151 "PUT": TokenType.PUT, 152 "UNDROP": TokenType.UNDROP, 153 "REMOVE": TokenType.COMMAND, 154 "RM": TokenType.COMMAND, 155 "ROLE": TokenType.ROLE, 156 "RULE": TokenType.RULE, 157 "SAMPLE": TokenType.TABLE_SAMPLE, 158 "SEMANTIC VIEW": TokenType.SEMANTIC_VIEW, 159 "SQL_DOUBLE": TokenType.DOUBLE, 160 "SQL_VARCHAR": TokenType.VARCHAR, 161 "STAGE": TokenType.STAGE, 162 "STORAGE INTEGRATION": TokenType.STORAGE_INTEGRATION, 163 "STREAMLIT": TokenType.STREAMLIT, 164 "TAG": TokenType.TAG, 165 "TIMESTAMP_TZ": TokenType.TIMESTAMPTZ, 166 "TOP": TokenType.TOP, 167 "VOLUME": TokenType.VOLUME, 168 "WAREHOUSE": TokenType.WAREHOUSE, 169 # https://docs.snowflake.com/en/sql-reference/data-types-numeric#float 170 # FLOAT is a synonym for DOUBLE in Snowflake 171 "FLOAT": TokenType.DOUBLE, 172 } 173 KEYWORDS.pop("/*+") 174 KEYWORDS.pop("GLOB") 175 KEYWORDS.pop("RETURNING") 176 177 SINGLE_TOKENS = { 178 **tokens.Tokenizer.SINGLE_TOKENS, 179 "$": TokenType.PARAMETER, 180 "!": TokenType.EXCLAMATION, 181 } 182 183 VAR_SINGLE_TOKENS = {"$"} 184 185 COMMANDS = tokens.Tokenizer.COMMANDS - {TokenType.SHOW}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
11class Solr(Dialect): 12 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 13 DPIPE_IS_STRING_CONCAT = False 14 15 Generator = SolrGenerator 16 17 Parser = SolrParser 18 19 class Tokenizer(tokens.Tokenizer): 20 QUOTES = ["'"] 21 IDENTIFIERS = ["`"]
Specifies the strategy according to which identifiers should be normalized.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- KEYWORDS
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
13class Spark(Spark2): 14 SUPPORTS_ORDER_BY_ALL = True 15 SUPPORTS_LIMIT_ALL = True 16 SUPPORTS_NULL_TYPE = True 17 ARRAY_FUNCS_PROPAGATES_NULLS = True 18 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 19 20 # Spark 3+ parses MM/dd/HH/hh/mm/ss strictly, unlike Spark 2 (SimpleDateFormat) 21 TIME_MAPPING = { 22 **Spark2.TIME_MAPPING, 23 "MM": "%mstrict", 24 "dd": "%dstrict", 25 "HH": "%Hstrict", 26 "hh": "%Istrict", 27 "mm": "%Mstrict", 28 "ss": "%Sstrict", 29 } 30 31 class Tokenizer(Spark2.Tokenizer): 32 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "U": (16, 8, 8, 0x10FFFF), "0": (8, 3, 3, 0x7F)} 33 STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS = False 34 35 RAW_STRINGS = [ 36 (prefix + q, q) 37 for q in t.cast(list[str], Spark2.Tokenizer.QUOTES) 38 for prefix in ("r", "R") 39 ] 40 41 KEYWORDS = { 42 **Spark2.Tokenizer.KEYWORDS, 43 "DECLARE": TokenType.DECLARE, 44 } 45 46 Parser = SparkParser 47 48 Generator = SparkGenerator
Whether ORDER BY ALL is supported (expands to all the selected columns) as in DuckDB, Spark3/Databricks
Whether NULL/VOID is supported as a valid data type (not just a value).
Databricks and Spark v3+ support NULL as an actual type, allowing expressions like: SELECT NULL AS col -- Has type NULL, not just value NULL CAST(x AS VOID) -- Valid type cast
Whether Array update functions return NULL when the input array is NULL.
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
31 class Tokenizer(Spark2.Tokenizer): 32 NUMERIC_ESCAPES = {"u": (16, 4, 4, 0xFFFF), "U": (16, 8, 8, 0x10FFFF), "0": (8, 3, 3, 0x7F)} 33 STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS = False 34 35 RAW_STRINGS = [ 36 (prefix + q, q) 37 for q in t.cast(list[str], Spark2.Tokenizer.QUOTES) 38 for prefix in ("r", "R") 39 ] 40 41 KEYWORDS = { 42 **Spark2.Tokenizer.KEYWORDS, 43 "DECLARE": TokenType.DECLARE, 44 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- NUMERIC_ESCAPES_ARE_BYTES
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
11class Spark2(Hive): 12 ALTER_TABLE_SUPPORTS_CASCADE = False 13 INTERSECT_BINDS_TIGHTER_THAN_UNION_AND_EXCEPT = True 14 15 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 16 17 # Spark 2.x parses MM/dd/HH/hh/mm/ss leniently (SimpleDateFormat), unlike strict Hive/Spark 3+ 18 TIME_MAPPING = { 19 **Hive.TIME_MAPPING, 20 "MM": "%m", 21 "dd": "%d", 22 "HH": "%H", 23 "hh": "%I", 24 "mm": "%M", 25 "ss": "%S", 26 } 27 28 # https://spark.apache.org/docs/latest/api/sql/index.html#initcap 29 # https://docs.databricks.com/aws/en/sql/language-manual/functions/initcap 30 # https://github.com/apache/spark/blob/master/common/unsafe/src/main/java/org/apache/spark/unsafe/types/UTF8String.java#L859-L905 31 INITCAP_DEFAULT_DELIMITER_CHARS = " " 32 33 class Tokenizer(Hive.Tokenizer): 34 HEX_STRINGS = [("X'", "'"), ("x'", "'")] 35 36 KEYWORDS = { 37 **Hive.Tokenizer.KEYWORDS, 38 "TIMESTAMP": TokenType.TIMESTAMPTZ, 39 } 40 41 Parser = Spark2Parser 42 43 Generator = Spark2Generator
Hive by default does not update the schema of existing partitions when a column is changed. the CASCADE clause is used to indicate that the change should be propagated to all existing partitions. the Spark dialect, while derived from Hive, does not support the CASCADE clause.
Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't parenthesized. If False, all set operations have equal precedence and associate left to right.
Associates this dialect's time formats with their equivalent Python strftime formats.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
33 class Tokenizer(Hive.Tokenizer): 34 HEX_STRINGS = [("X'", "'"), ("x'", "'")] 35 36 KEYWORDS = { 37 **Hive.Tokenizer.KEYWORDS, 38 "TIMESTAMP": TokenType.TIMESTAMPTZ, 39 }
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES_ARE_BYTES
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
15class SQLite(Dialect): 16 # https://sqlite.org/forum/forumpost/5e575586ac5c711b?raw 17 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 18 ASCII_ONLY_NORMALIZATION = True 19 TYPED_DIVISION = True 20 SAFE_DIVISION = True 21 SAFE_TO_ELIMINATE_DOUBLE_NEGATION = False 22 USING_COLUMN_ORDER = UsingColumnOrder.IN_PLACE 23 CONCAT_COALESCE = True 24 CONCAT_WS_COALESCE = True 25 INTERSECT_BINDS_TIGHTER_THAN_UNION_AND_EXCEPT = False 26 27 class Tokenizer(tokens.Tokenizer): 28 IDENTIFIERS = ['"', ("[", "]"), "`"] 29 HEX_STRINGS = [("x'", "'"), ("X'", "'"), ("0x", ""), ("0X", "")] 30 31 NESTED_COMMENTS = False 32 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 33 34 KEYWORDS = { 35 **tokens.Tokenizer.KEYWORDS, 36 "ATTACH": TokenType.ATTACH, 37 "DETACH": TokenType.DETACH, 38 # REAL, FLOAT and DOUBLE are all 8-byte IEEE floats in SQLite (REAL affinity), 39 # so they must not become a 4-byte float in dialects where REAL/FLOAT means FLOAT4 40 "FLOAT": TokenType.DOUBLE, 41 "INDEXED BY": TokenType.INDEXED_BY, 42 "MATCH": TokenType.MATCH, 43 "REAL": TokenType.DOUBLE, 44 } 45 46 KEYWORDS.pop("/*+") 47 48 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.REPLACE} 49 50 Parser = SQLiteParser 51 52 Generator = SQLiteGenerator
Specifies the strategy according to which identifiers should be normalized.
Whether identifiers are only normalized with respect to ASCII characters, e.g. Ä and
ä are different identifiers in DuckDB, but the same identifier in Spark.
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
Where star expansion places the columns of a USING or NATURAL join.
Given a(a_id, k1, k2) and b(k2, b_id, k1), SELECT * FROM a JOIN b USING (k2, k1) returns:
USING_LIST:k2, k1, a_id, b_idLEFT_TABLE:k1, k2, a_id, b_idIN_PLACE:a_id, k1, k2, b_id
When join columns come first, this applies at every join: each USING join moves its columns ahead of all the columns to its left.
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't parenthesized. If False, all set operations have equal precedence and associate left to right.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
27 class Tokenizer(tokens.Tokenizer): 28 IDENTIFIERS = ['"', ("[", "]"), "`"] 29 HEX_STRINGS = [("x'", "'"), ("X'", "'"), ("0x", ""), ("0X", "")] 30 31 NESTED_COMMENTS = False 32 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = True 33 34 KEYWORDS = { 35 **tokens.Tokenizer.KEYWORDS, 36 "ATTACH": TokenType.ATTACH, 37 "DETACH": TokenType.DETACH, 38 # REAL, FLOAT and DOUBLE are all 8-byte IEEE floats in SQLite (REAL affinity), 39 # so they must not become a 4-byte float in dialects where REAL/FLOAT means FLOAT4 40 "FLOAT": TokenType.DOUBLE, 41 "INDEXED BY": TokenType.INDEXED_BY, 42 "MATCH": TokenType.MATCH, 43 "REAL": TokenType.DOUBLE, 44 } 45 46 KEYWORDS.pop("/*+") 47 48 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.REPLACE}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
12class StarRocks(MySQL): 13 STRICT_JSON_PATH_SYNTAX = False 14 INDEX_OFFSET = 1 15 USING_COLUMN_ORDER = UsingColumnOrder.USING_LIST 16 17 DEFAULT_FUNCTIONS_COLUMN_NAMES = { 18 exp.GenerateSeries: "generate_series", 19 } 20 21 class Tokenizer(MySQL.Tokenizer): 22 # Unlike MySQL, "#" doesn't start a comment 23 COMMENTS = ["--", ("/*", "*/")] 24 DASH_COMMENT_REQUIRES_BOUNDARY = False 25 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = False 26 27 KEYWORDS = { 28 **MySQL.Tokenizer.KEYWORDS, 29 "ADD BACKEND BLACKLIST": TokenType.COMMAND, 30 "ADD COMPUTE NODE BLACKLIST": TokenType.COMMAND, 31 "ADD SQL DIGEST BLACKLIST": TokenType.COMMAND, 32 "ADD SQLBLACKLIST": TokenType.COMMAND, 33 "ADMIN": TokenType.COMMAND, 34 "BACKUP": TokenType.COMMAND, 35 "CANCEL": TokenType.COMMAND, 36 "DEALLOCATE": TokenType.COMMAND, 37 "DELETE BACKEND BLACKLIST": TokenType.COMMAND, 38 "DELETE COMPUTE NODE BLACKLIST": TokenType.COMMAND, 39 "DELETE SQL DIGEST BLACKLIST": TokenType.COMMAND, 40 "DELETE SQLBLACKLIST": TokenType.COMMAND, 41 "EXPORT": TokenType.COMMAND, 42 "HLL": TokenType.HLLSKETCH, 43 "INSTALL": TokenType.COMMAND, 44 "LARGEINT": TokenType.INT128, 45 "PAUSE": TokenType.COMMAND, 46 "RECOVER": TokenType.COMMAND, 47 "REFRESH": TokenType.REFRESH, 48 "RESTORE": TokenType.COMMAND, 49 "RESUME": TokenType.COMMAND, 50 "STOP": TokenType.COMMAND, 51 "SUBMIT": TokenType.COMMAND, 52 "TRANSLATE TRINO": TokenType.COMMAND, 53 "UNINSTALL": TokenType.COMMAND, 54 } 55 KEYWORDS.pop("IGNORE") 56 KEYWORDS.pop("#>") 57 KEYWORDS.pop("#>>") 58 59 Parser = StarRocksParser 60 61 Generator = StarRocksGenerator
Whether failing to parse a JSON path expression using the JSONPath dialect will log a warning.
Where star expansion places the columns of a USING or NATURAL join.
Given a(a_id, k1, k2) and b(k2, b_id, k1), SELECT * FROM a JOIN b USING (k2, k1) returns:
USING_LIST:k2, k1, a_id, b_idLEFT_TABLE:k1, k2, a_id, b_idIN_PLACE:a_id, k1, k2, b_id
When join columns come first, this applies at every join: each USING join moves its columns ahead of all the columns to its left.
Maps function expressions to their default output column name(s).
For example, in Postgres, generate_series function outputs a column named "generate_series" by default, so we map the ExplodingGenerateSeries expression to "generate_series" string.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
21 class Tokenizer(MySQL.Tokenizer): 22 # Unlike MySQL, "#" doesn't start a comment 23 COMMENTS = ["--", ("/*", "*/")] 24 DASH_COMMENT_REQUIRES_BOUNDARY = False 25 COMMENTS_TERMINATE_AT_NEWLINE_ONLY = False 26 27 KEYWORDS = { 28 **MySQL.Tokenizer.KEYWORDS, 29 "ADD BACKEND BLACKLIST": TokenType.COMMAND, 30 "ADD COMPUTE NODE BLACKLIST": TokenType.COMMAND, 31 "ADD SQL DIGEST BLACKLIST": TokenType.COMMAND, 32 "ADD SQLBLACKLIST": TokenType.COMMAND, 33 "ADMIN": TokenType.COMMAND, 34 "BACKUP": TokenType.COMMAND, 35 "CANCEL": TokenType.COMMAND, 36 "DEALLOCATE": TokenType.COMMAND, 37 "DELETE BACKEND BLACKLIST": TokenType.COMMAND, 38 "DELETE COMPUTE NODE BLACKLIST": TokenType.COMMAND, 39 "DELETE SQL DIGEST BLACKLIST": TokenType.COMMAND, 40 "DELETE SQLBLACKLIST": TokenType.COMMAND, 41 "EXPORT": TokenType.COMMAND, 42 "HLL": TokenType.HLLSKETCH, 43 "INSTALL": TokenType.COMMAND, 44 "LARGEINT": TokenType.INT128, 45 "PAUSE": TokenType.COMMAND, 46 "RECOVER": TokenType.COMMAND, 47 "REFRESH": TokenType.REFRESH, 48 "RESTORE": TokenType.COMMAND, 49 "RESUME": TokenType.COMMAND, 50 "STOP": TokenType.COMMAND, 51 "SUBMIT": TokenType.COMMAND, 52 "TRANSLATE TRINO": TokenType.COMMAND, 53 "UNINSTALL": TokenType.COMMAND, 54 } 55 KEYWORDS.pop("IGNORE") 56 KEYWORDS.pop("#>") 57 KEYWORDS.pop("#>>")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- dialect
- tokenize
- sql
- size
- tokens
10class Tableau(Dialect): 11 LOG_BASE_FIRST = False 12 13 class Tokenizer(tokens.Tokenizer): 14 IDENTIFIERS = [("[", "]")] 15 QUOTES = ["'", '"'] 16 17 Generator = TableauGenerator 18 19 Parser = TableauParser
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- HEX_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- KEYWORDS
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
11class Teradata(Dialect): 12 TYPED_DIVISION = True 13 14 TIME_MAPPING = { 15 "YY": "%y", 16 "Y4": "%Y", 17 "YYYY": "%Y", 18 "M4": "%B", 19 "M3": "%b", 20 "M": "%-M", 21 "MI": "%M", 22 "MM": "%m", 23 "MMM": "%b", 24 "MMMM": "%B", 25 "D": "%-d", 26 "DD": "%d", 27 "D3": "%j", 28 "DDD": "%j", 29 "H": "%-H", 30 "HH": "%H", 31 "HH24": "%H", 32 "S": "%-S", 33 "SS": "%S", 34 "SSSSSS": "%f", 35 "E": "%a", 36 "EE": "%a", 37 "E3": "%a", 38 "E4": "%A", 39 "EEE": "%a", 40 "EEEE": "%A", 41 } 42 43 class Tokenizer(tokens.Tokenizer): 44 # Tested each of these and they work, although there is no 45 # Teradata documentation explicitly mentioning them. 46 HEX_STRINGS = [("X'", "'"), ("x'", "'"), ("0x", "")] 47 # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Exprs-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance 48 # https://docs.teradata.com/r/SQL-Functions-Operators-Exprs-and-Predicates/June-2017/Arithmetic-Trigonometric-Hyperbolic-Operators/Functions 49 KEYWORDS = { 50 **tokens.Tokenizer.KEYWORDS, 51 "**": TokenType.DSTAR, 52 "^=": TokenType.NEQ, 53 "BYTEINT": TokenType.SMALLINT, 54 "COLLECT": TokenType.COMMAND, 55 "DEL": TokenType.DELETE, 56 "EQ": TokenType.EQ, 57 "GE": TokenType.GTE, 58 "GT": TokenType.GT, 59 "HELP": TokenType.COMMAND, 60 "INS": TokenType.INSERT, 61 "LE": TokenType.LTE, 62 "LOCKING": TokenType.LOCK, 63 "LT": TokenType.LT, 64 "MINUS": TokenType.EXCEPT, 65 "MOD": TokenType.MOD, 66 "NE": TokenType.NEQ, 67 "NOT=": TokenType.NEQ, 68 "SAMPLE": TokenType.TABLE_SAMPLE, 69 "SEL": TokenType.SELECT, 70 "ST_GEOMETRY": TokenType.GEOMETRY, 71 "TOP": TokenType.TOP, 72 "UPD": TokenType.UPDATE, 73 } 74 KEYWORDS.pop("/*+") 75 76 # Teradata does not support % as a modulo operator 77 SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS} 78 SINGLE_TOKENS.pop("%") 79 80 Parser = TeradataParser 81 82 Generator = TeradataGenerator
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
Associates this dialect's time formats with their equivalent Python strftime formats.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
43 class Tokenizer(tokens.Tokenizer): 44 # Tested each of these and they work, although there is no 45 # Teradata documentation explicitly mentioning them. 46 HEX_STRINGS = [("X'", "'"), ("x'", "'"), ("0x", "")] 47 # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Exprs-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance 48 # https://docs.teradata.com/r/SQL-Functions-Operators-Exprs-and-Predicates/June-2017/Arithmetic-Trigonometric-Hyperbolic-Operators/Functions 49 KEYWORDS = { 50 **tokens.Tokenizer.KEYWORDS, 51 "**": TokenType.DSTAR, 52 "^=": TokenType.NEQ, 53 "BYTEINT": TokenType.SMALLINT, 54 "COLLECT": TokenType.COMMAND, 55 "DEL": TokenType.DELETE, 56 "EQ": TokenType.EQ, 57 "GE": TokenType.GTE, 58 "GT": TokenType.GT, 59 "HELP": TokenType.COMMAND, 60 "INS": TokenType.INSERT, 61 "LE": TokenType.LTE, 62 "LOCKING": TokenType.LOCK, 63 "LT": TokenType.LT, 64 "MINUS": TokenType.EXCEPT, 65 "MOD": TokenType.MOD, 66 "NE": TokenType.NEQ, 67 "NOT=": TokenType.NEQ, 68 "SAMPLE": TokenType.TABLE_SAMPLE, 69 "SEL": TokenType.SELECT, 70 "ST_GEOMETRY": TokenType.GEOMETRY, 71 "TOP": TokenType.TOP, 72 "UPD": TokenType.UPDATE, 73 } 74 KEYWORDS.pop("/*+") 75 76 # Teradata does not support % as a modulo operator 77 SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS} 78 SINGLE_TOKENS.pop("%")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
10class Trino(Presto): 11 SUPPORTS_USER_DEFINED_TYPES = False 12 LOG_BASE_FIRST = True 13 CONCAT_WS_COALESCE = True 14 15 class Tokenizer(Presto.Tokenizer): 16 KEYWORDS = { 17 **Presto.Tokenizer.KEYWORDS, 18 "REFRESH": TokenType.REFRESH, 19 "DECLARE": TokenType.DECLARE, 20 } 21 # Trino has no `SQL SECURITY` clause, only bare `SECURITY DEFINER`/`INVOKER`; 22 # the merged base keyword otherwise eats the `SQL` in `LANGUAGE SQL SECURITY DEFINER`. 23 KEYWORDS.pop("SQL SECURITY") 24 25 Parser = TrinoParser 26 27 Generator = TrinoGenerator
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
15 class Tokenizer(Presto.Tokenizer): 16 KEYWORDS = { 17 **Presto.Tokenizer.KEYWORDS, 18 "REFRESH": TokenType.REFRESH, 19 "DECLARE": TokenType.DECLARE, 20 } 21 # Trino has no `SQL SECURITY` clause, only bare `SECURITY DEFINER`/`INVOKER`; 22 # the merged base keyword otherwise eats the `SQL` in `LANGUAGE SQL SECURITY DEFINER`. 23 KEYWORDS.pop("SQL SECURITY")
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- IDENTIFIERS
- QUOTES
- STRING_ESCAPES
- VAR_SINGLE_TOKENS
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMANDS
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
15class TSQL(Dialect): 16 # Week truncation follows @@DATEFIRST, which defaults to 7 (Sunday) 17 WEEK_OFFSET = -1 18 19 LOG_BASE_FIRST = False 20 TYPED_DIVISION = True 21 CONCAT_COALESCE = True 22 CONCAT_WS_COALESCE = True 23 JSON_EXTRACT_SCALAR_SCALAR_ONLY = True 24 NORMALIZATION_STRATEGY = NormalizationStrategy.CASE_INSENSITIVE 25 ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False 26 ALTER_TABLE_DROP_REQUIRED_FOR_EACH_COLUMN = False 27 28 TIME_FORMAT = "'yyyy-mm-dd hh:mm:ss'" 29 30 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 31 32 DATE_PART_MAPPING = { 33 **Dialect.DATE_PART_MAPPING, 34 "QQ": "QUARTER", 35 "M": "MONTH", 36 "Y": "DAYOFYEAR", 37 "WW": "WEEK", 38 "N": "MINUTE", 39 "SS": "SECOND", 40 "MCS": "MICROSECOND", 41 "TZOFFSET": "TIMEZONE_MINUTE", 42 "TZ": "TIMEZONE_MINUTE", 43 "ISO_WEEK": "WEEKISO", 44 "ISOWK": "WEEKISO", 45 "ISOWW": "WEEKISO", 46 } 47 48 TIME_MAPPING = { 49 "year": "%Y", 50 "dayofyear": "%j", 51 "day": "%d", 52 "dy": "%d", 53 "y": "%Y", 54 "week": "%W", 55 "ww": "%W", 56 "wk": "%W", 57 "isowk": "%V", 58 "isoww": "%V", 59 "iso_week": "%V", 60 "hour": "%h", 61 "hh": "%I", 62 "minute": "%M", 63 "mi": "%M", 64 "n": "%M", 65 "second": "%S", 66 "ss": "%S", 67 "s": "%-S", 68 "millisecond": "%f", 69 "ms": "%f", 70 "weekday": "%w", 71 "dw": "%w", 72 "month": "%m", 73 "mm": "%M", 74 "m": "%-M", 75 "Y": "%Y", 76 "YYYY": "%Y", 77 "YY": "%y", 78 "MMMM": "%B", 79 "MMM": "%b", 80 "MM": "%m", 81 "M": "%-m", 82 "dddd": "%A", 83 "dd": "%d", 84 "d": "%-d", 85 "HH": "%H", 86 "H": "%-H", 87 "h": "%-I", 88 "ffffff": "%f", 89 "yyyy": "%Y", 90 "yy": "%y", 91 } 92 93 CONVERT_FORMAT_MAPPING = { 94 "0": "%b %d %Y %-I:%M%p", 95 "1": "%m/%d/%y", 96 "2": "%y.%m.%d", 97 "3": "%d/%m/%y", 98 "4": "%d.%m.%y", 99 "5": "%d-%m-%y", 100 "6": "%d %b %y", 101 "7": "%b %d, %y", 102 "8": "%H:%M:%S", 103 "9": "%b %d %Y %-I:%M:%S:%f%p", 104 "10": "mm-dd-yy", 105 "11": "yy/mm/dd", 106 "12": "yymmdd", 107 "13": "%d %b %Y %H:%M:ss:%f", 108 "14": "%H:%M:%S:%f", 109 "20": "%Y-%m-%d %H:%M:%S", 110 "21": "%Y-%m-%d %H:%M:%S.%f", 111 "22": "%m/%d/%y %-I:%M:%S %p", 112 "23": "%Y-%m-%d", 113 "24": "%H:%M:%S", 114 "25": "%Y-%m-%d %H:%M:%S.%f", 115 "100": "%b %d %Y %-I:%M%p", 116 "101": "%m/%d/%Y", 117 "102": "%Y.%m.%d", 118 "103": "%d/%m/%Y", 119 "104": "%d.%m.%Y", 120 "105": "%d-%m-%Y", 121 "106": "%d %b %Y", 122 "107": "%b %d, %Y", 123 "108": "%H:%M:%S", 124 "109": "%b %d %Y %-I:%M:%S:%f%p", 125 "110": "%m-%d-%Y", 126 "111": "%Y/%m/%d", 127 "112": "%Y%m%d", 128 "113": "%d %b %Y %H:%M:%S:%f", 129 "114": "%H:%M:%S:%f", 130 "120": "%Y-%m-%d %H:%M:%S", 131 "121": "%Y-%m-%d %H:%M:%S.%f", 132 "126": "%Y-%m-%dT%H:%M:%S.%f", 133 } 134 135 FORMAT_TIME_MAPPING = { 136 "y": "%B %Y", 137 "d": "%m/%d/%Y", 138 "H": "%-H", 139 "h": "%-I", 140 "s": "%Y-%m-%d %H:%M:%S", 141 "D": "%A,%B,%Y", 142 "f": "%A,%B,%Y %-I:%M %p", 143 "F": "%A,%B,%Y %-I:%M:%S %p", 144 "g": "%m/%d/%Y %-I:%M %p", 145 "G": "%m/%d/%Y %-I:%M:%S %p", 146 "M": "%B %-d", 147 "m": "%B %-d", 148 "O": "%Y-%m-%dT%H:%M:%S", 149 "u": "%Y-%M-%D %H:%M:%S%z", 150 "U": "%A, %B %D, %Y %H:%M:%S%z", 151 "T": "%-I:%M:%S %p", 152 "t": "%-I:%M", 153 "Y": "%a %Y", 154 } 155 156 class Tokenizer(tokens.Tokenizer): 157 IDENTIFIERS = [("[", "]"), '"'] 158 QUOTES = ["'", '"'] 159 HEX_STRINGS = [("0x", ""), ("0X", "")] 160 VAR_SINGLE_TOKENS = {"@", "$", "#"} 161 162 KEYWORDS = { 163 **tokens.Tokenizer.KEYWORDS, 164 "CLUSTERED INDEX": TokenType.INDEX, 165 "DATETIME2": TokenType.DATETIME2, 166 "DATETIMEOFFSET": TokenType.TIMESTAMPTZ, 167 "DECLARE": TokenType.DECLARE, 168 "EXEC": TokenType.EXECUTE, 169 "GO": TokenType.COMMAND, 170 "IMAGE": TokenType.IMAGE, 171 "MONEY": TokenType.MONEY, 172 "NONCLUSTERED INDEX": TokenType.INDEX, 173 "NTEXT": TokenType.TEXT, 174 "OPTION": TokenType.OPTION, 175 "OUTPUT": TokenType.RETURNING, 176 "PRINT": TokenType.COMMAND, 177 "PROC": TokenType.PROCEDURE, 178 "REAL": TokenType.FLOAT, 179 "ROWVERSION": TokenType.ROWVERSION, 180 "SMALLDATETIME": TokenType.SMALLDATETIME, 181 "SMALLMONEY": TokenType.SMALLMONEY, 182 "SQL_VARIANT": TokenType.VARIANT, 183 "SYSTEM_USER": TokenType.CURRENT_USER, 184 "TOP": TokenType.TOP, 185 "TIMESTAMP": TokenType.ROWVERSION, 186 "TINYINT": TokenType.UTINYINT, 187 "UNIQUEIDENTIFIER": TokenType.UUID, 188 "UPDATE STATISTICS": TokenType.COMMAND, 189 "XML": TokenType.XML, 190 } 191 KEYWORDS.pop("/*+") 192 193 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.END} - {TokenType.EXECUTE} 194 195 Parser = TSQLParser 196 197 Generator = TSQLGenerator
First day of the week in DATE_TRUNC(week). Defaults to 0 (Monday). -1 would be Sunday.
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Whether JSON_EXTRACT_SCALAR returns null if a non-scalar value is selected.
Specifies the strategy according to which identifiers should be normalized.
Associates this dialect's time formats with their equivalent Python strftime formats.
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
156 class Tokenizer(tokens.Tokenizer): 157 IDENTIFIERS = [("[", "]"), '"'] 158 QUOTES = ["'", '"'] 159 HEX_STRINGS = [("0x", ""), ("0X", "")] 160 VAR_SINGLE_TOKENS = {"@", "$", "#"} 161 162 KEYWORDS = { 163 **tokens.Tokenizer.KEYWORDS, 164 "CLUSTERED INDEX": TokenType.INDEX, 165 "DATETIME2": TokenType.DATETIME2, 166 "DATETIMEOFFSET": TokenType.TIMESTAMPTZ, 167 "DECLARE": TokenType.DECLARE, 168 "EXEC": TokenType.EXECUTE, 169 "GO": TokenType.COMMAND, 170 "IMAGE": TokenType.IMAGE, 171 "MONEY": TokenType.MONEY, 172 "NONCLUSTERED INDEX": TokenType.INDEX, 173 "NTEXT": TokenType.TEXT, 174 "OPTION": TokenType.OPTION, 175 "OUTPUT": TokenType.RETURNING, 176 "PRINT": TokenType.COMMAND, 177 "PROC": TokenType.PROCEDURE, 178 "REAL": TokenType.FLOAT, 179 "ROWVERSION": TokenType.ROWVERSION, 180 "SMALLDATETIME": TokenType.SMALLDATETIME, 181 "SMALLMONEY": TokenType.SMALLMONEY, 182 "SQL_VARIANT": TokenType.VARIANT, 183 "SYSTEM_USER": TokenType.CURRENT_USER, 184 "TOP": TokenType.TOP, 185 "TIMESTAMP": TokenType.ROWVERSION, 186 "TINYINT": TokenType.UTINYINT, 187 "UNIQUEIDENTIFIER": TokenType.UUID, 188 "UPDATE STATISTICS": TokenType.COMMAND, 189 "XML": TokenType.XML, 190 } 191 KEYWORDS.pop("/*+") 192 193 COMMANDS = {*tokens.Tokenizer.COMMANDS, TokenType.END} - {TokenType.EXECUTE}
Inherited Members
- sqlglot.tokens.Tokenizer
- Tokenizer
- SINGLE_TOKENS
- BIT_STRINGS
- BYTE_STRINGS
- NATIONAL_RAW_STRINGS
- RAW_STRINGS
- HEREDOC_STRINGS
- UNICODE_STRINGS
- STRING_ESCAPES
- IDENTIFIER_ESCAPES
- HEREDOC_TAG_IS_IDENTIFIER
- HEREDOC_STRING_ALTERNATIVE
- STRING_ESCAPES_ALLOWED_IN_RAW_STRINGS
- NUMERIC_ESCAPES
- DROP_UNKNOWN_ESCAPES
- NUMERIC_ESCAPES_ARE_BYTES
- LONE_SURROGATE_REPLACEMENT
- NESTED_COMMENTS
- DASH_COMMENT_REQUIRES_BOUNDARY
- COMMENTS_TERMINATE_AT_NEWLINE_ONLY
- HINT_START
- TOKENS_PRECEDING_HINT
- COMMAND_PREFIX_TOKENS
- NUMERIC_LITERALS
- NUMBERS_CAN_HAVE_DECIMALS
- COMMENTS
- dialect
- tokenize
- sql
- size
- tokens
415class Dialect(metaclass=_Dialect): 416 INDEX_OFFSET = 0 417 """The base index offset for arrays.""" 418 419 WEEK_OFFSET = 0 420 """First day of the week in DATE_TRUNC(week). Defaults to 0 (Monday). -1 would be Sunday.""" 421 422 UNNEST_COLUMN_ONLY = False 423 """Whether `UNNEST` table aliases are treated as column aliases.""" 424 425 ALIAS_POST_TABLESAMPLE = False 426 """Whether the table alias comes after tablesample.""" 427 428 TABLESAMPLE_SIZE_IS_PERCENT = False 429 """Whether a size in the table sample clause represents percentage.""" 430 431 NORMALIZATION_STRATEGY = NormalizationStrategy.LOWERCASE 432 """Specifies the strategy according to which identifiers should be normalized.""" 433 434 ASCII_ONLY_NORMALIZATION = False 435 """Whether identifiers are only normalized with respect to ASCII characters, e.g. `Ä` and 436 `ä` are different identifiers in DuckDB, but the same identifier in Spark.""" 437 438 IDENTIFIERS_CAN_START_WITH_DIGIT = False 439 """Whether an unquoted identifier can start with a digit.""" 440 441 DPIPE_IS_STRING_CONCAT = True 442 """Whether the DPIPE token (`||`) is a string concatenation operator.""" 443 444 STRICT_STRING_CONCAT = False 445 """Whether `CONCAT`'s arguments must be strings.""" 446 447 SUPPORTS_USER_DEFINED_TYPES = True 448 """Whether user-defined data types are supported.""" 449 450 SUPPORTS_COLUMN_JOIN_MARKS = False 451 """Whether the old-style outer join (+) syntax is supported.""" 452 453 COPY_PARAMS_ARE_CSV = True 454 """Separator of COPY statement parameters.""" 455 456 NORMALIZE_FUNCTIONS: bool | str = "upper" 457 """ 458 Determines how function names are going to be normalized. 459 Possible values: 460 "upper" or True: Convert names to uppercase. 461 "lower": Convert names to lowercase. 462 False: Disables function name normalization. 463 """ 464 465 ORIGINAL_NAME_META_KEY: str | None = None 466 """ 467 Dialect-specific metadata key for preserving original function names, or None to disable. 468 Only generators using the same key reuse these names, allowing round trips of aliases 469 that share an AST node, e.g. JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery. 470 """ 471 472 LOG_BASE_FIRST: bool | None = True 473 """ 474 Whether the base comes first in the `LOG` function. 475 Possible values: `True`, `False`, `None` (two arguments are not supported by `LOG`) 476 """ 477 478 NULL_ORDERING = "nulls_are_small" 479 """ 480 Default `NULL` ordering method to use if not explicitly set. 481 Possible values: `"nulls_are_small"`, `"nulls_are_large"`, `"nulls_are_last"` 482 """ 483 484 TYPED_DIVISION = False 485 """ 486 Whether the behavior of `a / b` depends on the types of `a` and `b`. 487 False means `a / b` is always float division. 488 True means `a / b` is integer division if both `a` and `b` are integers. 489 """ 490 491 SAFE_DIVISION = False 492 """Whether division by zero throws an error (`False`) or returns NULL (`True`).""" 493 494 CONCAT_COALESCE = False 495 """A `NULL` arg in `CONCAT` yields `NULL` by default, but in some dialects it yields an empty string.""" 496 497 CONCAT_WS_COALESCE = False 498 """A `NULL` arg in `CONCAT_WS` yields `NULL` by default, but in some dialects it is skipped.""" 499 500 HEX_LOWERCASE = False 501 """Whether the `HEX` function returns a lowercase hexadecimal string.""" 502 503 DATE_FORMAT = "'%Y-%m-%d'" 504 DATEINT_FORMAT = "'%Y%m%d'" 505 TIME_FORMAT = "'%Y-%m-%d %H:%M:%S'" 506 507 TIME_MAPPING: dict[str, str] = {} 508 """Associates this dialect's time formats with their equivalent Python `strftime` formats.""" 509 510 # https://cloud.google.com/bigquery/docs/reference/standard-sql/format-elements#format_model_rules_date_time 511 # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Exprs-and-Predicates/March-2017/Data-Type-Conversions/Character-to-DATE-Conversion/Forcing-a-FORMAT-on-CAST-for-Converting-Character-to-DATE 512 FORMAT_MAPPING: dict[str, str] = {} 513 """ 514 Helper which is used for parsing the special syntax `CAST(x AS DATE FORMAT 'yyyy')`. 515 If empty, the corresponding trie will be constructed off of `TIME_MAPPING`. 516 """ 517 518 UNESCAPED_SEQUENCES: dict[str, str] = {} 519 """Mapping of an escaped sequence (`\\n`) to its unescaped version (`\n`).""" 520 521 STRINGS_SUPPORT_ESCAPED_SEQUENCES: bool = False 522 """Whether string literals support escape sequences (e.g. `\\n`). Set by the metaclass based on the tokenizer's STRING_ESCAPES.""" 523 524 BYTE_STRINGS_SUPPORT_ESCAPED_SEQUENCES: bool = False 525 """Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.""" 526 527 IDENTIFIER_ESCAPED_SEQUENCES: dict[str, str] = {} 528 """Mapping of an identifier escape char (`\\`) to its escaped version (`\\\\`). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.""" 529 530 INVERSE_VECTOR_TYPE_ALIASES: dict[str, str] = {} 531 """Mapping of vector type aliases back to their canonical names. Overridden by dialects like SingleStore.""" 532 533 PSEUDOCOLUMNS: set[str] = set() 534 """ 535 Columns that are auto-generated by the engine corresponding to this dialect. 536 For example, such columns may be excluded from `SELECT *` queries. 537 """ 538 539 SUPPORTS_POSITIONAL_COLUMN_REFS = False 540 """Whether qualified `$N` references the Nth column of their source.""" 541 542 PREFER_CTE_ALIAS_COLUMN = False 543 """ 544 Some dialects, such as Snowflake, allow you to reference a CTE column alias in the 545 HAVING clause of the CTE. This flag will cause the CTE alias columns to override 546 any projection aliases in the subquery. 547 548 For example, 549 WITH y(c) AS ( 550 SELECT SUM(a) FROM (SELECT 1 a) AS x HAVING c > 0 551 ) SELECT c FROM y; 552 553 will be rewritten as 554 555 WITH y(c) AS ( 556 SELECT SUM(a) AS c FROM (SELECT 1 AS a) AS x HAVING c > 0 557 ) SELECT c FROM y; 558 """ 559 560 COPY_PARAMS_ARE_CSV = True 561 """ 562 Whether COPY statement parameters are separated by comma or whitespace 563 """ 564 565 FORCE_EARLY_ALIAS_REF_EXPANSION = False 566 """ 567 Whether alias reference expansion (_expand_alias_refs()) should run before column qualification (_qualify_columns()). 568 569 For example: 570 WITH data AS ( 571 SELECT 572 1 AS id, 573 2 AS my_id 574 ) 575 SELECT 576 id AS my_id 577 FROM 578 data 579 WHERE 580 my_id = 1 581 GROUP BY 582 my_id, 583 HAVING 584 my_id = 1 585 586 In most dialects, "my_id" would refer to "data.my_id" across the query, except: 587 - BigQuery, which will forward the alias to GROUP BY + HAVING clauses i.e 588 it resolves to "WHERE my_id = 1 GROUP BY id HAVING id = 1" 589 - Clickhouse, which will forward the alias across the query i.e it resolves 590 to "WHERE id = 1 GROUP BY id HAVING id = 1" 591 """ 592 593 EXPAND_ONLY_GROUP_ALIAS_REF = False 594 """Whether alias reference expansion before qualification should only happen for the GROUP BY clause.""" 595 596 ANNOTATE_ALL_SCOPES = False 597 """Whether to annotate all scopes during optimization. Used by BigQuery for UNNEST support.""" 598 599 DISABLES_ALIAS_REF_EXPANSION = False 600 """ 601 Whether alias reference expansion is disabled for this dialect. 602 603 Some dialects like Oracle do NOT support referencing aliases in projections or WHERE clauses. 604 The original expression must be repeated instead. 605 606 For example, in Oracle: 607 SELECT y.foo AS bar, bar * 2 AS baz FROM y -- INVALID 608 SELECT y.foo AS bar, y.foo * 2 AS baz FROM y -- VALID 609 """ 610 611 SUPPORTS_ALIAS_REFS_IN_JOIN_CONDITIONS = False 612 """ 613 Whether alias references are allowed in JOIN ... ON clauses. 614 615 Most dialects do not support this, but Snowflake allows alias expansion in the JOIN ... ON 616 clause (and almost everywhere else) 617 618 For example, in Snowflake: 619 SELECT a.id AS user_id FROM a JOIN b ON user_id = b.id -- VALID 620 621 Reference: https://docs.snowflake.com/en/sql-reference/sql/select#usage-notes 622 """ 623 624 SUPPORTS_ORDER_BY_ALL = False 625 """ 626 Whether ORDER BY ALL is supported (expands to all the selected columns) as in DuckDB, Spark3/Databricks 627 """ 628 629 SUPPORTS_LIMIT_ALL = False 630 """ 631 Whether LIMIT ALL is supported (equivalent to no limit) as in Postgres. 632 """ 633 634 PROJECTION_ALIASES_SHADOW_SOURCE_NAMES = False 635 """ 636 Whether projection alias names can shadow table/source names in GROUP BY and HAVING clauses. 637 638 In BigQuery, when a projection alias has the same name as a source table, the alias takes 639 precedence in GROUP BY and HAVING clauses, and the table becomes inaccessible by that name. 640 641 For example, in BigQuery: 642 SELECT id, ARRAY_AGG(col) AS custom_fields 643 FROM custom_fields 644 GROUP BY id 645 HAVING id >= 1 646 647 The "custom_fields" source is shadowed by the projection alias, so we cannot qualify "id" 648 with "custom_fields" in GROUP BY/HAVING. 649 """ 650 651 TABLE_ALIASES_SHADOW_COLUMN_NAMES = False 652 """ 653 Whether a whole-row reference to a table alias takes precedence over a same-named column. 654 """ 655 656 TABLES_REFERENCEABLE_AS_COLUMNS = False 657 """ 658 Whether table names can be referenced as columns (treated as structs). 659 660 BigQuery allows tables to be referenced as columns in queries, automatically treating 661 them as struct values containing all the table's columns. 662 663 For example, in BigQuery: 664 SELECT t FROM my_table AS t -- Returns entire row as a struct 665 """ 666 667 SUPPORTS_STRUCT_STAR_EXPANSION = False 668 """ 669 Whether the dialect supports expanding struct fields using star notation (e.g., struct_col.*). 670 671 BigQuery allows struct fields to be expanded with the star operator: 672 SELECT t.struct_col.* FROM table t 673 RisingWave also allows struct field expansion with the star operator using parentheses: 674 SELECT (t.struct_col).* FROM table t 675 676 This expands to all fields within the struct. 677 """ 678 679 STAR_ILIKE_BACKSLASH_ESCAPE = False 680 """ 681 Whether a backslash in a `SELECT * ILIKE '<pattern>'` filter escapes the following character, 682 so that e.g. `\\_` matches a literal underscore (Snowflake). When False, backslashes in the 683 pattern are matched literally (DuckDB). 684 """ 685 686 EXCLUDES_PSEUDOCOLUMNS_FROM_STAR = False 687 """ 688 Whether pseudocolumns should be excluded from star expansion (SELECT *). 689 690 Pseudocolumns are special dialect-specific columns (e.g., Oracle's ROWNUM, ROWID, LEVEL, 691 or BigQuery's _PARTITIONTIME, _PARTITIONDATE) that are implicitly available but not part 692 of the table schema. When this is True, SELECT * will not include these pseudocolumns; 693 they must be explicitly selected. 694 """ 695 696 USING_COLUMN_ORDER = UsingColumnOrder.USING_LIST 697 """ 698 Where star expansion places the columns of a `USING` or `NATURAL` join. 699 700 Given `a(a_id, k1, k2)` and `b(k2, b_id, k1)`, `SELECT * FROM a JOIN b USING (k2, k1)` returns: 701 - `USING_LIST`: `k2, k1, a_id, b_id` 702 - `LEFT_TABLE`: `k1, k2, a_id, b_id` 703 - `IN_PLACE`: `a_id, k1, k2, b_id` 704 705 When join columns come first, this applies at every join: each USING join moves its columns 706 ahead of all the columns to its left. 707 """ 708 709 QUERY_RESULTS_ARE_STRUCTS = False 710 """ 711 Whether query results are typed as structs in metadata for type inference. 712 713 In BigQuery, subqueries store their column types as a STRUCT in metadata, 714 enabling special type inference for ARRAY(SELECT ...) expressions: 715 ARRAY(SELECT x, y FROM t) → ARRAY<STRUCT<...>> 716 717 For single column subqueries, BigQuery unwraps the struct: 718 ARRAY(SELECT x FROM t) → ARRAY<type_of_x> 719 720 This is metadata-only for type inference. 721 """ 722 723 REQUIRES_PARENTHESIZED_STRUCT_ACCESS = False 724 """ 725 Whether struct field access requires parentheses around the expression. 726 727 RisingWave requires parentheses for struct field access in certain contexts: 728 SELECT (col.field).subfield FROM table -- Parentheses required 729 730 Without parentheses, the parser may not correctly interpret nested struct access. 731 732 Reference: https://docs.risingwave.com/sql/data-types/struct#retrieve-data-in-a-struct 733 """ 734 735 SUPPORTS_NULL_TYPE = False 736 """ 737 Whether NULL/VOID is supported as a valid data type (not just a value). 738 739 Databricks and Spark v3+ support NULL as an actual type, allowing expressions like: 740 SELECT NULL AS col -- Has type NULL, not just value NULL 741 CAST(x AS VOID) -- Valid type cast 742 """ 743 744 COALESCE_COMPARISON_NON_STANDARD = False 745 """ 746 Whether COALESCE in comparisons has non-standard NULL semantics. 747 748 We can't convert `COALESCE(x, 1) = 2` into `NOT x IS NULL AND x = 2` for redshift, 749 because they are not always equivalent. For example, if `x` is `NULL` and it comes 750 from a table, then the result is `NULL`, despite `FALSE AND NULL` evaluating to `FALSE`. 751 752 In standard SQL and most dialects, these expressions are equivalent, but Redshift treats 753 table NULLs differently in this context. 754 """ 755 756 HAS_DISTINCT_ARRAY_CONSTRUCTORS = False 757 """ 758 Whether the ARRAY constructor is context-sensitive, i.e in Redshift ARRAY[1, 2, 3] != ARRAY(1, 2, 3) 759 as the former is of type INT[] vs the latter which is SUPER 760 """ 761 762 SUPPORTS_FIXED_SIZE_ARRAYS = False 763 """ 764 Whether expressions such as x::INT[5] should be parsed as fixed-size array defs/casts e.g. 765 in DuckDB. In dialects which don't support fixed size arrays such as Snowflake, this should 766 be interpreted as a subscript/index operator. 767 """ 768 769 STRICT_JSON_PATH_SYNTAX = True 770 """Whether failing to parse a JSON path expression using the JSONPath dialect will log a warning.""" 771 772 JSON_PATH_SINGLE_DOT_IS_WILDCARD = False 773 """Whether a single DOT in a JSON path (e.g. $.) is treated as a valid wildcard key.""" 774 775 ON_CONDITION_EMPTY_BEFORE_ERROR = True 776 """Whether "X ON EMPTY" should come before "X ON ERROR" (for dialects like T-SQL, MySQL, Oracle).""" 777 778 ARRAY_AGG_INCLUDES_NULLS: bool | None = True 779 """Whether ArrayAgg needs to filter NULL values.""" 780 781 ARRAY_FUNCS_PROPAGATES_NULLS = False 782 """Whether Array update functions return NULL when the input array is NULL.""" 783 784 PROMOTE_TO_INFERRED_DATETIME_TYPE = False 785 """ 786 This flag is used in the optimizer's canonicalize rule and determines whether x will be promoted 787 to the literal's type in x::DATE < '2020-01-01 12:05:03' (i.e., DATETIME). When false, the literal 788 is cast to x's type to match it instead. 789 """ 790 791 SUPPORTS_VALUES_DEFAULT = True 792 """Whether the DEFAULT keyword is supported in the VALUES clause.""" 793 794 NUMBERS_CAN_BE_UNDERSCORE_SEPARATED = False 795 """Whether number literals can include underscores for better readability""" 796 797 HEX_STRING_IS_INTEGER_TYPE: bool = False 798 """Whether hex strings such as x'CC' evaluate to integer or binary/blob type""" 799 800 REGEXP_EXTRACT_DEFAULT_GROUP = 0 801 """The default value for the capturing group.""" 802 803 REGEXP_EXTRACT_POSITION_OVERFLOW_RETURNS_NULL = True 804 """Whether REGEXP_EXTRACT returns NULL when the position arg exceeds the string length.""" 805 806 SET_OP_DISTINCT_BY_DEFAULT: dict[Type[exp.Expr], bool | None] = { 807 exp.Except: True, 808 exp.Intersect: True, 809 exp.Union: True, 810 } 811 """ 812 Whether a set operation uses DISTINCT by default. This is `None` when either `DISTINCT` or `ALL` 813 must be explicitly specified. 814 """ 815 816 INTERSECT_BINDS_TIGHTER_THAN_UNION_AND_EXCEPT = True 817 """ 818 Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't 819 parenthesized. If False, all set operations have equal precedence and associate left to right. 820 """ 821 822 CREATABLE_KIND_MAPPING: dict[str, str] = {} 823 """ 824 Helper for dialects that use a different name for the same creatable kind. For example, the Clickhouse 825 equivalent of CREATE SCHEMA is CREATE DATABASE. 826 """ 827 828 ALTER_TABLE_SUPPORTS_CASCADE = False 829 """ 830 Hive by default does not update the schema of existing partitions when a column is changed. 831 the CASCADE clause is used to indicate that the change should be propagated to all existing partitions. 832 the Spark dialect, while derived from Hive, does not support the CASCADE clause. 833 """ 834 835 # Whether ADD is present for each column added by ALTER TABLE 836 ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = True 837 838 # Whether DROP is present for each column dropped by ALTER TABLE 839 ALTER_TABLE_DROP_REQUIRED_FOR_EACH_COLUMN = True 840 841 # Whether the value/LHS of the TRY_CAST(<value> AS <type>) should strictly be a 842 # STRING type (Snowflake's case) or can be of any type 843 TRY_CAST_REQUIRES_STRING: bool | None = None 844 845 # Whether the double negation can be applied 846 # Not safe with MySQL and SQLite due to type coercion (may not return boolean) 847 SAFE_TO_ELIMINATE_DOUBLE_NEGATION = True 848 849 # Whether `x IS NOT NULL` can be normalized to `NOT x IS NULL` 850 NORMALIZE_NOT_NULL = True 851 852 # Whether the INITCAP function supports custom delimiter characters as the second argument 853 # Default delimiter characters for INITCAP function: whitespace and non-alphanumeric characters 854 INITCAP_SUPPORTS_CUSTOM_DELIMITERS = True 855 INITCAP_DEFAULT_DELIMITER_CHARS = " \t\n\r\f\v!\"#$%&'()*+,\\-./:;<=>?@\\[\\]^_`{|}~" 856 857 BYTE_STRING_IS_BYTES_TYPE: bool = False 858 """ 859 Whether byte string literals (ex: BigQuery's b'...') are typed as BYTES/BINARY 860 """ 861 862 UUID_IS_STRING_TYPE: bool = False 863 """ 864 Whether a UUID is considered a string or a UUID type. 865 """ 866 867 JSON_EXTRACT_SCALAR_SCALAR_ONLY = False 868 """ 869 Whether JSON_EXTRACT_SCALAR returns null if a non-scalar value is selected. 870 """ 871 872 DEFAULT_FUNCTIONS_COLUMN_NAMES: dict[Type[exp.Func], str | tuple[str, ...]] = {} 873 """ 874 Maps function expressions to their default output column name(s). 875 876 For example, in Postgres, generate_series function outputs a column named "generate_series" by default, 877 so we map the ExplodingGenerateSeries expression to "generate_series" string. 878 """ 879 880 DEFAULT_NULL_TYPE = exp.DType.UNKNOWN 881 """ 882 The default type of NULL for producing the correct projection type. 883 884 For example, in BigQuery the default type of the NULL value is INT64. 885 """ 886 887 LEAST_GREATEST_IGNORES_NULLS = True 888 """ 889 Whether LEAST/GREATEST functions ignore NULL values, e.g: 890 - BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL 891 - Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1 892 """ 893 894 PRIORITIZE_NON_LITERAL_TYPES = False 895 """ 896 Whether to prioritize non-literal types over literals during type annotation. 897 """ 898 899 ALIAS_POST_VERSION = True 900 """Whether the table alias comes after version (timestamp or iceberg snapshot).""" 901 902 # --- Autofilled --- 903 904 tokenizer_class = Tokenizer 905 jsonpath_tokenizer_class = JSONPathTokenizer 906 parser_class = BaseParser 907 generator_class = Generator 908 909 # A trie of the time_mapping keys 910 TIME_TRIE: dict = {} 911 FORMAT_TRIE: dict = {} 912 913 INVERSE_TIME_MAPPING: dict[str, str] = {} 914 INVERSE_TIME_TRIE: dict = {} 915 INVERSE_FORMAT_MAPPING: dict[str, str] = {} 916 INVERSE_FORMAT_TRIE: dict = {} 917 918 INVERSE_CREATABLE_KIND_MAPPING: dict[str, str] = {} 919 920 ESCAPED_SEQUENCES: dict[str, str] = {} 921 922 # Delimiters for string literals and identifiers 923 QUOTE_START = "'" 924 QUOTE_END = "'" 925 IDENTIFIER_START = '"' 926 IDENTIFIER_END = '"' 927 928 VALID_INTERVAL_UNITS: set[str] = set() 929 930 # Delimiters for bit, hex, byte and unicode literals 931 BIT_START: str | None = None 932 BIT_END: str | None = None 933 HEX_START: str | None = None 934 HEX_END: str | None = None 935 BYTE_START: str | None = None 936 BYTE_END: str | None = None 937 UNICODE_START: str | None = None 938 UNICODE_END: str | None = None 939 940 DATE_PART_MAPPING = { 941 "Y": "YEAR", 942 "YY": "YEAR", 943 "YYY": "YEAR", 944 "YYYY": "YEAR", 945 "YR": "YEAR", 946 "YEARS": "YEAR", 947 "YRS": "YEAR", 948 "MM": "MONTH", 949 "MON": "MONTH", 950 "MONS": "MONTH", 951 "MONTHS": "MONTH", 952 "D": "DAY", 953 "DD": "DAY", 954 "DAYS": "DAY", 955 "DAYOFMONTH": "DAY", 956 "DAY OF WEEK": "DAYOFWEEK", 957 "WEEKDAY": "DAYOFWEEK", 958 "DOW": "DAYOFWEEK", 959 "DW": "DAYOFWEEK", 960 "WEEKDAY_ISO": "DAYOFWEEKISO", 961 "DOW_ISO": "DAYOFWEEKISO", 962 "DW_ISO": "DAYOFWEEKISO", 963 "DAYOFWEEK_ISO": "DAYOFWEEKISO", 964 "DAY OF YEAR": "DAYOFYEAR", 965 "DOY": "DAYOFYEAR", 966 "DY": "DAYOFYEAR", 967 "W": "WEEK", 968 "WK": "WEEK", 969 "WEEKOFYEAR": "WEEK", 970 "WOY": "WEEK", 971 "WY": "WEEK", 972 "WEEK_ISO": "WEEKISO", 973 "WEEKOFYEARISO": "WEEKISO", 974 "WEEKOFYEAR_ISO": "WEEKISO", 975 "Q": "QUARTER", 976 "QTR": "QUARTER", 977 "QTRS": "QUARTER", 978 "QUARTERS": "QUARTER", 979 "H": "HOUR", 980 "HH": "HOUR", 981 "HR": "HOUR", 982 "HOURS": "HOUR", 983 "HRS": "HOUR", 984 "M": "MINUTE", 985 "MI": "MINUTE", 986 "MIN": "MINUTE", 987 "MINUTES": "MINUTE", 988 "MINS": "MINUTE", 989 "S": "SECOND", 990 "SEC": "SECOND", 991 "SECONDS": "SECOND", 992 "SECS": "SECOND", 993 "MS": "MILLISECOND", 994 "MSEC": "MILLISECOND", 995 "MSECS": "MILLISECOND", 996 "MSECOND": "MILLISECOND", 997 "MSECONDS": "MILLISECOND", 998 "MILLISEC": "MILLISECOND", 999 "MILLISECS": "MILLISECOND", 1000 "MILLISECON": "MILLISECOND", 1001 "MILLISECONDS": "MILLISECOND", 1002 "US": "MICROSECOND", 1003 "USEC": "MICROSECOND", 1004 "USECS": "MICROSECOND", 1005 "MICROSEC": "MICROSECOND", 1006 "MICROSECS": "MICROSECOND", 1007 "USECOND": "MICROSECOND", 1008 "USECONDS": "MICROSECOND", 1009 "MICROSECONDS": "MICROSECOND", 1010 "NS": "NANOSECOND", 1011 "NSEC": "NANOSECOND", 1012 "NANOSEC": "NANOSECOND", 1013 "NSECOND": "NANOSECOND", 1014 "NSECONDS": "NANOSECOND", 1015 "NANOSECS": "NANOSECOND", 1016 "EPOCH_SECOND": "EPOCH", 1017 "EPOCH_SECONDS": "EPOCH", 1018 "EPOCH_MILLISECONDS": "EPOCH_MILLISECOND", 1019 "EPOCH_MICROSECONDS": "EPOCH_MICROSECOND", 1020 "EPOCH_NANOSECONDS": "EPOCH_NANOSECOND", 1021 "TZH": "TIMEZONE_HOUR", 1022 "TZM": "TIMEZONE_MINUTE", 1023 "DEC": "DECADE", 1024 "DECS": "DECADE", 1025 "DECADES": "DECADE", 1026 "MIL": "MILLENNIUM", 1027 "MILS": "MILLENNIUM", 1028 "MILLENIA": "MILLENNIUM", 1029 "C": "CENTURY", 1030 "CENT": "CENTURY", 1031 "CENTS": "CENTURY", 1032 "CENTURIES": "CENTURY", 1033 } 1034 1035 # Specifies what types a given type can be coerced into 1036 COERCES_TO: dict[exp.DType, set[exp.DType]] = {} 1037 1038 # Specifies type inference & validation rules for expressions 1039 EXPRESSION_METADATA = EXPRESSION_METADATA.copy() 1040 1041 # Determines the supported Dialect instance settings 1042 SUPPORTED_SETTINGS = { 1043 "normalization_strategy", 1044 "version", 1045 } 1046 1047 @classmethod 1048 def get_or_raise(cls, dialect: DialectType) -> Dialect: 1049 """ 1050 Look up a dialect in the global dialect registry and return it if it exists. 1051 1052 Args: 1053 dialect: The target dialect. If this is a string, it can be optionally followed by 1054 additional key-value pairs that are separated by commas and are used to specify 1055 dialect settings, such as whether the dialect's identifiers are case-sensitive. 1056 1057 Example: 1058 >>> from sqlglot.dialects.dialect import Dialect 1059 >>> dialect = Dialect.get_or_raise("duckdb") 1060 >>> dialect = Dialect.get_or_raise("mysql, normalization_strategy = case_sensitive") 1061 1062 Returns: 1063 The corresponding Dialect instance. 1064 """ 1065 1066 if not dialect: 1067 return cls() 1068 if isinstance(dialect, _Dialect): 1069 return dialect() 1070 if isinstance(dialect, Dialect): 1071 return dialect 1072 if isinstance(dialect, str): 1073 try: 1074 dialect_name, *kv_strings = dialect.split(",") 1075 kv_pairs = (kv.split("=") for kv in kv_strings) 1076 kwargs = {} 1077 for pair in kv_pairs: 1078 key = pair[0].strip() 1079 value: bool | str | None = None 1080 1081 if len(pair) == 1: 1082 # Default initialize standalone settings to True 1083 value = True 1084 elif len(pair) == 2: 1085 value = pair[1].strip() 1086 1087 kwargs[key] = to_bool(value) 1088 1089 except ValueError: 1090 raise ValueError( 1091 f"Invalid dialect format: '{dialect}'. " 1092 "Please use the correct format: 'dialect [, k1 = v2 [, ...]]'." 1093 ) 1094 1095 result = cls.get(dialect_name.strip()) 1096 if not result: 1097 # Include both built-in dialects and any loaded dialects for better error messages 1098 all_dialects = set(DIALECT_MODULE_NAMES) | set(cls._classes.keys()) 1099 suggest_closest_match_and_fail("dialect", dialect_name, all_dialects) 1100 1101 assert result is not None 1102 return result(**kwargs) 1103 1104 raise ValueError(f"Invalid dialect type for '{dialect}': '{type(dialect)}'.") 1105 1106 @classmethod 1107 def format_time(cls, expression: str | exp.Expr | None) -> exp.Expr | None: 1108 """Converts a time format in this dialect to its equivalent Python `strftime` format.""" 1109 if isinstance(expression, str): 1110 return exp.Literal.string( 1111 # the time formats are quoted 1112 format_time(expression[1:-1], cls.TIME_MAPPING, cls.TIME_TRIE) 1113 ) 1114 1115 if expression and expression.is_string: 1116 return exp.Literal.string(format_time(expression.this, cls.TIME_MAPPING, cls.TIME_TRIE)) 1117 1118 return expression 1119 1120 def __init__(self, **kwargs) -> None: 1121 parts = str(kwargs.pop("version", sys.maxsize)).split(".") 1122 parts.extend(["0"] * (3 - len(parts))) 1123 self.version = tuple(int(p) for p in parts[:3]) 1124 1125 normalization_strategy = kwargs.pop("normalization_strategy", None) 1126 if normalization_strategy is None: 1127 self.normalization_strategy = self.NORMALIZATION_STRATEGY 1128 else: 1129 self.normalization_strategy = NormalizationStrategy(normalization_strategy.upper()) 1130 1131 self.settings = kwargs 1132 1133 for unsupported_setting in kwargs.keys() - self.SUPPORTED_SETTINGS: 1134 suggest_closest_match_and_fail("setting", unsupported_setting, self.SUPPORTED_SETTINGS) 1135 1136 def __eq__(self, other: object) -> bool: 1137 # Does not currently take dialect state into account 1138 return type(self) == other 1139 1140 def __hash__(self) -> int: 1141 # Does not currently take dialect state into account 1142 return hash(type(self)) 1143 1144 def normalize_identifier(self, expression: E) -> E: 1145 """ 1146 Transforms an identifier in a way that resembles how it'd be resolved by this dialect. 1147 1148 For example, an identifier like `FoO` would be resolved as `foo` in Postgres, because it 1149 lowercases all unquoted identifiers. On the other hand, Snowflake uppercases them, so 1150 it would resolve it as `FOO`. If it was quoted, it'd need to be treated as case-sensitive, 1151 and so any normalization would be prohibited in order to avoid "breaking" the identifier. 1152 1153 There are also dialects like Spark, which are case-insensitive even when quotes are 1154 present, and dialects like MySQL, whose resolution rules match those employed by the 1155 underlying operating system, for example they may always be case-sensitive in Linux. 1156 1157 Finally, the normalization behavior of some engines can even be controlled through flags, 1158 like in Redshift's case, where users can explicitly set enable_case_sensitive_identifier. 1159 1160 SQLGlot aims to understand and handle all of these different behaviors gracefully, so 1161 that it can analyze queries in the optimizer and successfully capture their semantics. 1162 """ 1163 if ( 1164 isinstance(expression, exp.Identifier) 1165 and self.normalization_strategy is not NormalizationStrategy.CASE_SENSITIVE 1166 and ( 1167 not expression.quoted 1168 or self.normalization_strategy 1169 in ( 1170 NormalizationStrategy.CASE_INSENSITIVE, 1171 NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE, 1172 ) 1173 ) 1174 ): 1175 if self.normalization_strategy in ( 1176 NormalizationStrategy.UPPERCASE, 1177 NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE, 1178 ): 1179 normalized = ( 1180 expression.this.translate(ASCII_UPPER) 1181 if self.ASCII_ONLY_NORMALIZATION 1182 else expression.this.upper() 1183 ) 1184 else: 1185 normalized = ( 1186 expression.this.translate(ASCII_LOWER) 1187 if self.ASCII_ONLY_NORMALIZATION 1188 else expression.this.lower() 1189 ) 1190 1191 expression.set("this", normalized) 1192 1193 return expression 1194 1195 def case_sensitive(self, text: str) -> bool: 1196 """Checks if text contains any case sensitive characters, based on the dialect's rules.""" 1197 if self.normalization_strategy is NormalizationStrategy.CASE_INSENSITIVE: 1198 return False 1199 1200 unsafe = ( 1201 str.islower 1202 if self.normalization_strategy is NormalizationStrategy.UPPERCASE 1203 else str.isupper 1204 ) 1205 return any(unsafe(char) for char in text) 1206 1207 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 1208 """Checks if an identifier can be quoted 1209 1210 Args: 1211 identifier: The identifier to check. 1212 identify: 1213 `True`: Always returns `True` except for certain cases. 1214 `"safe"`: Only returns `True` if the identifier is case-insensitive. 1215 `"unsafe"`: Only returns `True` if the identifier is case-sensitive. 1216 1217 Returns: 1218 Whether the given text can be identified. 1219 """ 1220 if identifier.quoted: 1221 return True 1222 if not identify: 1223 return False 1224 if isinstance(identifier.parent, exp.Func): 1225 return False 1226 if identify is True: 1227 return True 1228 1229 is_safe = not self.case_sensitive(identifier.this) and bool( 1230 exp.SAFE_IDENTIFIER_RE.match(identifier.this) 1231 ) 1232 1233 if identify == "safe": 1234 return is_safe 1235 if identify == "unsafe": 1236 return not is_safe 1237 1238 raise ValueError(f"Unexpected argument for identify: '{identify}'") 1239 1240 def quote_identifier(self, expression: E, identify: bool = True) -> E: 1241 """ 1242 Adds quotes to a given expression if it is an identifier. 1243 1244 Args: 1245 expression: The expression of interest. If it's not an `Identifier`, this method is a no-op. 1246 identify: If set to `False`, the quotes will only be added if the identifier is deemed 1247 "unsafe", with respect to its characters and this dialect's normalization strategy. 1248 """ 1249 if isinstance(expression, exp.Identifier): 1250 expression.set("quoted", self.can_quote(expression, identify or "unsafe")) 1251 return expression 1252 1253 def to_json_path(self, path: exp.Expr | None) -> exp.Expr | None: 1254 if isinstance(path, exp.Literal): 1255 path_text = path.name 1256 if path.is_number: 1257 path_text = f"[{path_text}]" 1258 try: 1259 return parse_json_path(path_text, self) 1260 except (ParseError, TokenError) as e: 1261 if self.STRICT_JSON_PATH_SYNTAX and not path_text.lstrip().startswith( 1262 ("lax", "strict") 1263 ): 1264 logger.warning(f"Invalid JSON path syntax. {str(e)}") 1265 1266 return path 1267 1268 def parse(self, sql: str, **opts: Unpack[ParserArgs]) -> list[exp.Expr | None]: 1269 return self.parser(**opts).parse(self.tokenize(sql), sql) 1270 1271 def parse_into( 1272 self, expression_type: exp.IntoType, sql: str, **opts: Unpack[ParserArgs] 1273 ) -> list[exp.Expr | None]: 1274 return self.parser(**opts).parse_into(expression_type, self.tokenize(sql), sql) 1275 1276 def generate( 1277 self, expression: exp.Expr, copy: bool = True, **opts: Unpack[GeneratorArgs] 1278 ) -> str: 1279 return self.generator(**opts).generate(expression, copy=copy) 1280 1281 def transpile(self, sql: str, **opts: Unpack[GeneratorArgs]) -> list[str]: 1282 return [ 1283 self.generate(expression, copy=False, **opts) if expression else "" 1284 for expression in self.parse(sql) 1285 ] 1286 1287 def tokenize(self, sql: str, dialect: DialectType = None) -> list[Token]: 1288 return self.tokenizer(dialect=dialect).tokenize(sql) 1289 1290 def tokenizer(self, dialect: DialectType = None) -> Tokenizer: 1291 return self.tokenizer_class(dialect=dialect or self) 1292 1293 def jsonpath_tokenizer(self, dialect: DialectType = None) -> JSONPathTokenizer: 1294 return self.jsonpath_tokenizer_class(dialect=dialect or self) 1295 1296 def parser(self, **opts: Unpack[ParserArgs]) -> Parser: 1297 args: ParserArgs = {"dialect": self, **opts} 1298 return self.parser_class(**args) 1299 1300 def generator(self, **opts: Unpack[GeneratorArgs]) -> Generator: 1301 args: GeneratorArgs = {"dialect": self, **opts} 1302 return self.generator_class(**args) 1303 1304 def generate_values_aliases(self, expression: exp.Values) -> list[exp.Identifier]: 1305 return [ 1306 exp.to_identifier(f"_col_{i}") 1307 for i, _ in enumerate(expression.expressions[0].expressions) 1308 ]
1120 def __init__(self, **kwargs) -> None: 1121 parts = str(kwargs.pop("version", sys.maxsize)).split(".") 1122 parts.extend(["0"] * (3 - len(parts))) 1123 self.version = tuple(int(p) for p in parts[:3]) 1124 1125 normalization_strategy = kwargs.pop("normalization_strategy", None) 1126 if normalization_strategy is None: 1127 self.normalization_strategy = self.NORMALIZATION_STRATEGY 1128 else: 1129 self.normalization_strategy = NormalizationStrategy(normalization_strategy.upper()) 1130 1131 self.settings = kwargs 1132 1133 for unsupported_setting in kwargs.keys() - self.SUPPORTED_SETTINGS: 1134 suggest_closest_match_and_fail("setting", unsupported_setting, self.SUPPORTED_SETTINGS)
First day of the week in DATE_TRUNC(week). Defaults to 0 (Monday). -1 would be Sunday.
Whether a size in the table sample clause represents percentage.
Specifies the strategy according to which identifiers should be normalized.
Whether identifiers are only normalized with respect to ASCII characters, e.g. Ä and
ä are different identifiers in DuckDB, but the same identifier in Spark.
Determines how function names are going to be normalized.
Possible values:
"upper" or True: Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
Dialect-specific metadata key for preserving original function names, or None to disable. Only generators using the same key reuse these names, allowing round trips of aliases that share an AST node, e.g. JSON_VALUE vs JSON_EXTRACT_SCALAR in BigQuery.
Whether the base comes first in the LOG function.
Possible values: True, False, None (two arguments are not supported by LOG)
Default NULL ordering method to use if not explicitly set.
Possible values: "nulls_are_small", "nulls_are_large", "nulls_are_last"
Whether the behavior of a / b depends on the types of a and b.
False means a / b is always float division.
True means a / b is integer division if both a and b are integers.
A NULL arg in CONCAT yields NULL by default, but in some dialects it yields an empty string.
A NULL arg in CONCAT_WS yields NULL by default, but in some dialects it is skipped.
Associates this dialect's time formats with their equivalent Python strftime formats.
Helper which is used for parsing the special syntax CAST(x AS DATE FORMAT 'yyyy').
If empty, the corresponding trie will be constructed off of TIME_MAPPING.
Mapping of an escaped sequence (\n) to its unescaped version (
).
Whether string literals support escape sequences (e.g. \n). Set by the metaclass based on the tokenizer's STRING_ESCAPES.
Whether byte string literals support escape sequences. Set by the metaclass based on the tokenizer's BYTE_STRING_ESCAPES.
Mapping of an identifier escape char (\) to its escaped version (\\). Set by the metaclass based on the tokenizer's IDENTIFIER_ESCAPES.
Mapping of vector type aliases back to their canonical names. Overridden by dialects like SingleStore.
Columns that are auto-generated by the engine corresponding to this dialect.
For example, such columns may be excluded from SELECT * queries.
Whether qualified $N references the Nth column of their source.
Some dialects, such as Snowflake, allow you to reference a CTE column alias in the HAVING clause of the CTE. This flag will cause the CTE alias columns to override any projection aliases in the subquery.
For example, WITH y(c) AS ( SELECT SUM(a) FROM (SELECT 1 a) AS x HAVING c > 0 ) SELECT c FROM y;
will be rewritten as
WITH y(c) AS (
SELECT SUM(a) AS c FROM (SELECT 1 AS a) AS x HAVING c > 0
) SELECT c FROM y;
Whether alias reference expansion (_expand_alias_refs()) should run before column qualification (_qualify_columns()).
For example:
WITH data AS ( SELECT 1 AS id, 2 AS my_id ) SELECT id AS my_id FROM data WHERE my_id = 1 GROUP BY my_id, HAVING my_id = 1
In most dialects, "my_id" would refer to "data.my_id" across the query, except: - BigQuery, which will forward the alias to GROUP BY + HAVING clauses i.e it resolves to "WHERE my_id = 1 GROUP BY id HAVING id = 1" - Clickhouse, which will forward the alias across the query i.e it resolves to "WHERE id = 1 GROUP BY id HAVING id = 1"
Whether alias reference expansion before qualification should only happen for the GROUP BY clause.
Whether to annotate all scopes during optimization. Used by BigQuery for UNNEST support.
Whether alias reference expansion is disabled for this dialect.
Some dialects like Oracle do NOT support referencing aliases in projections or WHERE clauses. The original expression must be repeated instead.
For example, in Oracle: SELECT y.foo AS bar, bar * 2 AS baz FROM y -- INVALID SELECT y.foo AS bar, y.foo * 2 AS baz FROM y -- VALID
Whether alias references are allowed in JOIN ... ON clauses.
Most dialects do not support this, but Snowflake allows alias expansion in the JOIN ... ON clause (and almost everywhere else)
For example, in Snowflake: SELECT a.id AS user_id FROM a JOIN b ON user_id = b.id -- VALID
Reference: sqlglot.dialects.snowflake.com/en/sql-reference/sql/select#usage-notes">https://docssqlglot.dialects.snowflake.com/en/sql-reference/sql/select#usage-notes
Whether ORDER BY ALL is supported (expands to all the selected columns) as in DuckDB, Spark3/Databricks
Whether projection alias names can shadow table/source names in GROUP BY and HAVING clauses.
In BigQuery, when a projection alias has the same name as a source table, the alias takes precedence in GROUP BY and HAVING clauses, and the table becomes inaccessible by that name.
For example, in BigQuery: SELECT id, ARRAY_AGG(col) AS custom_fields FROM custom_fields GROUP BY id HAVING id >= 1
The "custom_fields" source is shadowed by the projection alias, so we cannot qualify "id" with "custom_fields" in GROUP BY/HAVING.
Whether a whole-row reference to a table alias takes precedence over a same-named column.
Whether table names can be referenced as columns (treated as structs).
BigQuery allows tables to be referenced as columns in queries, automatically treating them as struct values containing all the table's columns.
For example, in BigQuery: SELECT t FROM my_table AS t -- Returns entire row as a struct
Whether the dialect supports expanding struct fields using star notation (e.g., struct_col.*).
BigQuery allows struct fields to be expanded with the star operator:
SELECT t.struct_col.* FROM table t
RisingWave also allows struct field expansion with the star operator using parentheses:
SELECT (t.struct_col).* FROM table t
This expands to all fields within the struct.
Whether a backslash in a SELECT * ILIKE '<pattern>' filter escapes the following character,
so that e.g. \_ matches a literal underscore (Snowflake). When False, backslashes in the
pattern are matched literally (DuckDB).
Whether pseudocolumns should be excluded from star expansion (SELECT *).
Pseudocolumns are special dialect-specific columns (e.g., Oracle's ROWNUM, ROWID, LEVEL, or BigQuery's _PARTITIONTIME, _PARTITIONDATE) that are implicitly available but not part of the table schema. When this is True, SELECT * will not include these pseudocolumns; they must be explicitly selected.
Where star expansion places the columns of a USING or NATURAL join.
Given a(a_id, k1, k2) and b(k2, b_id, k1), SELECT * FROM a JOIN b USING (k2, k1) returns:
USING_LIST:k2, k1, a_id, b_idLEFT_TABLE:k1, k2, a_id, b_idIN_PLACE:a_id, k1, k2, b_id
When join columns come first, this applies at every join: each USING join moves its columns ahead of all the columns to its left.
Whether query results are typed as structs in metadata for type inference.
In BigQuery, subqueries store their column types as a STRUCT in metadata,
enabling special type inference for ARRAY(SELECT ...) expressions:
ARRAY(SELECT x, y FROM t) → ARRAY For single column subqueries, BigQuery unwraps the struct:
ARRAY(SELECT x FROM t) → ARRAY This is metadata-only for type inference.
Whether struct field access requires parentheses around the expression.
RisingWave requires parentheses for struct field access in certain contexts:
SELECT (col.field).subfield FROM table -- Parentheses required
Without parentheses, the parser may not correctly interpret nested struct access.
Reference: sqlglot.dialects.risingwave.com/sql/data-types/struct#retrieve-data-in-a-struct">https://docssqlglot.dialects.risingwave.com/sql/data-types/struct#retrieve-data-in-a-struct
Whether NULL/VOID is supported as a valid data type (not just a value).
Databricks and Spark v3+ support NULL as an actual type, allowing expressions like: SELECT NULL AS col -- Has type NULL, not just value NULL CAST(x AS VOID) -- Valid type cast
Whether COALESCE in comparisons has non-standard NULL semantics.
We can't convert COALESCE(x, 1) = 2 into NOT x IS NULL AND x = 2 for redshift,
because they are not always equivalent. For example, if x is NULL and it comes
from a table, then the result is NULL, despite FALSE AND NULL evaluating to FALSE.
In standard SQL and most dialects, these expressions are equivalent, but Redshift treats table NULLs differently in this context.
Whether the ARRAY constructor is context-sensitive, i.e in Redshift ARRAY[1, 2, 3] != ARRAY(1, 2, 3) as the former is of type INT[] vs the latter which is SUPER
Whether expressions such as x::INT[5] should be parsed as fixed-size array defs/casts e.g. in DuckDB. In dialects which don't support fixed size arrays such as Snowflake, this should be interpreted as a subscript/index operator.
Whether failing to parse a JSON path expression using the JSONPath dialect will log a warning.
Whether a single DOT in a JSON path (e.g. $.) is treated as a valid wildcard key.
Whether "X ON EMPTY" should come before "X ON ERROR" (for dialects like T-SQL, MySQL, Oracle).
Whether Array update functions return NULL when the input array is NULL.
This flag is used in the optimizer's canonicalize rule and determines whether x will be promoted to the literal's type in x::DATE < '2020-01-01 12:05:03' (i.e., DATETIME). When false, the literal is cast to x's type to match it instead.
Whether number literals can include underscores for better readability
Whether hex strings such as x'CC' evaluate to integer or binary/blob type
Whether REGEXP_EXTRACT returns NULL when the position arg exceeds the string length.
Whether a set operation uses DISTINCT by default. This is None when either DISTINCT or ALL
must be explicitly specified.
Whether INTERSECT binds more tightly than UNION and EXCEPT when a set operation chain isn't parenthesized. If False, all set operations have equal precedence and associate left to right.
Helper for dialects that use a different name for the same creatable kind. For example, the Clickhouse equivalent of CREATE SCHEMA is CREATE DATABASE.
Hive by default does not update the schema of existing partitions when a column is changed. the CASCADE clause is used to indicate that the change should be propagated to all existing partitions. the Spark dialect, while derived from Hive, does not support the CASCADE clause.
Whether byte string literals (ex: BigQuery's b'...') are typed as BYTES/BINARY
Whether JSON_EXTRACT_SCALAR returns null if a non-scalar value is selected.
Maps function expressions to their default output column name(s).
For example, in Postgres, generate_series function outputs a column named "generate_series" by default, so we map the ExplodingGenerateSeries expression to "generate_series" string.
The default type of NULL for producing the correct projection type.
For example, in BigQuery the default type of the NULL value is INT64.
Whether LEAST/GREATEST functions ignore NULL values, e.g:
- BigQuery, Snowflake, MySQL, Presto/Trino: LEAST(1, NULL, 2) -> NULL
- Spark, Postgres, DuckDB, TSQL: LEAST(1, NULL, 2) -> 1
Whether to prioritize non-literal types over literals during type annotation.
Whether the table alias comes after version (timestamp or iceberg snapshot).
1047 @classmethod 1048 def get_or_raise(cls, dialect: DialectType) -> Dialect: 1049 """ 1050 Look up a dialect in the global dialect registry and return it if it exists. 1051 1052 Args: 1053 dialect: The target dialect. If this is a string, it can be optionally followed by 1054 additional key-value pairs that are separated by commas and are used to specify 1055 dialect settings, such as whether the dialect's identifiers are case-sensitive. 1056 1057 Example: 1058 >>> from sqlglot.dialects.dialect import Dialect 1059 >>> dialect = Dialect.get_or_raise("duckdb") 1060 >>> dialect = Dialect.get_or_raise("mysql, normalization_strategy = case_sensitive") 1061 1062 Returns: 1063 The corresponding Dialect instance. 1064 """ 1065 1066 if not dialect: 1067 return cls() 1068 if isinstance(dialect, _Dialect): 1069 return dialect() 1070 if isinstance(dialect, Dialect): 1071 return dialect 1072 if isinstance(dialect, str): 1073 try: 1074 dialect_name, *kv_strings = dialect.split(",") 1075 kv_pairs = (kv.split("=") for kv in kv_strings) 1076 kwargs = {} 1077 for pair in kv_pairs: 1078 key = pair[0].strip() 1079 value: bool | str | None = None 1080 1081 if len(pair) == 1: 1082 # Default initialize standalone settings to True 1083 value = True 1084 elif len(pair) == 2: 1085 value = pair[1].strip() 1086 1087 kwargs[key] = to_bool(value) 1088 1089 except ValueError: 1090 raise ValueError( 1091 f"Invalid dialect format: '{dialect}'. " 1092 "Please use the correct format: 'dialect [, k1 = v2 [, ...]]'." 1093 ) 1094 1095 result = cls.get(dialect_name.strip()) 1096 if not result: 1097 # Include both built-in dialects and any loaded dialects for better error messages 1098 all_dialects = set(DIALECT_MODULE_NAMES) | set(cls._classes.keys()) 1099 suggest_closest_match_and_fail("dialect", dialect_name, all_dialects) 1100 1101 assert result is not None 1102 return result(**kwargs) 1103 1104 raise ValueError(f"Invalid dialect type for '{dialect}': '{type(dialect)}'.")
Look up a dialect in the global dialect registry and return it if it exists.
Arguments:
- dialect: The target dialect. If this is a string, it can be optionally followed by additional key-value pairs that are separated by commas and are used to specify dialect settings, such as whether the dialect's identifiers are case-sensitive.
Example:
>>> from sqlglot.dialects.dialect import Dialect >>> dialect = Dialect.get_or_raise("duckdb") >>> dialect = Dialect.get_or_raise("mysql, normalization_strategy = case_sensitive")
Returns:
The corresponding Dialect instance.
1106 @classmethod 1107 def format_time(cls, expression: str | exp.Expr | None) -> exp.Expr | None: 1108 """Converts a time format in this dialect to its equivalent Python `strftime` format.""" 1109 if isinstance(expression, str): 1110 return exp.Literal.string( 1111 # the time formats are quoted 1112 format_time(expression[1:-1], cls.TIME_MAPPING, cls.TIME_TRIE) 1113 ) 1114 1115 if expression and expression.is_string: 1116 return exp.Literal.string(format_time(expression.this, cls.TIME_MAPPING, cls.TIME_TRIE)) 1117 1118 return expression
Converts a time format in this dialect to its equivalent Python strftime format.
1144 def normalize_identifier(self, expression: E) -> E: 1145 """ 1146 Transforms an identifier in a way that resembles how it'd be resolved by this dialect. 1147 1148 For example, an identifier like `FoO` would be resolved as `foo` in Postgres, because it 1149 lowercases all unquoted identifiers. On the other hand, Snowflake uppercases them, so 1150 it would resolve it as `FOO`. If it was quoted, it'd need to be treated as case-sensitive, 1151 and so any normalization would be prohibited in order to avoid "breaking" the identifier. 1152 1153 There are also dialects like Spark, which are case-insensitive even when quotes are 1154 present, and dialects like MySQL, whose resolution rules match those employed by the 1155 underlying operating system, for example they may always be case-sensitive in Linux. 1156 1157 Finally, the normalization behavior of some engines can even be controlled through flags, 1158 like in Redshift's case, where users can explicitly set enable_case_sensitive_identifier. 1159 1160 SQLGlot aims to understand and handle all of these different behaviors gracefully, so 1161 that it can analyze queries in the optimizer and successfully capture their semantics. 1162 """ 1163 if ( 1164 isinstance(expression, exp.Identifier) 1165 and self.normalization_strategy is not NormalizationStrategy.CASE_SENSITIVE 1166 and ( 1167 not expression.quoted 1168 or self.normalization_strategy 1169 in ( 1170 NormalizationStrategy.CASE_INSENSITIVE, 1171 NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE, 1172 ) 1173 ) 1174 ): 1175 if self.normalization_strategy in ( 1176 NormalizationStrategy.UPPERCASE, 1177 NormalizationStrategy.CASE_INSENSITIVE_UPPERCASE, 1178 ): 1179 normalized = ( 1180 expression.this.translate(ASCII_UPPER) 1181 if self.ASCII_ONLY_NORMALIZATION 1182 else expression.this.upper() 1183 ) 1184 else: 1185 normalized = ( 1186 expression.this.translate(ASCII_LOWER) 1187 if self.ASCII_ONLY_NORMALIZATION 1188 else expression.this.lower() 1189 ) 1190 1191 expression.set("this", normalized) 1192 1193 return expression
Transforms an identifier in a way that resembles how it'd be resolved by this dialect.
For example, an identifier like FoO would be resolved as foo in Postgres, because it
lowercases all unquoted identifiers. On the other hand, Snowflake uppercases them, so
it would resolve it as FOO. If it was quoted, it'd need to be treated as case-sensitive,
and so any normalization would be prohibited in order to avoid "breaking" the identifier.
There are also dialects like Spark, which are case-insensitive even when quotes are present, and dialects like MySQL, whose resolution rules match those employed by the underlying operating system, for example they may always be case-sensitive in Linux.
Finally, the normalization behavior of some engines can even be controlled through flags, like in Redshift's case, where users can explicitly set enable_case_sensitive_identifier.
SQLGlot aims to understand and handle all of these different behaviors gracefully, so that it can analyze queries in the optimizer and successfully capture their semantics.
1195 def case_sensitive(self, text: str) -> bool: 1196 """Checks if text contains any case sensitive characters, based on the dialect's rules.""" 1197 if self.normalization_strategy is NormalizationStrategy.CASE_INSENSITIVE: 1198 return False 1199 1200 unsafe = ( 1201 str.islower 1202 if self.normalization_strategy is NormalizationStrategy.UPPERCASE 1203 else str.isupper 1204 ) 1205 return any(unsafe(char) for char in text)
Checks if text contains any case sensitive characters, based on the dialect's rules.
1207 def can_quote(self, identifier: exp.Identifier, identify: str | bool = "safe") -> bool: 1208 """Checks if an identifier can be quoted 1209 1210 Args: 1211 identifier: The identifier to check. 1212 identify: 1213 `True`: Always returns `True` except for certain cases. 1214 `"safe"`: Only returns `True` if the identifier is case-insensitive. 1215 `"unsafe"`: Only returns `True` if the identifier is case-sensitive. 1216 1217 Returns: 1218 Whether the given text can be identified. 1219 """ 1220 if identifier.quoted: 1221 return True 1222 if not identify: 1223 return False 1224 if isinstance(identifier.parent, exp.Func): 1225 return False 1226 if identify is True: 1227 return True 1228 1229 is_safe = not self.case_sensitive(identifier.this) and bool( 1230 exp.SAFE_IDENTIFIER_RE.match(identifier.this) 1231 ) 1232 1233 if identify == "safe": 1234 return is_safe 1235 if identify == "unsafe": 1236 return not is_safe 1237 1238 raise ValueError(f"Unexpected argument for identify: '{identify}'")
Checks if an identifier can be quoted
Arguments:
- identifier: The identifier to check.
- identify:
True: Always returnsTrueexcept for certain cases."safe": Only returnsTrueif the identifier is case-insensitive."unsafe": Only returnsTrueif the identifier is case-sensitive.
Returns:
Whether the given text can be identified.
1240 def quote_identifier(self, expression: E, identify: bool = True) -> E: 1241 """ 1242 Adds quotes to a given expression if it is an identifier. 1243 1244 Args: 1245 expression: The expression of interest. If it's not an `Identifier`, this method is a no-op. 1246 identify: If set to `False`, the quotes will only be added if the identifier is deemed 1247 "unsafe", with respect to its characters and this dialect's normalization strategy. 1248 """ 1249 if isinstance(expression, exp.Identifier): 1250 expression.set("quoted", self.can_quote(expression, identify or "unsafe")) 1251 return expression
Adds quotes to a given expression if it is an identifier.
Arguments:
- expression: The expression of interest. If it's not an
Identifier, this method is a no-op. - identify: If set to
False, the quotes will only be added if the identifier is deemed "unsafe", with respect to its characters and this dialect's normalization strategy.
1253 def to_json_path(self, path: exp.Expr | None) -> exp.Expr | None: 1254 if isinstance(path, exp.Literal): 1255 path_text = path.name 1256 if path.is_number: 1257 path_text = f"[{path_text}]" 1258 try: 1259 return parse_json_path(path_text, self) 1260 except (ParseError, TokenError) as e: 1261 if self.STRICT_JSON_PATH_SYNTAX and not path_text.lstrip().startswith( 1262 ("lax", "strict") 1263 ): 1264 logger.warning(f"Invalid JSON path syntax. {str(e)}") 1265 1266 return path
98class Dialects(str, Enum): 99 """Dialects supported by SQLGLot.""" 100 101 DIALECT = "" 102 103 ATHENA = "athena" 104 BIGQUERY = "bigquery" 105 CLICKHOUSE = "clickhouse" 106 DATABRICKS = "databricks" 107 DAX = "dax" 108 DORIS = "doris" 109 DREMIO = "dremio" 110 DRILL = "drill" 111 DRUID = "druid" 112 DUCKDB = "duckdb" 113 DUNE = "dune" 114 FABRIC = "fabric" 115 HIVE = "hive" 116 MATERIALIZE = "materialize" 117 MYSQL = "mysql" 118 ORACLE = "oracle" 119 POSTGRES = "postgres" 120 PRESTO = "presto" 121 PRQL = "prql" 122 REDSHIFT = "redshift" 123 RISINGWAVE = "risingwave" 124 SNOWFLAKE = "snowflake" 125 SOLR = "solr" 126 SPARK = "spark" 127 SPARK2 = "spark2" 128 SQLITE = "sqlite" 129 STARROCKS = "starrocks" 130 TABLEAU = "tableau" 131 TERADATA = "teradata" 132 TRINO = "trino" 133 TSQL = "tsql" 134 EXASOL = "exasol"
Dialects supported by SQLGLot.