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