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