sqlglot.generators.presto
1from __future__ import annotations 2 3import typing as t 4 5from sqlglot import exp, generator, transforms 6from sqlglot.dialects.dialect import ( 7 array_sort_order, 8 array_slice_to_slice_sql, 9 bool_xor_sql, 10 bracket_to_element_at_sql, 11 datestrtodate_sql, 12 encode_decode_sql, 13 if_sql, 14 left_to_substring_sql, 15 no_ilike_sql, 16 no_pivot_sql, 17 no_timestamp_sql, 18 regexp_extract_sql, 19 rename_func, 20 right_to_substring_sql, 21 strposition_sql, 22 struct_extract_sql, 23 timestamptrunc_sql, 24 timestrtotime_sql, 25 ts_or_ds_add_cast, 26 unit_to_str, 27 week_unit_to_dow, 28 sequence_sql, 29 explode_to_unnest_sql, 30) 31from sqlglot.dialects.hive import Hive 32from sqlglot.generator import unsupported_args 33from sqlglot.helper import is_float 34from sqlglot.optimizer.scope import find_all_in_scope 35from sqlglot.transforms import unqualify_columns 36 37DATE_ADD_OR_SUB = t.Union[exp.DateAdd, exp.TimestampAdd, exp.DateSub] 38 39 40def _sha2_digest_sql(self: PrestoGenerator, expression: exp.SHA2Digest) -> str: 41 length = expression.text("length") or "256" 42 if length not in ("256", "512"): 43 self.unsupported(f"SHA{length} is not supported in Presto") 44 45 this = expression.this 46 if this.is_type(*exp.DataType.TEXT_TYPES): 47 # the native digest takes VARBINARY, so a text-typed argument needs encoding 48 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 49 50 return self.func(f"SHA{length}", this) 51 52 53def _initcap_sql(self: PrestoGenerator, expression: exp.Initcap) -> str: 54 delimiters = expression.expression 55 if delimiters and not ( 56 delimiters.is_string and delimiters.this == self.dialect.INITCAP_DEFAULT_DELIMITER_CHARS 57 ): 58 self.unsupported("INITCAP does not support custom delimiters") 59 60 regex = r"(\w)(\w*)" 61 return f"REGEXP_REPLACE({self.sql(expression, 'this')}, '{regex}', x -> UPPER(x[1]) || LOWER(x[2]))" 62 63 64def _array_sort_sql(self: PrestoGenerator, expression: exp.ArraySort) -> str: 65 if expression.expression: 66 return self.func("ARRAY_SORT", expression.this, expression.expression) 67 68 # ARRAY_SORT puts NULLs last, so reversing it sorts descending with NULLs first 69 asc, nulls_first = array_sort_order(expression) or (True, True) 70 if nulls_first == asc: 71 self.unsupported( 72 "ARRAY_SORT can't sort ascending with NULLs first or descending with NULLs last" 73 ) 74 sort = self.func("ARRAY_SORT", expression.this) 75 return sort if asc else self.func("REVERSE", sort) 76 77 78def _schema_sql(self: PrestoGenerator, expression: exp.Schema) -> str: 79 if isinstance(expression.parent, exp.PartitionedByProperty): 80 # Any columns in the ARRAY[] string literals should not be quoted 81 expression.transform(lambda n: n.name if isinstance(n, exp.Identifier) else n, copy=False) 82 83 partition_exprs = [ 84 self.sql(c) if isinstance(c, (exp.Func, exp.Property)) else self.sql(c, "this") 85 for c in expression.expressions 86 ] 87 return self.sql(exp.Array(expressions=[exp.Literal.string(c) for c in partition_exprs])) 88 89 if expression.parent: 90 for schema in expression.parent.find_all(exp.Schema): 91 if schema is expression: 92 continue 93 94 column_defs = schema.find_all(exp.ColumnDef) 95 if column_defs and isinstance(schema.parent, exp.Property): 96 expression.expressions.extend(column_defs) 97 98 return self.schema_sql(expression) 99 100 101def _quantile_sql(self: PrestoGenerator, expression: exp.Quantile) -> str: 102 self.unsupported("Presto does not support exact quantiles") 103 return self.func("APPROX_PERCENTILE", expression.this, expression.args.get("quantile")) 104 105 106def _str_to_time_sql( 107 self: PrestoGenerator, expression: exp.StrToDate | exp.StrToTime | exp.TsOrDsToDate 108) -> str: 109 return self.func("DATE_PARSE", expression.this, self.format_time(expression)) 110 111 112def _ts_or_ds_to_date_sql(self: PrestoGenerator, expression: exp.TsOrDsToDate) -> str: 113 time_format = self.format_time(expression) 114 dialect_class = type(self.dialect) 115 if time_format and time_format not in (dialect_class.TIME_FORMAT, dialect_class.DATE_FORMAT): 116 return self.sql(exp.cast(_str_to_time_sql(self, expression), exp.DType.DATE)) 117 return self.sql(exp.cast(exp.cast(expression.this, exp.DType.TIMESTAMP), exp.DType.DATE)) 118 119 120def _ts_or_ds_add_sql(self: PrestoGenerator, expression: exp.TsOrDsAdd) -> str: 121 expression = ts_or_ds_add_cast(expression) 122 unit = unit_to_str(expression) 123 return self.func("DATE_ADD", unit, expression.expression, expression.this) 124 125 126def _ts_or_ds_diff_sql(self: PrestoGenerator, expression: exp.TsOrDsDiff) -> str: 127 this = exp.cast(expression.this, exp.DType.TIMESTAMP) 128 expr = exp.cast(expression.expression, exp.DType.TIMESTAMP) 129 unit = unit_to_str(expression) 130 return self.func("DATE_DIFF", unit, expr, this) 131 132 133def _first_last_sql(self: PrestoGenerator, expression: exp.Func) -> str: 134 """ 135 Trino doesn't support FIRST / LAST as functions, but they're valid in the context 136 of MATCH_RECOGNIZE, so we need to preserve them in that case. In all other cases 137 they're converted into an ARBITRARY call. 138 139 Reference: https://trino.io/docs/current/sql/match-recognize.html#logical-navigation-functions 140 """ 141 if isinstance(expression.find_ancestor(exp.MatchRecognize, exp.Select), exp.MatchRecognize): 142 return self.function_fallback_sql(expression) 143 144 return rename_func("ARBITRARY")(self, expression) 145 146 147def _unix_to_time_sql(self: PrestoGenerator, expression: exp.UnixToTime) -> str: 148 scale = expression.args.get("scale") 149 timestamp = self.sql(expression, "this") 150 if scale in (None, exp.UnixToTime.SECONDS): 151 return rename_func("FROM_UNIXTIME")(self, expression) 152 153 return f"FROM_UNIXTIME(CAST({timestamp} AS DOUBLE) / POW(10, {scale}))" 154 155 156def _to_int(self: PrestoGenerator, expression: exp.Expr) -> exp.Expr: 157 if not expression.type: 158 from sqlglot.optimizer.annotate_types import annotate_types 159 160 annotate_types(expression, dialect=self.dialect) 161 if expression.type and expression.type.this not in exp.DataType.INTEGER_TYPES: 162 return exp.cast(expression, to=exp.DType.BIGINT) 163 return expression 164 165 166def _date_delta_sql( 167 name: str, negate_interval: bool = False 168) -> t.Callable[[PrestoGenerator, DATE_ADD_OR_SUB], str]: 169 def _delta_sql(self: PrestoGenerator, expression: DATE_ADD_OR_SUB) -> str: 170 interval = _to_int(self, expression.expression) 171 return self.func( 172 name, 173 unit_to_str(expression), 174 interval * (-1) if negate_interval else interval, 175 expression.this, 176 ) 177 178 return _delta_sql 179 180 181def _date_diff_sql( 182 self: PrestoGenerator, expression: exp.DateDiff | exp.DatetimeDiff | exp.TimestampDiff 183) -> str: 184 # Presto/Trino only expose date_diff(unit, ts1, ts2); it returns ts2 - ts1, so the 185 # operands are emitted as (expression, this) to preserve `this - expression` semantics. 186 this: exp.Expr = expression.this 187 expr: exp.Expr = expression.expression 188 unit = unit_to_str(expression) 189 190 # DATE_DIFF counts complete units between its operands, whereas dialects that set 191 # date_part_boundary count unit boundary crossings, so the operands are truncated 192 # down to the unit to make the two coincide 193 if unit and expression.args.get("date_part_boundary"): 194 raw_unit = expression.args.get("unit") 195 dow = week_unit_to_dow(raw_unit) 196 197 if dow is not None: 198 unit = exp.Literal.string("WEEK") 199 200 # DATE_TRUNC('WEEK', ...) is Monday-based; shifting both operands by the same 201 # delta realigns it to the requested week start without changing the diff 202 shift_days = 1 if dow == 7 else 1 - dow 203 if shift_days: 204 delta = exp.Interval(this=exp.Literal.string(str(shift_days)), unit=exp.var("DAY")) 205 this = exp.Add(this=this, expression=delta) 206 expr = exp.Add(this=expr, expression=delta.copy()) 207 208 if not isinstance(raw_unit, exp.WeekStart) or dow is not None: 209 this = exp.DateTrunc(unit=unit.copy(), this=this) 210 expr = exp.DateTrunc(unit=unit.copy(), this=expr) 211 212 return self.func("DATE_DIFF", unit, expr, this) 213 214 215def _explode_to_unnest_sql(self: PrestoGenerator, expression: exp.Lateral) -> str: 216 explode = expression.this 217 if isinstance(explode, exp.Explode): 218 exploded_type = explode.this.type 219 alias = expression.args.get("alias") 220 221 # This attempts a best-effort transpilation of LATERAL VIEW EXPLODE on a struct array 222 if ( 223 isinstance(alias, exp.TableAlias) 224 and isinstance(exploded_type, exp.DataType) 225 and exploded_type.is_type(exp.DType.ARRAY) 226 and exploded_type.expressions 227 and exploded_type.expressions[0].is_type(exp.DType.STRUCT) 228 ): 229 # When unnesting a ROW in Presto, it produces N columns, so we need to fix the alias 230 alias.set("columns", [c.this.copy() for c in exploded_type.expressions[0].expressions]) 231 elif isinstance(explode, exp.Inline): 232 explode.replace(exp.Explode(this=explode.this.copy())) 233 234 return explode_to_unnest_sql(self, expression) 235 236 237def amend_exploded_column_table(expression: exp.Expr) -> exp.Expr: 238 # We check for expression.type because the columns can be amended only if types were inferred 239 if isinstance(expression, exp.Select) and expression.type: 240 for lateral in expression.args.get("laterals") or []: 241 alias = lateral.args.get("alias") 242 if ( 243 not isinstance(lateral.this, exp.Explode) 244 or not isinstance(alias, exp.TableAlias) 245 or len(alias.columns) != 1 246 ): 247 continue 248 249 new_table = alias.this 250 old_table = alias.columns[0].name.lower() 251 252 # When transpiling a LATERAL VIEW EXPLODE Spark query, the exploded fields may be qualified 253 # with the struct column, resulting in invalid Presto references that need to be amended 254 for column in find_all_in_scope(expression, exp.Column): 255 if column.db.lower() == old_table: 256 column.set("table", column.args["db"].pop()) 257 elif column.table.lower() == old_table: 258 column.set("table", new_table.copy()) 259 elif column.name.lower() == old_table and isinstance(column.parent, exp.Dot): 260 column.parent.replace(exp.column(column.parent.expression, table=new_table)) 261 262 return expression 263 264 265class PrestoGenerator(generator.Generator): 266 SELECT_KINDS: tuple[str, ...] = () 267 SUPPORTS_DECODE_CASE = False 268 SUPPORTS_TEMPORAL_PRECISION = False 269 270 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 271 272 INTERVAL_ALLOWS_PLURAL_FORM = False 273 JOIN_HINTS = False 274 CAST_TO_INT_ROUNDS = True 275 TABLE_HINTS = False 276 QUERY_HINTS = False 277 IS_BOOL_ALLOWED = False 278 TZ_TO_WITH_TIME_ZONE = True 279 NVL2_SUPPORTED = False 280 STRUCT_DELIMITER = ("(", ")") 281 LIMIT_ONLY_LITERALS = True 282 SUPPORTS_SINGLE_ARG_CONCAT = False 283 LIKE_PROPERTY_INSIDE_SCHEMA = True 284 MULTI_ARG_DISTINCT = False 285 SUPPORTS_TO_NUMBER = False 286 HEX_FUNC = "TO_HEX" 287 PARSE_JSON_NAME: str | None = "JSON_PARSE" 288 PAD_FILL_PATTERN_IS_REQUIRED = True 289 EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False 290 SUPPORTS_MEDIAN = False 291 ARRAY_SIZE_NAME = "CARDINALITY" 292 293 PROPERTIES_LOCATION = { 294 **generator.Generator.PROPERTIES_LOCATION, 295 exp.LocationProperty: exp.Properties.Location.UNSUPPORTED, 296 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 297 } 298 299 TYPE_MAPPING = { 300 **generator.Generator.TYPE_MAPPING, 301 exp.DType.BINARY: "VARBINARY", 302 exp.DType.BIT: "BOOLEAN", 303 exp.DType.DATETIME: "TIMESTAMP", 304 exp.DType.DATETIME64: "TIMESTAMP", 305 exp.DType.FLOAT: "REAL", 306 exp.DType.HLLSKETCH: "HYPERLOGLOG", 307 exp.DType.INT: "INTEGER", 308 exp.DType.STRUCT: "ROW", 309 exp.DType.TEXT: "VARCHAR", 310 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 311 exp.DType.TIMESTAMPNTZ: "TIMESTAMP", 312 exp.DType.TIMETZ: "TIME", 313 } 314 315 TRANSFORMS = { 316 **generator.Generator.TRANSFORMS, 317 exp.AnyValue: rename_func("ARBITRARY"), 318 exp.ApproxQuantile: lambda self, e: self.func( 319 "APPROX_PERCENTILE", 320 e.this, 321 e.args.get("weight"), 322 e.args.get("quantile"), 323 e.args.get("accuracy"), 324 ), 325 exp.ArgMax: rename_func("MAX_BY"), 326 exp.ArgMin: rename_func("MIN_BY"), 327 exp.Array: transforms.preprocess( 328 [transforms.inherit_struct_field_names], 329 generator=lambda self, e: f"ARRAY[{self.expressions(e, flat=True)}]", 330 ), 331 exp.ArrayAny: rename_func("ANY_MATCH"), 332 exp.ArrayConcat: rename_func("CONCAT"), 333 exp.ArrayContains: rename_func("CONTAINS"), 334 exp.ArraySort: _array_sort_sql, 335 exp.ArrayToString: rename_func("ARRAY_JOIN"), 336 exp.ArrayUniqueAgg: rename_func("SET_AGG"), 337 exp.ArraySlice: array_slice_to_slice_sql, 338 exp.AtTimeZone: rename_func("AT_TIMEZONE"), 339 exp.BitwiseAnd: lambda self, e: self.func("BITWISE_AND", e.this, e.expression), 340 exp.BitwiseLeftShift: rename_func("BITWISE_LEFT_SHIFT"), 341 exp.BitwiseNot: lambda self, e: self.func("BITWISE_NOT", e.this), 342 exp.BitwiseOr: lambda self, e: self.func("BITWISE_OR", e.this, e.expression), 343 exp.BitwiseRightShift: rename_func("BITWISE_RIGHT_SHIFT"), 344 exp.BitwiseXor: lambda self, e: self.func("BITWISE_XOR", e.this, e.expression), 345 exp.Cast: transforms.preprocess([transforms.epoch_cast_to_ts]), 346 exp.CurrentTime: lambda *_: "CURRENT_TIME", 347 exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP", 348 exp.CurrentUser: lambda *_: "CURRENT_USER", 349 exp.DateAdd: _date_delta_sql("DATE_ADD"), 350 exp.DateDiff: _date_diff_sql, 351 exp.DatetimeDiff: _date_diff_sql, 352 exp.TimestampDiff: _date_diff_sql, 353 exp.DateStrToDate: datestrtodate_sql, 354 exp.DateToDi: lambda self, e: ( 355 f"CAST(DATE_FORMAT({self.sql(e, 'this')}, {type(self.dialect).DATEINT_FORMAT}) AS INT)" 356 ), 357 exp.DateSub: _date_delta_sql("DATE_ADD", negate_interval=True), 358 exp.DayOfWeek: lambda self, e: f"(({self.func('DAY_OF_WEEK', e.this)} % 7) + 1)", 359 exp.DayOfWeekIso: rename_func("DAY_OF_WEEK"), 360 exp.Decode: lambda self, e: encode_decode_sql(self, e, "FROM_UTF8"), 361 exp.DiToDate: lambda self, e: ( 362 f"CAST(DATE_PARSE(CAST({self.sql(e, 'this')} AS VARCHAR), {type(self.dialect).DATEINT_FORMAT}) AS DATE)" 363 ), 364 exp.Encode: lambda self, e: encode_decode_sql(self, e, "TO_UTF8"), 365 exp.FileFormatProperty: lambda self, e: f"format={self.sql(exp.Literal.string(e.name))}", 366 exp.First: _first_last_sql, 367 exp.FromISO8601Date: rename_func("FROM_ISO8601_DATE"), 368 exp.FromISO8601Timestamp: rename_func("FROM_ISO8601_TIMESTAMP"), 369 exp.FromTimeZone: lambda self, e: ( 370 f"WITH_TIMEZONE({self.sql(e, 'this')}, {self.sql(e, 'zone')}) AT TIME ZONE 'UTC'" 371 ), 372 exp.GenerateSeries: sequence_sql, 373 exp.GenerateDateArray: sequence_sql, 374 exp.If: if_sql(), 375 exp.ILike: no_ilike_sql, 376 exp.Initcap: _initcap_sql, 377 exp.Last: _first_last_sql, 378 exp.LastDay: lambda self, e: self.func("LAST_DAY_OF_MONTH", e.this), 379 exp.Lateral: _explode_to_unnest_sql, 380 exp.Left: left_to_substring_sql, 381 exp.Levenshtein: unsupported_args("ins_cost", "del_cost", "sub_cost", "max_dist")( 382 rename_func("LEVENSHTEIN_DISTANCE") 383 ), 384 exp.LogicalAnd: rename_func("BOOL_AND"), 385 exp.LogicalOr: rename_func("BOOL_OR"), 386 exp.Pivot: no_pivot_sql, 387 exp.Quantile: _quantile_sql, 388 exp.RegexpExtract: regexp_extract_sql, 389 exp.RegexpExtractAll: regexp_extract_sql, 390 exp.Right: right_to_substring_sql, 391 exp.Schema: _schema_sql, 392 exp.SchemaCommentProperty: lambda self, e: self.naked_property(e), 393 exp.Select: transforms.preprocess( 394 [ 395 transforms.eliminate_window_clause, 396 transforms.eliminate_qualify, 397 transforms.eliminate_distinct_on, 398 transforms.explode_projection_to_unnest(1, unnest_map=True), 399 transforms.eliminate_semi_and_anti_joins, 400 amend_exploded_column_table, 401 ] 402 ), 403 exp.SqlSecurityProperty: lambda self, e: f"SECURITY {self.sql(e.this)}", 404 exp.StrPosition: lambda self, e: strposition_sql(self, e, supports_occurrence=True), 405 exp.StrToDate: lambda self, e: f"CAST({_str_to_time_sql(self, e)} AS DATE)", 406 exp.StrToMap: rename_func("SPLIT_TO_MAP"), 407 exp.StrToTime: _str_to_time_sql, 408 exp.StructExtract: struct_extract_sql, 409 exp.Table: transforms.preprocess([transforms.unnest_generate_series]), 410 exp.Timestamp: no_timestamp_sql, 411 exp.TimestampAdd: _date_delta_sql("DATE_ADD"), 412 exp.TimestampTrunc: timestamptrunc_sql(), 413 exp.TimeStrToDate: timestrtotime_sql, 414 exp.TimeStrToTime: timestrtotime_sql, 415 exp.TimeStrToUnix: lambda self, e: self.func( 416 "TO_UNIXTIME", self.func("DATE_PARSE", e.this, type(self.dialect).TIME_FORMAT) 417 ), 418 exp.TimeToStr: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 419 exp.TimeToUnix: rename_func("TO_UNIXTIME"), 420 exp.ToChar: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 421 exp.TryCast: transforms.preprocess([transforms.epoch_cast_to_ts]), 422 exp.TsOrDiToDi: lambda self, e: ( 423 f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS VARCHAR), '-', ''), 1, 8) AS INT)" 424 ), 425 exp.TsOrDsAdd: _ts_or_ds_add_sql, 426 exp.TsOrDsDiff: _ts_or_ds_diff_sql, 427 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 428 exp.Unhex: rename_func("FROM_HEX"), 429 exp.UnixToStr: lambda self, e: ( 430 f"DATE_FORMAT(FROM_UNIXTIME({self.sql(e, 'this')}), {self.format_time(e)})" 431 ), 432 exp.UnixToTime: _unix_to_time_sql, 433 exp.UnixToTimeStr: lambda self, e: f"CAST(FROM_UNIXTIME({self.sql(e, 'this')}) AS VARCHAR)", 434 exp.VariancePop: rename_func("VAR_POP"), 435 exp.With: transforms.preprocess([transforms.add_recursive_cte_column_names]), 436 exp.WithinGroup: transforms.preprocess([transforms.remove_within_group_for_percentiles]), 437 # Note: Presto's TRUNCATE always returns DOUBLE, even with decimals=0, whereas 438 # most dialects return INT (SQLite also returns REAL, see sqlite.py). This creates 439 # a bidirectional transpilation gap: Presto→Other may change float division to int 440 # division, and vice versa. Modeling precisely would require exp.FloatTrunc or 441 # similar, deemed overengineering for this subtle semantic difference. 442 exp.Trunc: rename_func("TRUNCATE"), 443 exp.Xor: bool_xor_sql, 444 exp.MD5Digest: rename_func("MD5"), 445 exp.SHA: rename_func("SHA1"), 446 exp.SHA1Digest: rename_func("SHA1"), 447 exp.SHA2Digest: _sha2_digest_sql, 448 exp.Substring: rename_func("SUBSTR"), 449 } 450 451 RESERVED_KEYWORDS = { 452 "alter", 453 "and", 454 "as", 455 "between", 456 "by", 457 "case", 458 "cast", 459 "constraint", 460 "create", 461 "cross", 462 "current_time", 463 "current_timestamp", 464 "deallocate", 465 "delete", 466 "describe", 467 "distinct", 468 "drop", 469 "else", 470 "end", 471 "escape", 472 "except", 473 "execute", 474 "exists", 475 "extract", 476 "false", 477 "for", 478 "from", 479 "full", 480 "group", 481 "having", 482 "in", 483 "inner", 484 "insert", 485 "intersect", 486 "into", 487 "is", 488 "join", 489 "left", 490 "like", 491 "natural", 492 "not", 493 "null", 494 "on", 495 "or", 496 "order", 497 "outer", 498 "prepare", 499 "right", 500 "select", 501 "table", 502 "then", 503 "true", 504 "union", 505 "using", 506 "values", 507 "when", 508 "where", 509 "with", 510 } 511 512 def datatype_sql(self, expression: exp.DataType) -> str: 513 if not self.SUPPORTS_TEMPORAL_PRECISION and expression.this in exp.DataType.TEMPORAL_TYPES: 514 if expression.expressions and expression.expressions[0].name != "3": 515 self.unsupported("Presto only supports millisecond precision for temporal types") 516 expression.set("expressions", None) 517 return super().datatype_sql(expression) 518 519 def extract_sql(self, expression: exp.Extract) -> str: 520 date_part = expression.name 521 522 if not date_part.startswith("EPOCH"): 523 return super().extract_sql(expression) 524 525 if date_part == "EPOCH_MILLISECOND": 526 scale = 10**3 527 elif date_part == "EPOCH_MICROSECOND": 528 scale = 10**6 529 elif date_part == "EPOCH_NANOSECOND": 530 scale = 10**9 531 else: 532 scale = None 533 534 value = expression.expression 535 536 ts = exp.cast(value, to=exp.DType.TIMESTAMP.into_expr()) 537 to_unix: exp.Expr = exp.TimeToUnix(this=ts) 538 539 if scale: 540 to_unix = exp.Mul(this=to_unix, expression=exp.Literal.number(scale)) 541 542 return self.sql(to_unix) 543 544 def jsonformat_sql(self, expression: exp.JSONFormat) -> str: 545 this = expression.this 546 is_json = expression.args.get("is_json") 547 548 if this and not (is_json or this.type): 549 from sqlglot.optimizer.annotate_types import annotate_types 550 551 this = annotate_types(this, dialect=self.dialect) 552 553 if not (is_json or this.is_type(exp.DType.JSON)): 554 this.replace(exp.cast(this, exp.DType.JSON)) 555 556 return self.function_fallback_sql(expression) 557 558 def md5_sql(self, expression: exp.MD5) -> str: 559 this = expression.this 560 561 if not this.type: 562 from sqlglot.optimizer.annotate_types import annotate_types 563 564 this = annotate_types(this, dialect=self.dialect) 565 566 if this.is_type(*exp.DataType.TEXT_TYPES): 567 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 568 569 return self.func("LOWER", self.func("TO_HEX", self.func("MD5", self.sql(this)))) 570 571 def sha2_sql(self, expression: exp.SHA2) -> str: 572 length = expression.text("length") or "256" 573 if length not in ("256", "512"): 574 self.unsupported(f"SHA{length} is not supported in Presto") 575 576 this = expression.this 577 578 if this.is_type(*exp.DataType.TEXT_TYPES): 579 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 580 581 return self.func("LOWER", self.func("TO_HEX", self.func(f"SHA{length}", self.sql(this)))) 582 583 def strtounix_sql(self, expression: exp.StrToUnix) -> str: 584 # Since `TO_UNIXTIME` requires a `TIMESTAMP`, we need to parse the argument into one. 585 # To do this, we first try to `DATE_PARSE` it, but since this can fail when there's a 586 # timezone involved, we wrap it in a `TRY` call and use `PARSE_DATETIME` as a fallback, 587 # which seems to be using the same time mapping as Hive, as per: 588 # https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html 589 this = expression.this 590 value_as_text = exp.cast(this, exp.DType.TEXT) 591 value_as_timestamp = exp.cast(this, exp.DType.TIMESTAMP) if this.is_string else this 592 593 parse_without_tz = self.func("DATE_PARSE", value_as_text, self.format_time(expression)) 594 595 formatted_value = self.func("DATE_FORMAT", value_as_timestamp, self.format_time(expression)) 596 parse_with_tz = self.func( 597 "PARSE_DATETIME", 598 formatted_value, 599 self.format_time(expression, Hive.INVERSE_TIME_MAPPING, Hive.INVERSE_TIME_TRIE), 600 ) 601 coalesced = self.func("COALESCE", self.func("TRY", parse_without_tz), parse_with_tz) 602 return self.func("TO_UNIXTIME", coalesced) 603 604 def bracket_sql(self, expression: exp.Bracket) -> str: 605 if expression.args.get("safe"): 606 return bracket_to_element_at_sql(self, expression) 607 return super().bracket_sql(expression) 608 609 def struct_sql(self, expression: exp.Struct) -> str: 610 if not expression.type: 611 from sqlglot.optimizer.annotate_types import annotate_types 612 613 annotate_types(expression, dialect=self.dialect) 614 615 values: list[str] = [] 616 schema: list[str] = [] 617 unknown_type = False 618 619 for e in expression.expressions: 620 if isinstance(e, exp.PropertyEQ): 621 if e.type and e.type.is_type(exp.DType.UNKNOWN): 622 unknown_type = True 623 else: 624 schema.append(f"{self.sql(e, 'this')} {self.sql(e.type)}") 625 values.append(self.sql(e, "expression")) 626 else: 627 values.append(self.sql(e)) 628 629 size = len(expression.expressions) 630 631 if not size or len(schema) != size: 632 if unknown_type: 633 self.unsupported( 634 "Cannot convert untyped key-value definitions (try annotate_types)." 635 ) 636 return self.func("ROW", *values) 637 return f"CAST(ROW({', '.join(values)}) AS ROW({', '.join(schema)}))" 638 639 def interval_sql(self, expression: exp.Interval) -> str: 640 this = expression.this 641 if this and expression.text("unit").upper().startswith("WEEK"): 642 if not this.is_string: 643 return f"({self.sql(this)} * INTERVAL '7' DAY)" 644 if is_float(this.name): 645 return f"({this.name} * INTERVAL '7' DAY)" 646 return super().interval_sql(expression) 647 648 def transaction_sql(self, expression: exp.Transaction) -> str: 649 modes = expression.args.get("modes") 650 modes = f" {', '.join(modes)}" if modes else "" 651 return f"START TRANSACTION{modes}" 652 653 def offset_limit_modifiers( 654 self, expression: exp.Expr, fetch: bool, limit: exp.Fetch | exp.Limit | None 655 ) -> list[str]: 656 return [ 657 self.sql(expression, "offset"), 658 self.sql(limit), 659 ] 660 661 def create_sql(self, expression: exp.Create) -> str: 662 """ 663 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 664 so we need to remove them 665 """ 666 kind = expression.args["kind"] 667 schema = expression.this 668 if kind == "VIEW" and schema.expressions: 669 expression.this.set("expressions", None) 670 return super().create_sql(expression) 671 672 def delete_sql(self, expression: exp.Delete) -> str: 673 """ 674 Presto only supports DELETE FROM for a single table without an alias, so we need 675 to remove the unnecessary parts. If the original DELETE statement contains more 676 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 677 """ 678 tables = expression.args.get("tables") or [expression.this] 679 if len(tables) > 1: 680 return super().delete_sql(expression) 681 682 table = tables[0] 683 expression.set("this", table) 684 expression.set("tables", None) 685 686 if isinstance(table, exp.Table): 687 table_alias = table.args.get("alias") 688 if table_alias: 689 table_alias.pop() 690 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 691 692 return super().delete_sql(expression) 693 694 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 695 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 696 697 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 698 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 699 if not expression.args.get("variant_extract") or is_json_extract: 700 return self.func( 701 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 702 ) 703 704 this = self.sql(expression, "this") 705 706 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 707 segments = [] 708 for path_key in expression.expression.expressions[1:]: 709 if not isinstance(path_key, exp.JSONPathKey): 710 # Cannot transpile subscripts, wildcards etc to dot notation 711 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 712 continue 713 key = path_key.this 714 if not exp.SAFE_IDENTIFIER_RE.match(key): 715 key = f'"{key}"' 716 segments.append(f".{key}") 717 718 expr = "".join(segments) 719 720 return f"{this}{expr}" 721 722 def groupconcat_sql(self, expression: exp.GroupConcat) -> str: 723 return self.func( 724 "ARRAY_JOIN", 725 self.func("ARRAY_AGG", expression.this), 726 expression.args.get("separator"), 727 )
DATE_ADD_OR_SUB =
typing.Union[sqlglot.expressions.temporal.DateAdd, sqlglot.expressions.temporal.TimestampAdd, sqlglot.expressions.temporal.DateSub]
def
amend_exploded_column_table( expression: sqlglot.expressions.core.Expr) -> sqlglot.expressions.core.Expr:
238def amend_exploded_column_table(expression: exp.Expr) -> exp.Expr: 239 # We check for expression.type because the columns can be amended only if types were inferred 240 if isinstance(expression, exp.Select) and expression.type: 241 for lateral in expression.args.get("laterals") or []: 242 alias = lateral.args.get("alias") 243 if ( 244 not isinstance(lateral.this, exp.Explode) 245 or not isinstance(alias, exp.TableAlias) 246 or len(alias.columns) != 1 247 ): 248 continue 249 250 new_table = alias.this 251 old_table = alias.columns[0].name.lower() 252 253 # When transpiling a LATERAL VIEW EXPLODE Spark query, the exploded fields may be qualified 254 # with the struct column, resulting in invalid Presto references that need to be amended 255 for column in find_all_in_scope(expression, exp.Column): 256 if column.db.lower() == old_table: 257 column.set("table", column.args["db"].pop()) 258 elif column.table.lower() == old_table: 259 column.set("table", new_table.copy()) 260 elif column.name.lower() == old_table and isinstance(column.parent, exp.Dot): 261 column.parent.replace(exp.column(column.parent.expression, table=new_table)) 262 263 return expression
266class PrestoGenerator(generator.Generator): 267 SELECT_KINDS: tuple[str, ...] = () 268 SUPPORTS_DECODE_CASE = False 269 SUPPORTS_TEMPORAL_PRECISION = False 270 271 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 272 273 INTERVAL_ALLOWS_PLURAL_FORM = False 274 JOIN_HINTS = False 275 CAST_TO_INT_ROUNDS = True 276 TABLE_HINTS = False 277 QUERY_HINTS = False 278 IS_BOOL_ALLOWED = False 279 TZ_TO_WITH_TIME_ZONE = True 280 NVL2_SUPPORTED = False 281 STRUCT_DELIMITER = ("(", ")") 282 LIMIT_ONLY_LITERALS = True 283 SUPPORTS_SINGLE_ARG_CONCAT = False 284 LIKE_PROPERTY_INSIDE_SCHEMA = True 285 MULTI_ARG_DISTINCT = False 286 SUPPORTS_TO_NUMBER = False 287 HEX_FUNC = "TO_HEX" 288 PARSE_JSON_NAME: str | None = "JSON_PARSE" 289 PAD_FILL_PATTERN_IS_REQUIRED = True 290 EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False 291 SUPPORTS_MEDIAN = False 292 ARRAY_SIZE_NAME = "CARDINALITY" 293 294 PROPERTIES_LOCATION = { 295 **generator.Generator.PROPERTIES_LOCATION, 296 exp.LocationProperty: exp.Properties.Location.UNSUPPORTED, 297 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 298 } 299 300 TYPE_MAPPING = { 301 **generator.Generator.TYPE_MAPPING, 302 exp.DType.BINARY: "VARBINARY", 303 exp.DType.BIT: "BOOLEAN", 304 exp.DType.DATETIME: "TIMESTAMP", 305 exp.DType.DATETIME64: "TIMESTAMP", 306 exp.DType.FLOAT: "REAL", 307 exp.DType.HLLSKETCH: "HYPERLOGLOG", 308 exp.DType.INT: "INTEGER", 309 exp.DType.STRUCT: "ROW", 310 exp.DType.TEXT: "VARCHAR", 311 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 312 exp.DType.TIMESTAMPNTZ: "TIMESTAMP", 313 exp.DType.TIMETZ: "TIME", 314 } 315 316 TRANSFORMS = { 317 **generator.Generator.TRANSFORMS, 318 exp.AnyValue: rename_func("ARBITRARY"), 319 exp.ApproxQuantile: lambda self, e: self.func( 320 "APPROX_PERCENTILE", 321 e.this, 322 e.args.get("weight"), 323 e.args.get("quantile"), 324 e.args.get("accuracy"), 325 ), 326 exp.ArgMax: rename_func("MAX_BY"), 327 exp.ArgMin: rename_func("MIN_BY"), 328 exp.Array: transforms.preprocess( 329 [transforms.inherit_struct_field_names], 330 generator=lambda self, e: f"ARRAY[{self.expressions(e, flat=True)}]", 331 ), 332 exp.ArrayAny: rename_func("ANY_MATCH"), 333 exp.ArrayConcat: rename_func("CONCAT"), 334 exp.ArrayContains: rename_func("CONTAINS"), 335 exp.ArraySort: _array_sort_sql, 336 exp.ArrayToString: rename_func("ARRAY_JOIN"), 337 exp.ArrayUniqueAgg: rename_func("SET_AGG"), 338 exp.ArraySlice: array_slice_to_slice_sql, 339 exp.AtTimeZone: rename_func("AT_TIMEZONE"), 340 exp.BitwiseAnd: lambda self, e: self.func("BITWISE_AND", e.this, e.expression), 341 exp.BitwiseLeftShift: rename_func("BITWISE_LEFT_SHIFT"), 342 exp.BitwiseNot: lambda self, e: self.func("BITWISE_NOT", e.this), 343 exp.BitwiseOr: lambda self, e: self.func("BITWISE_OR", e.this, e.expression), 344 exp.BitwiseRightShift: rename_func("BITWISE_RIGHT_SHIFT"), 345 exp.BitwiseXor: lambda self, e: self.func("BITWISE_XOR", e.this, e.expression), 346 exp.Cast: transforms.preprocess([transforms.epoch_cast_to_ts]), 347 exp.CurrentTime: lambda *_: "CURRENT_TIME", 348 exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP", 349 exp.CurrentUser: lambda *_: "CURRENT_USER", 350 exp.DateAdd: _date_delta_sql("DATE_ADD"), 351 exp.DateDiff: _date_diff_sql, 352 exp.DatetimeDiff: _date_diff_sql, 353 exp.TimestampDiff: _date_diff_sql, 354 exp.DateStrToDate: datestrtodate_sql, 355 exp.DateToDi: lambda self, e: ( 356 f"CAST(DATE_FORMAT({self.sql(e, 'this')}, {type(self.dialect).DATEINT_FORMAT}) AS INT)" 357 ), 358 exp.DateSub: _date_delta_sql("DATE_ADD", negate_interval=True), 359 exp.DayOfWeek: lambda self, e: f"(({self.func('DAY_OF_WEEK', e.this)} % 7) + 1)", 360 exp.DayOfWeekIso: rename_func("DAY_OF_WEEK"), 361 exp.Decode: lambda self, e: encode_decode_sql(self, e, "FROM_UTF8"), 362 exp.DiToDate: lambda self, e: ( 363 f"CAST(DATE_PARSE(CAST({self.sql(e, 'this')} AS VARCHAR), {type(self.dialect).DATEINT_FORMAT}) AS DATE)" 364 ), 365 exp.Encode: lambda self, e: encode_decode_sql(self, e, "TO_UTF8"), 366 exp.FileFormatProperty: lambda self, e: f"format={self.sql(exp.Literal.string(e.name))}", 367 exp.First: _first_last_sql, 368 exp.FromISO8601Date: rename_func("FROM_ISO8601_DATE"), 369 exp.FromISO8601Timestamp: rename_func("FROM_ISO8601_TIMESTAMP"), 370 exp.FromTimeZone: lambda self, e: ( 371 f"WITH_TIMEZONE({self.sql(e, 'this')}, {self.sql(e, 'zone')}) AT TIME ZONE 'UTC'" 372 ), 373 exp.GenerateSeries: sequence_sql, 374 exp.GenerateDateArray: sequence_sql, 375 exp.If: if_sql(), 376 exp.ILike: no_ilike_sql, 377 exp.Initcap: _initcap_sql, 378 exp.Last: _first_last_sql, 379 exp.LastDay: lambda self, e: self.func("LAST_DAY_OF_MONTH", e.this), 380 exp.Lateral: _explode_to_unnest_sql, 381 exp.Left: left_to_substring_sql, 382 exp.Levenshtein: unsupported_args("ins_cost", "del_cost", "sub_cost", "max_dist")( 383 rename_func("LEVENSHTEIN_DISTANCE") 384 ), 385 exp.LogicalAnd: rename_func("BOOL_AND"), 386 exp.LogicalOr: rename_func("BOOL_OR"), 387 exp.Pivot: no_pivot_sql, 388 exp.Quantile: _quantile_sql, 389 exp.RegexpExtract: regexp_extract_sql, 390 exp.RegexpExtractAll: regexp_extract_sql, 391 exp.Right: right_to_substring_sql, 392 exp.Schema: _schema_sql, 393 exp.SchemaCommentProperty: lambda self, e: self.naked_property(e), 394 exp.Select: transforms.preprocess( 395 [ 396 transforms.eliminate_window_clause, 397 transforms.eliminate_qualify, 398 transforms.eliminate_distinct_on, 399 transforms.explode_projection_to_unnest(1, unnest_map=True), 400 transforms.eliminate_semi_and_anti_joins, 401 amend_exploded_column_table, 402 ] 403 ), 404 exp.SqlSecurityProperty: lambda self, e: f"SECURITY {self.sql(e.this)}", 405 exp.StrPosition: lambda self, e: strposition_sql(self, e, supports_occurrence=True), 406 exp.StrToDate: lambda self, e: f"CAST({_str_to_time_sql(self, e)} AS DATE)", 407 exp.StrToMap: rename_func("SPLIT_TO_MAP"), 408 exp.StrToTime: _str_to_time_sql, 409 exp.StructExtract: struct_extract_sql, 410 exp.Table: transforms.preprocess([transforms.unnest_generate_series]), 411 exp.Timestamp: no_timestamp_sql, 412 exp.TimestampAdd: _date_delta_sql("DATE_ADD"), 413 exp.TimestampTrunc: timestamptrunc_sql(), 414 exp.TimeStrToDate: timestrtotime_sql, 415 exp.TimeStrToTime: timestrtotime_sql, 416 exp.TimeStrToUnix: lambda self, e: self.func( 417 "TO_UNIXTIME", self.func("DATE_PARSE", e.this, type(self.dialect).TIME_FORMAT) 418 ), 419 exp.TimeToStr: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 420 exp.TimeToUnix: rename_func("TO_UNIXTIME"), 421 exp.ToChar: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 422 exp.TryCast: transforms.preprocess([transforms.epoch_cast_to_ts]), 423 exp.TsOrDiToDi: lambda self, e: ( 424 f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS VARCHAR), '-', ''), 1, 8) AS INT)" 425 ), 426 exp.TsOrDsAdd: _ts_or_ds_add_sql, 427 exp.TsOrDsDiff: _ts_or_ds_diff_sql, 428 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 429 exp.Unhex: rename_func("FROM_HEX"), 430 exp.UnixToStr: lambda self, e: ( 431 f"DATE_FORMAT(FROM_UNIXTIME({self.sql(e, 'this')}), {self.format_time(e)})" 432 ), 433 exp.UnixToTime: _unix_to_time_sql, 434 exp.UnixToTimeStr: lambda self, e: f"CAST(FROM_UNIXTIME({self.sql(e, 'this')}) AS VARCHAR)", 435 exp.VariancePop: rename_func("VAR_POP"), 436 exp.With: transforms.preprocess([transforms.add_recursive_cte_column_names]), 437 exp.WithinGroup: transforms.preprocess([transforms.remove_within_group_for_percentiles]), 438 # Note: Presto's TRUNCATE always returns DOUBLE, even with decimals=0, whereas 439 # most dialects return INT (SQLite also returns REAL, see sqlite.py). This creates 440 # a bidirectional transpilation gap: Presto→Other may change float division to int 441 # division, and vice versa. Modeling precisely would require exp.FloatTrunc or 442 # similar, deemed overengineering for this subtle semantic difference. 443 exp.Trunc: rename_func("TRUNCATE"), 444 exp.Xor: bool_xor_sql, 445 exp.MD5Digest: rename_func("MD5"), 446 exp.SHA: rename_func("SHA1"), 447 exp.SHA1Digest: rename_func("SHA1"), 448 exp.SHA2Digest: _sha2_digest_sql, 449 exp.Substring: rename_func("SUBSTR"), 450 } 451 452 RESERVED_KEYWORDS = { 453 "alter", 454 "and", 455 "as", 456 "between", 457 "by", 458 "case", 459 "cast", 460 "constraint", 461 "create", 462 "cross", 463 "current_time", 464 "current_timestamp", 465 "deallocate", 466 "delete", 467 "describe", 468 "distinct", 469 "drop", 470 "else", 471 "end", 472 "escape", 473 "except", 474 "execute", 475 "exists", 476 "extract", 477 "false", 478 "for", 479 "from", 480 "full", 481 "group", 482 "having", 483 "in", 484 "inner", 485 "insert", 486 "intersect", 487 "into", 488 "is", 489 "join", 490 "left", 491 "like", 492 "natural", 493 "not", 494 "null", 495 "on", 496 "or", 497 "order", 498 "outer", 499 "prepare", 500 "right", 501 "select", 502 "table", 503 "then", 504 "true", 505 "union", 506 "using", 507 "values", 508 "when", 509 "where", 510 "with", 511 } 512 513 def datatype_sql(self, expression: exp.DataType) -> str: 514 if not self.SUPPORTS_TEMPORAL_PRECISION and expression.this in exp.DataType.TEMPORAL_TYPES: 515 if expression.expressions and expression.expressions[0].name != "3": 516 self.unsupported("Presto only supports millisecond precision for temporal types") 517 expression.set("expressions", None) 518 return super().datatype_sql(expression) 519 520 def extract_sql(self, expression: exp.Extract) -> str: 521 date_part = expression.name 522 523 if not date_part.startswith("EPOCH"): 524 return super().extract_sql(expression) 525 526 if date_part == "EPOCH_MILLISECOND": 527 scale = 10**3 528 elif date_part == "EPOCH_MICROSECOND": 529 scale = 10**6 530 elif date_part == "EPOCH_NANOSECOND": 531 scale = 10**9 532 else: 533 scale = None 534 535 value = expression.expression 536 537 ts = exp.cast(value, to=exp.DType.TIMESTAMP.into_expr()) 538 to_unix: exp.Expr = exp.TimeToUnix(this=ts) 539 540 if scale: 541 to_unix = exp.Mul(this=to_unix, expression=exp.Literal.number(scale)) 542 543 return self.sql(to_unix) 544 545 def jsonformat_sql(self, expression: exp.JSONFormat) -> str: 546 this = expression.this 547 is_json = expression.args.get("is_json") 548 549 if this and not (is_json or this.type): 550 from sqlglot.optimizer.annotate_types import annotate_types 551 552 this = annotate_types(this, dialect=self.dialect) 553 554 if not (is_json or this.is_type(exp.DType.JSON)): 555 this.replace(exp.cast(this, exp.DType.JSON)) 556 557 return self.function_fallback_sql(expression) 558 559 def md5_sql(self, expression: exp.MD5) -> str: 560 this = expression.this 561 562 if not this.type: 563 from sqlglot.optimizer.annotate_types import annotate_types 564 565 this = annotate_types(this, dialect=self.dialect) 566 567 if this.is_type(*exp.DataType.TEXT_TYPES): 568 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 569 570 return self.func("LOWER", self.func("TO_HEX", self.func("MD5", self.sql(this)))) 571 572 def sha2_sql(self, expression: exp.SHA2) -> str: 573 length = expression.text("length") or "256" 574 if length not in ("256", "512"): 575 self.unsupported(f"SHA{length} is not supported in Presto") 576 577 this = expression.this 578 579 if this.is_type(*exp.DataType.TEXT_TYPES): 580 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 581 582 return self.func("LOWER", self.func("TO_HEX", self.func(f"SHA{length}", self.sql(this)))) 583 584 def strtounix_sql(self, expression: exp.StrToUnix) -> str: 585 # Since `TO_UNIXTIME` requires a `TIMESTAMP`, we need to parse the argument into one. 586 # To do this, we first try to `DATE_PARSE` it, but since this can fail when there's a 587 # timezone involved, we wrap it in a `TRY` call and use `PARSE_DATETIME` as a fallback, 588 # which seems to be using the same time mapping as Hive, as per: 589 # https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html 590 this = expression.this 591 value_as_text = exp.cast(this, exp.DType.TEXT) 592 value_as_timestamp = exp.cast(this, exp.DType.TIMESTAMP) if this.is_string else this 593 594 parse_without_tz = self.func("DATE_PARSE", value_as_text, self.format_time(expression)) 595 596 formatted_value = self.func("DATE_FORMAT", value_as_timestamp, self.format_time(expression)) 597 parse_with_tz = self.func( 598 "PARSE_DATETIME", 599 formatted_value, 600 self.format_time(expression, Hive.INVERSE_TIME_MAPPING, Hive.INVERSE_TIME_TRIE), 601 ) 602 coalesced = self.func("COALESCE", self.func("TRY", parse_without_tz), parse_with_tz) 603 return self.func("TO_UNIXTIME", coalesced) 604 605 def bracket_sql(self, expression: exp.Bracket) -> str: 606 if expression.args.get("safe"): 607 return bracket_to_element_at_sql(self, expression) 608 return super().bracket_sql(expression) 609 610 def struct_sql(self, expression: exp.Struct) -> str: 611 if not expression.type: 612 from sqlglot.optimizer.annotate_types import annotate_types 613 614 annotate_types(expression, dialect=self.dialect) 615 616 values: list[str] = [] 617 schema: list[str] = [] 618 unknown_type = False 619 620 for e in expression.expressions: 621 if isinstance(e, exp.PropertyEQ): 622 if e.type and e.type.is_type(exp.DType.UNKNOWN): 623 unknown_type = True 624 else: 625 schema.append(f"{self.sql(e, 'this')} {self.sql(e.type)}") 626 values.append(self.sql(e, "expression")) 627 else: 628 values.append(self.sql(e)) 629 630 size = len(expression.expressions) 631 632 if not size or len(schema) != size: 633 if unknown_type: 634 self.unsupported( 635 "Cannot convert untyped key-value definitions (try annotate_types)." 636 ) 637 return self.func("ROW", *values) 638 return f"CAST(ROW({', '.join(values)}) AS ROW({', '.join(schema)}))" 639 640 def interval_sql(self, expression: exp.Interval) -> str: 641 this = expression.this 642 if this and expression.text("unit").upper().startswith("WEEK"): 643 if not this.is_string: 644 return f"({self.sql(this)} * INTERVAL '7' DAY)" 645 if is_float(this.name): 646 return f"({this.name} * INTERVAL '7' DAY)" 647 return super().interval_sql(expression) 648 649 def transaction_sql(self, expression: exp.Transaction) -> str: 650 modes = expression.args.get("modes") 651 modes = f" {', '.join(modes)}" if modes else "" 652 return f"START TRANSACTION{modes}" 653 654 def offset_limit_modifiers( 655 self, expression: exp.Expr, fetch: bool, limit: exp.Fetch | exp.Limit | None 656 ) -> list[str]: 657 return [ 658 self.sql(expression, "offset"), 659 self.sql(limit), 660 ] 661 662 def create_sql(self, expression: exp.Create) -> str: 663 """ 664 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 665 so we need to remove them 666 """ 667 kind = expression.args["kind"] 668 schema = expression.this 669 if kind == "VIEW" and schema.expressions: 670 expression.this.set("expressions", None) 671 return super().create_sql(expression) 672 673 def delete_sql(self, expression: exp.Delete) -> str: 674 """ 675 Presto only supports DELETE FROM for a single table without an alias, so we need 676 to remove the unnecessary parts. If the original DELETE statement contains more 677 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 678 """ 679 tables = expression.args.get("tables") or [expression.this] 680 if len(tables) > 1: 681 return super().delete_sql(expression) 682 683 table = tables[0] 684 expression.set("this", table) 685 expression.set("tables", None) 686 687 if isinstance(table, exp.Table): 688 table_alias = table.args.get("alias") 689 if table_alias: 690 table_alias.pop() 691 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 692 693 return super().delete_sql(expression) 694 695 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 696 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 697 698 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 699 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 700 if not expression.args.get("variant_extract") or is_json_extract: 701 return self.func( 702 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 703 ) 704 705 this = self.sql(expression, "this") 706 707 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 708 segments = [] 709 for path_key in expression.expression.expressions[1:]: 710 if not isinstance(path_key, exp.JSONPathKey): 711 # Cannot transpile subscripts, wildcards etc to dot notation 712 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 713 continue 714 key = path_key.this 715 if not exp.SAFE_IDENTIFIER_RE.match(key): 716 key = f'"{key}"' 717 segments.append(f".{key}") 718 719 expr = "".join(segments) 720 721 return f"{this}{expr}" 722 723 def groupconcat_sql(self, expression: exp.GroupConcat) -> str: 724 return self.func( 725 "ARRAY_JOIN", 726 self.func("ARRAY_AGG", expression.this), 727 expression.args.get("separator"), 728 )
Generator converts a given syntax tree to the corresponding SQL string.
Arguments:
- pretty: Whether to format the produced SQL string. Default: False.
- identify: Determines when an identifier should be quoted. Possible values are: False (default): Never quote, except in cases where it's mandatory by the dialect. True: Always quote except for specials cases. 'safe': Only quote identifiers that are case insensitive.
- normalize: Whether to normalize identifiers to lowercase. Default: False.
- pad: The pad size in a formatted string. For example, this affects the indentation of a projection in a query, relative to its nesting level. Default: 2.
- indent: The indentation size in a formatted string. For example, this affects the
indentation of subqueries and filters under a
WHEREclause. Default: 2. - normalize_functions: How to normalize function names. Possible values are: "upper" or True (default): Convert names to uppercase. "lower": Convert names to lowercase. False: Disables function name normalization.
- unsupported_level: Determines the generator's behavior when it encounters unsupported expressions. Default ErrorLevel.WARN.
- max_unsupported: Maximum number of unsupported messages to include in a raised UnsupportedError. This is only relevant if unsupported_level is ErrorLevel.RAISE. Default: 3
- leading_comma: Whether the comma is leading or trailing in select expressions. This is only relevant when generating in pretty mode. Default: False
- max_text_width: The max number of characters in a segment before creating new lines in pretty mode. The default is on the smaller end because the length only represents a segment and not the true line length. Default: 80
- comments: Whether to preserve comments in the output SQL code. Default: True
PROPERTIES_LOCATION =
{<class 'sqlglot.expressions.properties.AggregateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AlgorithmProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApiProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.AutoIncrementProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BackupProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.BlockCompressionProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CalledOnNullInputProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ChecksumProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.CollateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.CopyTagsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.query.Cluster'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusteredByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ClusterProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistributedByProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DuplicateKeyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DataBlocksizeProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DataDeletionProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DefinerProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DictRange'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.DistKeyProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EncodeProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.EngineProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.FallbackProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.FreespaceProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.HeapProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.HybridProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.IgnoreGrantsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InteractiveProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.IsolatedLoadingProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.JournalProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LikeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LocationProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.LockProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.LockingProperty'>: <PropertiesLocation.POST_ALIAS: 'POST_ALIAS'>, <class 'sqlglot.expressions.properties.LogProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.MergeBlockRatioProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.ModuleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OnProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.OptionsProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.query.Order'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PartitionedByProperty'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.PartitionedOfProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.PhysicalProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.constraints.PrimaryKey'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Property'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.RefreshTriggerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RollupProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.RowFormatProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatDelimitedProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.RowFormatSerdeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SampleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SchemaCommentProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SecureProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SerdeProperties'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.Set'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SetProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SharingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.SequenceProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.ddl.TriggerProperties'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.SortKeyProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StorageHandlerProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.StorageProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.StrictProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.Tags'>: <PropertiesLocation.POST_WITH: 'POST_WITH'>, <class 'sqlglot.expressions.properties.TableSpaceProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.TransientProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.ddl.MergeTreeTTL'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.UsingProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.WithDataProperty'>: <PropertiesLocation.POST_EXPRESSION: 'POST_EXPRESSION'>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <PropertiesLocation.POST_NAME: 'POST_NAME'>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithSystemVersioningProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.WithoutRowidProperty'>: <PropertiesLocation.UNSUPPORTED: 'UNSUPPORTED'>, <class 'sqlglot.expressions.properties.ForceProperty'>: <PropertiesLocation.POST_CREATE: 'POST_CREATE'>}
TYPE_MAPPING =
{<DType.DATETIME2: 'DATETIME2'>: 'TIMESTAMP', <DType.NCHAR: 'NCHAR'>: 'CHAR', <DType.NVARCHAR: 'NVARCHAR'>: 'VARCHAR', <DType.MEDIUMTEXT: 'MEDIUMTEXT'>: 'TEXT', <DType.LONGTEXT: 'LONGTEXT'>: 'TEXT', <DType.TINYTEXT: 'TINYTEXT'>: 'TEXT', <DType.BLOB: 'BLOB'>: 'VARBINARY', <DType.MEDIUMBLOB: 'MEDIUMBLOB'>: 'BLOB', <DType.LONGBLOB: 'LONGBLOB'>: 'BLOB', <DType.TINYBLOB: 'TINYBLOB'>: 'BLOB', <DType.INET: 'INET'>: 'INET', <DType.ROWVERSION: 'ROWVERSION'>: 'VARBINARY', <DType.SMALLDATETIME: 'SMALLDATETIME'>: 'TIMESTAMP', <DType.BINARY: 'BINARY'>: 'VARBINARY', <DType.BIT: 'BIT'>: 'BOOLEAN', <DType.DATETIME: 'DATETIME'>: 'TIMESTAMP', <DType.DATETIME64: 'DATETIME64'>: 'TIMESTAMP', <DType.FLOAT: 'FLOAT'>: 'REAL', <DType.HLLSKETCH: 'HLLSKETCH'>: 'HYPERLOGLOG', <DType.INT: 'INT'>: 'INTEGER', <DType.STRUCT: 'STRUCT'>: 'ROW', <DType.TEXT: 'TEXT'>: 'VARCHAR', <DType.TIMESTAMPTZ: 'TIMESTAMPTZ'>: 'TIMESTAMP', <DType.TIMESTAMPNTZ: 'TIMESTAMPNTZ'>: 'TIMESTAMP', <DType.TIMETZ: 'TIMETZ'>: 'TIME'}
TRANSFORMS =
{<class 'sqlglot.expressions.query.JSONPathFilter'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathKey'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathRecursive'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathRoot'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathScript'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSelector'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSlice'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathSubscript'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathUnion'>: <function <lambda>>, <class 'sqlglot.expressions.query.JSONPathWildcard'>: <function <lambda>>, <class 'sqlglot.expressions.core.Adjacent'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AllowedValuesProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.AnalyzeColumns'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.AnalyzeWith'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayContainedBy'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayContainsAll'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ArrayOverlaps'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.AssumeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.AutoRefreshProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.BackupProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.BinaryColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CaseSpecificColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CalledOnNullInputProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Ceil'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CharacterSetColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CharacterSetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CollateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.CommentColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.ConnectByRoot'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.string.ConvertToCharset'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CopyTagsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CredentialsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentCatalog'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.SessionUser'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.DateFormatColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.DefaultColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApiProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ApplicationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.CatalogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ComputeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DatabaseProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.DynamicProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EmptyProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EncodeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.EndStatement'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.EnviromentProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HandlerProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ParameterStyleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.EphemeralColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ExcludeColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExecuteAsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Except'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ExternalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.math.Floor'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Get'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.GlobalProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HeapProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.HybridProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.IcebergProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.IgnoreGrantsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InheritsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InlineLengthColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Intersect'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.datatypes.IntervalSpan'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.Int64'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAnyTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsAllTopKeys'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBContainsTopKey'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBDeleteAtPath'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONBPathExists'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObject'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.json.JSONObjectAgg'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LanguageProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LocationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.LogProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaskingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.MaterializedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.functions.NetFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NetworkProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NonClusteredColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.NoPrimaryIndexProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.NotForReplicationColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnCommitProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OnProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.OnUpdateColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.Operator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.OutputModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsLeft'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.ExtendsRight'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.PathColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionedByBucket'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.PartitionByTruncate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.PivotAny'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.PositionalColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ProjectionPolicyColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.InvisibleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.ZeroFillColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Put'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RemoteWithConnectionModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ReturnsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.RowAccessProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.core.SafeFunc'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SampleProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecureProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SecurityIntegrationProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetConfigProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SetProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SettingsProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SharingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlReadWriteProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.SqlSecurityProperty'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.properties.StabilityProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Stream'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StreamingTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.StrictProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.SwapTable'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.TableColumn'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.Tags'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TemporaryProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.TitleColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.ToMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ToTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransformModelProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.TransientProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VirtualProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.ddl.TriggerExecute'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Union'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UnloggedProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.UsingTemplateProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.UsingData'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.UppercaseColumnConstraint'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcDate'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTime'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.temporal.UtcTimestamp'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.query.Variadic'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.array.VarMap'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ViewAttributeProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.VolatileProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithJournalTableProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithProcedureOptions'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithSchemaBindingProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.constraints.WithOperator'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.WithoutRowidProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.properties.ForceProperty'>: <function Generator.<lambda>>, <class 'sqlglot.expressions.aggregate.AnyValue'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.ApproxQuantile'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.aggregate.ArgMax'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.ArgMin'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.array.Array'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.array.ArrayAny'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.array.ArrayConcat'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.array.ArrayContains'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.array.ArraySort'>: <function _array_sort_sql>, <class 'sqlglot.expressions.array.ArrayToString'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.ArrayUniqueAgg'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.array.ArraySlice'>: <function array_slice_to_slice_sql>, <class 'sqlglot.expressions.core.AtTimeZone'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.BitwiseAnd'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.core.BitwiseLeftShift'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.BitwiseNot'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.core.BitwiseOr'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.core.BitwiseRightShift'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.BitwiseXor'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.functions.Cast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.temporal.CurrentTime'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.CurrentTimestamp'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.functions.CurrentUser'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.DateAdd'>: <function _date_delta_sql.<locals>._delta_sql>, <class 'sqlglot.expressions.temporal.DateDiff'>: <function _date_diff_sql>, <class 'sqlglot.expressions.temporal.DatetimeDiff'>: <function _date_diff_sql>, <class 'sqlglot.expressions.temporal.TimestampDiff'>: <function _date_diff_sql>, <class 'sqlglot.expressions.temporal.DateStrToDate'>: <function datestrtodate_sql>, <class 'sqlglot.expressions.temporal.DateToDi'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.DateSub'>: <function _date_delta_sql.<locals>._delta_sql>, <class 'sqlglot.expressions.temporal.DayOfWeek'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.DayOfWeekIso'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.Decode'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.DiToDate'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.string.Encode'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.properties.FileFormatProperty'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.aggregate.First'>: <function _first_last_sql>, <class 'sqlglot.expressions.temporal.FromISO8601Date'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.FromISO8601Timestamp'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.FromTimeZone'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.array.GenerateSeries'>: <function sequence_sql>, <class 'sqlglot.expressions.temporal.GenerateDateArray'>: <function sequence_sql>, <class 'sqlglot.expressions.functions.If'>: <function if_sql.<locals>._if_sql>, <class 'sqlglot.expressions.core.ILike'>: <function no_ilike_sql>, <class 'sqlglot.expressions.string.Initcap'>: <function _initcap_sql>, <class 'sqlglot.expressions.aggregate.Last'>: <function _first_last_sql>, <class 'sqlglot.expressions.temporal.LastDay'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.query.Lateral'>: <function _explode_to_unnest_sql>, <class 'sqlglot.expressions.string.Left'>: <function left_to_substring_sql>, <class 'sqlglot.expressions.string.Levenshtein'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.LogicalAnd'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.aggregate.LogicalOr'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.Pivot'>: <function no_pivot_sql>, <class 'sqlglot.expressions.aggregate.Quantile'>: <function _quantile_sql>, <class 'sqlglot.expressions.string.RegexpExtract'>: <function regexp_extract_sql>, <class 'sqlglot.expressions.string.RegexpExtractAll'>: <function regexp_extract_sql>, <class 'sqlglot.expressions.string.Right'>: <function right_to_substring_sql>, <class 'sqlglot.expressions.query.Schema'>: <function _schema_sql>, <class 'sqlglot.expressions.properties.SchemaCommentProperty'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.query.Select'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.string.StrPosition'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.StrToDate'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.string.StrToMap'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.StrToTime'>: <function _str_to_time_sql>, <class 'sqlglot.expressions.array.StructExtract'>: <function struct_extract_sql>, <class 'sqlglot.expressions.query.Table'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.temporal.Timestamp'>: <function no_timestamp_sql>, <class 'sqlglot.expressions.temporal.TimestampAdd'>: <function _date_delta_sql.<locals>._delta_sql>, <class 'sqlglot.expressions.temporal.TimestampTrunc'>: <function timestamptrunc_sql.<locals>._timestamptrunc_sql>, <class 'sqlglot.expressions.temporal.TimeStrToDate'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.temporal.TimeStrToTime'>: <function timestrtotime_sql>, <class 'sqlglot.expressions.temporal.TimeStrToUnix'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimeToStr'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TimeToUnix'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.ToChar'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.functions.TryCast'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.temporal.TsOrDiToDi'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.TsOrDsAdd'>: <function _ts_or_ds_add_sql>, <class 'sqlglot.expressions.temporal.TsOrDsDiff'>: <function _ts_or_ds_diff_sql>, <class 'sqlglot.expressions.temporal.TsOrDsToDate'>: <function _ts_or_ds_to_date_sql>, <class 'sqlglot.expressions.string.Unhex'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.temporal.UnixToStr'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.temporal.UnixToTime'>: <function _unix_to_time_sql>, <class 'sqlglot.expressions.temporal.UnixToTimeStr'>: <function PrestoGenerator.<lambda>>, <class 'sqlglot.expressions.aggregate.VariancePop'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.query.With'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.core.WithinGroup'>: <function preprocess.<locals>._to_sql>, <class 'sqlglot.expressions.math.Trunc'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.core.Xor'>: <function bool_xor_sql>, <class 'sqlglot.expressions.string.MD5Digest'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.SHA'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.SHA1Digest'>: <function rename_func.<locals>.<lambda>>, <class 'sqlglot.expressions.string.SHA2Digest'>: <function _sha2_digest_sql>, <class 'sqlglot.expressions.string.Substring'>: <function rename_func.<locals>.<lambda>>}
RESERVED_KEYWORDS =
{'on', 'insert', 'intersect', 'inner', 'false', 'join', 'then', 'left', 'order', 'else', 'using', 'table', 'current_timestamp', 'delete', 'is', 'true', 'execute', 'in', 'escape', 'values', 'cross', 'except', 'natural', 'into', 'end', 'distinct', 'exists', 'full', 'like', 'outer', 'union', 'when', 'deallocate', 'drop', 'having', 'where', 'extract', 'alter', 'constraint', 'with', 'current_time', 'create', 'cast', 'null', 'select', 'or', 'by', 'right', 'between', 'group', 'not', 'as', 'prepare', 'case', 'for', 'and', 'describe', 'from'}
513 def datatype_sql(self, expression: exp.DataType) -> str: 514 if not self.SUPPORTS_TEMPORAL_PRECISION and expression.this in exp.DataType.TEMPORAL_TYPES: 515 if expression.expressions and expression.expressions[0].name != "3": 516 self.unsupported("Presto only supports millisecond precision for temporal types") 517 expression.set("expressions", None) 518 return super().datatype_sql(expression)
520 def extract_sql(self, expression: exp.Extract) -> str: 521 date_part = expression.name 522 523 if not date_part.startswith("EPOCH"): 524 return super().extract_sql(expression) 525 526 if date_part == "EPOCH_MILLISECOND": 527 scale = 10**3 528 elif date_part == "EPOCH_MICROSECOND": 529 scale = 10**6 530 elif date_part == "EPOCH_NANOSECOND": 531 scale = 10**9 532 else: 533 scale = None 534 535 value = expression.expression 536 537 ts = exp.cast(value, to=exp.DType.TIMESTAMP.into_expr()) 538 to_unix: exp.Expr = exp.TimeToUnix(this=ts) 539 540 if scale: 541 to_unix = exp.Mul(this=to_unix, expression=exp.Literal.number(scale)) 542 543 return self.sql(to_unix)
545 def jsonformat_sql(self, expression: exp.JSONFormat) -> str: 546 this = expression.this 547 is_json = expression.args.get("is_json") 548 549 if this and not (is_json or this.type): 550 from sqlglot.optimizer.annotate_types import annotate_types 551 552 this = annotate_types(this, dialect=self.dialect) 553 554 if not (is_json or this.is_type(exp.DType.JSON)): 555 this.replace(exp.cast(this, exp.DType.JSON)) 556 557 return self.function_fallback_sql(expression)
559 def md5_sql(self, expression: exp.MD5) -> str: 560 this = expression.this 561 562 if not this.type: 563 from sqlglot.optimizer.annotate_types import annotate_types 564 565 this = annotate_types(this, dialect=self.dialect) 566 567 if this.is_type(*exp.DataType.TEXT_TYPES): 568 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 569 570 return self.func("LOWER", self.func("TO_HEX", self.func("MD5", self.sql(this))))
572 def sha2_sql(self, expression: exp.SHA2) -> str: 573 length = expression.text("length") or "256" 574 if length not in ("256", "512"): 575 self.unsupported(f"SHA{length} is not supported in Presto") 576 577 this = expression.this 578 579 if this.is_type(*exp.DataType.TEXT_TYPES): 580 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 581 582 return self.func("LOWER", self.func("TO_HEX", self.func(f"SHA{length}", self.sql(this))))
584 def strtounix_sql(self, expression: exp.StrToUnix) -> str: 585 # Since `TO_UNIXTIME` requires a `TIMESTAMP`, we need to parse the argument into one. 586 # To do this, we first try to `DATE_PARSE` it, but since this can fail when there's a 587 # timezone involved, we wrap it in a `TRY` call and use `PARSE_DATETIME` as a fallback, 588 # which seems to be using the same time mapping as Hive, as per: 589 # https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html 590 this = expression.this 591 value_as_text = exp.cast(this, exp.DType.TEXT) 592 value_as_timestamp = exp.cast(this, exp.DType.TIMESTAMP) if this.is_string else this 593 594 parse_without_tz = self.func("DATE_PARSE", value_as_text, self.format_time(expression)) 595 596 formatted_value = self.func("DATE_FORMAT", value_as_timestamp, self.format_time(expression)) 597 parse_with_tz = self.func( 598 "PARSE_DATETIME", 599 formatted_value, 600 self.format_time(expression, Hive.INVERSE_TIME_MAPPING, Hive.INVERSE_TIME_TRIE), 601 ) 602 coalesced = self.func("COALESCE", self.func("TRY", parse_without_tz), parse_with_tz) 603 return self.func("TO_UNIXTIME", coalesced)
610 def struct_sql(self, expression: exp.Struct) -> str: 611 if not expression.type: 612 from sqlglot.optimizer.annotate_types import annotate_types 613 614 annotate_types(expression, dialect=self.dialect) 615 616 values: list[str] = [] 617 schema: list[str] = [] 618 unknown_type = False 619 620 for e in expression.expressions: 621 if isinstance(e, exp.PropertyEQ): 622 if e.type and e.type.is_type(exp.DType.UNKNOWN): 623 unknown_type = True 624 else: 625 schema.append(f"{self.sql(e, 'this')} {self.sql(e.type)}") 626 values.append(self.sql(e, "expression")) 627 else: 628 values.append(self.sql(e)) 629 630 size = len(expression.expressions) 631 632 if not size or len(schema) != size: 633 if unknown_type: 634 self.unsupported( 635 "Cannot convert untyped key-value definitions (try annotate_types)." 636 ) 637 return self.func("ROW", *values) 638 return f"CAST(ROW({', '.join(values)}) AS ROW({', '.join(schema)}))"
640 def interval_sql(self, expression: exp.Interval) -> str: 641 this = expression.this 642 if this and expression.text("unit").upper().startswith("WEEK"): 643 if not this.is_string: 644 return f"({self.sql(this)} * INTERVAL '7' DAY)" 645 if is_float(this.name): 646 return f"({this.name} * INTERVAL '7' DAY)" 647 return super().interval_sql(expression)
def
offset_limit_modifiers( self, expression: sqlglot.expressions.core.Expr, fetch: bool, limit: sqlglot.expressions.query.Fetch | sqlglot.expressions.query.Limit | None) -> list[str]:
662 def create_sql(self, expression: exp.Create) -> str: 663 """ 664 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 665 so we need to remove them 666 """ 667 kind = expression.args["kind"] 668 schema = expression.this 669 if kind == "VIEW" and schema.expressions: 670 expression.this.set("expressions", None) 671 return super().create_sql(expression)
Presto doesn't support CREATE VIEW with expressions (ex: CREATE VIEW x (cola) then (cola) is the expression),
so we need to remove them
673 def delete_sql(self, expression: exp.Delete) -> str: 674 """ 675 Presto only supports DELETE FROM for a single table without an alias, so we need 676 to remove the unnecessary parts. If the original DELETE statement contains more 677 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 678 """ 679 tables = expression.args.get("tables") or [expression.this] 680 if len(tables) > 1: 681 return super().delete_sql(expression) 682 683 table = tables[0] 684 expression.set("this", table) 685 expression.set("tables", None) 686 687 if isinstance(table, exp.Table): 688 table_alias = table.args.get("alias") 689 if table_alias: 690 table_alias.pop() 691 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 692 693 return super().delete_sql(expression)
Presto only supports DELETE FROM for a single table without an alias, so we need to remove the unnecessary parts. If the original DELETE statement contains more than one table to be deleted, we can't safely map it 1-1 to a Presto statement.
695 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 696 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 697 698 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 699 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 700 if not expression.args.get("variant_extract") or is_json_extract: 701 return self.func( 702 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 703 ) 704 705 this = self.sql(expression, "this") 706 707 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 708 segments = [] 709 for path_key in expression.expression.expressions[1:]: 710 if not isinstance(path_key, exp.JSONPathKey): 711 # Cannot transpile subscripts, wildcards etc to dot notation 712 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 713 continue 714 key = path_key.this 715 if not exp.SAFE_IDENTIFIER_RE.match(key): 716 key = f'"{key}"' 717 segments.append(f".{key}") 718 719 expr = "".join(segments) 720 721 return f"{this}{expr}"
Inherited Members
- sqlglot.generator.Generator
- Generator
- NULL_ORDERING_SUPPORTED
- WINDOW_FUNCS_WITH_NULL_ORDERING
- IGNORE_NULLS_IN_FUNC
- IGNORE_NULLS_BEFORE_ORDER
- LOCKING_READS_SUPPORTED
- WRAP_DERIVED_VALUES
- CREATE_FUNCTION_RETURN_AS
- MATCHED_BY_SOURCE
- SUPPORTS_MERGE_WHERE
- MERGE_ALL_BY_NAME
- SINGLE_STRING_INTERVAL
- AUTO_REFRESH_BARE_INTERVALS
- LIMIT_FETCH
- RENAME_TABLE_WITH_DB
- GROUPINGS_SEP
- SUPPORTS_GROUPING_SETS_AS_SUFFIX
- INDEX_ON
- INOUT_SEPARATOR
- DIRECTED_JOINS
- SUPPORTS_NEAREST_JOIN
- QUERY_HINT_SEP
- SAFE_INT_DIVISION
- DUPLICATE_KEY_UPDATE_WITH_SET
- LIMIT_IS_TOP
- RETURNING_END
- EXTRACT_ALLOWS_QUOTES
- VALUES_AS_TABLE
- ALTER_TABLE_INCLUDE_COLUMN_KEYWORD
- ALTER_TABLE_ADD_COLUMNS_WRAPPED
- UNNEST_WITH_ORDINALITY
- SEMI_ANTI_JOIN_WITH_SIDE
- COMPUTED_COLUMN_WITH_TYPE
- SUPPORTS_TABLE_COPY
- TABLESAMPLE_REQUIRES_PARENS
- TABLESAMPLE_SIZE_IS_ROWS
- TABLESAMPLE_KEYWORDS
- TABLESAMPLE_WITH_METHOD
- TABLESAMPLE_SEED_KEYWORD
- HISTORICAL_DATA_POST_ALIAS
- COLLATE_IS_FUNC
- DATA_TYPE_SPECIFIERS_ALLOWED
- ENSURE_BOOLS
- CTE_RECURSIVE_KEYWORD_REQUIRED
- LAST_DAY_SUPPORTS_DATE_PART
- SUPPORTS_TABLE_ALIAS_COLUMNS
- SUPPORTS_NAMED_CTE_COLUMNS
- UNPIVOT_ALIASES_ARE_IDENTIFIERS
- PIVOT_ALIAS_WITH_AS
- JSON_KEY_VALUE_PAIR_SEP
- INSERT_OVERWRITE
- SUPPORTS_SELECT_INTO
- SUPPORTS_UNLOGGED_TABLES
- SUPPORTS_CREATE_TABLE_LIKE
- SUPPORTS_MODIFY_COLUMN
- SUPPORTS_CHANGE_COLUMN
- SUPPORTS_ALTER_COLUMN_NULLABILITY
- SUPPORTS_ALTER_COLUMN_IF_EXISTS
- JSON_TYPE_REQUIRED_FOR_EXTRACTION
- JSON_PATH_BRACKETED_KEY_SUPPORTED
- JSON_PATH_SINGLE_QUOTE_ESCAPE
- JSON_PATH_KEY_QUOTED_FORCES_BRACKETS
- SUPPORTED_JSON_PATH_PARTS
- CAN_IMPLEMENT_ARRAY_ANY
- SUPPORTS_WINDOW_EXCLUDE
- SET_OP_MODIFIERS
- SET_OP_LIMITS
- SET_OP_PARENTHESIZED_OPERANDS
- COPY_PARAMS_ARE_WRAPPED
- COPY_PARAMS_EQ_REQUIRED
- COPY_HAS_INTO_KEYWORD
- TRY_SUPPORTED
- SUPPORTS_UESCAPE
- UNICODE_SUBSTITUTE
- STAR_EXCEPT
- BYTE_STRING_FUNCTION
- WITH_PROPERTIES_PREFIX
- QUOTE_JSON_PATH
- SUPPORTS_EXPLODING_PROJECTIONS
- ARRAY_CONCAT_IS_VAR_LEN
- SUPPORTS_CONVERT_TIMEZONE
- SUPPORTS_UNIX_SECONDS
- ALTER_SET_WRAPPED
- NORMALIZE_EXTRACT_DATE_PARTS
- ALTER_SET_TYPE
- ARRAY_SIZE_DIM_REQUIRED
- SUPPORTS_BETWEEN_FLAGS
- SUPPORTS_LIKE_QUANTIFIERS
- MATCH_AGAINST_TABLE_PREFIX
- SET_ASSIGNMENT_REQUIRES_VARIABLE_KEYWORD
- DECLARE_DEFAULT_ASSIGNMENT
- UPDATE_STATEMENT_SUPPORTS_FROM
- STAR_EXCLUDE_REQUIRES_DERIVED_TABLE
- SUPPORTS_DROP_ALTER_ICEBERG_PROPERTY
- UNSUPPORTED_TYPES
- TYPE_PARAM_SETTINGS
- TIME_PART_SINGULARS
- TOKEN_MAPPING
- PARAMETER_TOKEN
- NAMED_PLACEHOLDER_TOKEN
- EXPRESSION_PRECEDES_PROPERTIES_CREATABLES
- WITH_SEPARATED_COMMENTS
- EXCLUDE_COMMENTS
- UNWRAPPED_INTERVAL_VALUES
- PARAMETERIZABLE_TEXT_TYPES
- EXPRESSIONS_WITHOUT_NESTED_CTES
- RESPECT_IGNORE_NULLS_UNSUPPORTED_EXPRESSIONS
- MOD_OPERATOR
- MOD_PAREN_PARENT_TYPES
- ALTER_PARTITION_OPTIONS
- SAFE_JSON_PATH_KEY_RE
- SENTINEL_LINE_BREAK
- pretty
- identify
- normalize
- pad
- unsupported_level
- max_unsupported
- leading_comma
- max_text_width
- comments
- dialect
- normalize_functions
- unsupported_messages
- generate
- preprocess
- unsupported
- sep
- seg
- sanitize_comment
- maybe_comment
- wrap
- no_identify
- normalize_func
- indent
- sql
- uncache_sql
- cache_sql
- characterset_sql
- column_parts
- column_sql
- pseudocolumn_sql
- columnposition_sql
- columndef_sql
- columnconstraint_sql
- computedcolumnconstraint_sql
- autoincrementcolumnconstraint_sql
- compresscolumnconstraint_sql
- generatedasidentitycolumnconstraint_sql
- generatedasrowcolumnconstraint_sql
- periodforsystemtimeconstraint_sql
- notnullcolumnconstraint_sql
- primarykeycolumnconstraint_sql
- uniquecolumnconstraint_sql
- inoutcolumnconstraint_sql
- createable_sql
- sequenceproperties_sql
- triggerproperties_sql
- triggerreferencing_sql
- triggerevent_sql
- clone_sql
- describe_sql
- heredoc_sql
- prepend_ctes
- with_sql
- cte_sql
- tablealias_sql
- bitstring_sql
- hexstring_sql
- bytestring_sql
- unicodestring_sql
- rawstring_sql
- datatypeparam_sql
- datatype_param_bound_limiter
- directory_sql
- drop_sql
- set_operation
- set_operations
- fetch_sql
- limitoptions_sql
- filter_sql
- per_sql
- hint_sql
- indexparameters_sql
- index_sql
- dynamicidentifier_sql
- identifier_sql
- hex_sql
- lowerhex_sql
- inputoutputformat_sql
- national_sql
- partition_sql
- properties_sql
- root_properties
- properties
- with_properties
- locate_properties
- property_name
- property_sql
- uuidproperty_sql
- likeproperty_sql
- fallbackproperty_sql
- journalproperty_sql
- freespaceproperty_sql
- checksumproperty_sql
- mergeblockratioproperty_sql
- moduleproperty_sql
- datablocksizeproperty_sql
- blockcompressionproperty_sql
- isolatedloadingproperty_sql
- partitionboundspec_sql
- partitionedofproperty_sql
- lockingproperty_sql
- lockingstatement_sql
- withdataproperty_sql
- withsystemversioningproperty_sql
- insert_sql
- introducer_sql
- kill_sql
- pseudotype_sql
- objectidentifier_sql
- onconflict_sql
- returning_sql
- rowformatdelimitedproperty_sql
- withtablehint_sql
- indextablehint_sql
- historicaldata_sql
- table_parts
- table_sql
- tablefromrows_sql
- tablesample_sql
- pivot_sql
- version_sql
- tuple_sql
- update_sql
- values_sql
- var_sql
- into_sql
- from_sql
- groupingsets_sql
- rollup_sql
- rollupindex_sql
- rollupproperty_sql
- cube_sql
- group_sql
- having_sql
- connectto_sql
- disconnect_sql
- connect_sql
- prior_sql
- join_sql
- nearest_sql
- lambda_sql
- lateral_op
- lateral_sql
- limit_sql
- offset_sql
- setitem_sql
- set_sql
- queryband_sql
- pragma_sql
- lock_sql
- literal_sql
- escape_str
- loaddata_sql
- null_sql
- boolean_sql
- booland_sql
- boolor_sql
- order_sql
- withfill_sql
- cluster_sql
- clusterproperty_sql
- distribute_sql
- sort_sql
- ordered_sql
- matchrecognizemeasure_sql
- matchrecognize_sql
- query_modifiers
- options_modifier
- forclause_sql
- queryoption_sql
- after_limit_modifiers
- select_sql
- schema_sql
- schema_columns_sql
- star_sql
- parameter_sql
- sessionparameter_sql
- placeholder_sql
- subquery_sql
- qualify_sql
- unnest_sql
- prewhere_sql
- where_sql
- window_sql
- partition_by_sql
- partitionbyexcluding_sql
- windowspec_sql
- withingroup_sql
- between_sql
- bracket_offset_expressions
- all_sql
- any_sql
- exists_sql
- case_sql
- constraint_sql
- nextvaluefor_sql
- trim_sql
- convert_concat_args
- concat_sql
- concatws_sql
- check_sql
- foreignkey_sql
- primarykey_sql
- timeserieskey_sql
- if_sql
- matchagainst_sql
- jsonkeyvalue_sql
- jsonpath_sql
- json_path_part
- formatjson_sql
- formatphrase_sql
- teradatatitle_sql
- jsonarray_sql
- jsonarrayagg_sql
- jsoncolumndef_sql
- jsonschema_sql
- jsontable_sql
- openjsoncolumndef_sql
- openjson_sql
- in_sql
- in_unnest_op
- return_sql
- reference_sql
- anonymous_sql
- paren_sql
- neg_sql
- not_sql
- alias_sql
- pivotalias_sql
- aliases_sql
- atindex_sql
- attimezone_sql
- fromtimezone_sql
- fromiso8601date_sql
- fromiso8601timestamp_sql
- fromiso8601timestampnanos_sql
- add_sql
- and_sql
- or_sql
- xor_sql
- connector_sql
- bitwiseand_sql
- bitwiseleftshift_sql
- bitwisenot_sql
- bitwiseor_sql
- bitwiserightshift_sql
- bitwisexor_sql
- cast_sql
- strtotime_sql
- strtodate_sql
- parsedatetime_sql
- currentdate_sql
- collate_sql
- command_sql
- comment_sql
- mergetreettlaction_sql
- mergetreettl_sql
- commit_sql
- rollback_sql
- altercolumn_sql
- modifycolumn_sql
- alterindex_sql
- alterdiststyle_sql
- altersortkey_sql
- alterrename_sql
- renamecolumn_sql
- alterset_sql
- alter_sql
- altersession_sql
- add_column_sql
- droppartition_sql
- dropprimarykey_sql
- addconstraint_sql
- replacecolumns_sql
- addpartition_sql
- distinct_sql
- ignorenulls_sql
- respectnulls_sql
- havingmax_sql
- intdiv_sql
- dpipe_sql
- nullif_zero_divisor
- div_sql
- safedivide_sql
- overlaps_sql
- distance_sql
- distancend_sql
- dot_sql
- eq_sql
- propertyeq_sql
- escape_sql
- glob_sql
- gt_sql
- gte_sql
- is_sql
- like_sql
- ilike_sql
- match_sql
- similarto_sql
- lt_sql
- lte_sql
- mod_sql
- mul_sql
- neq_sql
- nullsafeeq_sql
- nullsafeneq_sql
- sub_sql
- trycast_sql
- jsoncast_sql
- try_sql
- log_sql
- use_sql
- binary
- ceil_floor
- function_fallback_sql
- function_name
- func
- format_args
- too_wide
- format_time
- expressions
- op_expressions
- naked_property
- tag_sql
- token_sql
- userdefinedfunction_sql
- macrooverloads_sql
- macrooverload_sql
- joinhint_sql
- kwarg_sql
- when_sql
- whens_sql
- merge_sql
- tochar_sql
- tonumber_sql
- dictproperty_sql
- dictrange_sql
- dictsubproperty_sql
- aggregatekeyproperty_sql
- duplicatekeyproperty_sql
- uniquekeyproperty_sql
- distributedbyproperty_sql
- oncluster_sql
- clusteredbyproperty_sql
- anyvalue_sql
- querytransform_sql
- indexconstraintoption_sql
- checkcolumnconstraint_sql
- indexcolumnconstraint_sql
- nvl2_sql
- nthvalue_sql
- comprehension_sql
- columnprefix_sql
- opclass_sql
- predict_sql
- generateembedding_sql
- generatetext_sql
- generatetable_sql
- generatebool_sql
- generateint_sql
- generatedouble_sql
- mltranslate_sql
- mlforecast_sql
- aiforecast_sql
- featuresattime_sql
- vectorsearch_sql
- forin_sql
- refresh_sql
- toarray_sql
- tsordstotime_sql
- tsordstotimestamp_sql
- tsordstodatetime_sql
- tsordstodate_sql
- unixdate_sql
- lastday_sql
- dateadd_sql
- arrayinsert_sql
- arrayany_sql
- partitionrange_sql
- truncatetable_sql
- convert_sql
- copyparameter_sql
- credentials_sql
- copy_sql
- semicolon_sql
- datadeletionproperty_sql
- maskingpolicycolumnconstraint_sql
- gapfill_sql
- scope_resolution
- scoperesolution_sql
- parsejson_sql
- rand_sql
- changes_sql
- pad_sql
- summarize_sql
- explodinggenerateseries_sql
- converttimezone_sql
- json_sql
- jsonvalue_sql
- skipjsoncolumn_sql
- conditionalinsert_sql
- multitableinserts_sql
- oncondition_sql
- jsonextractquote_sql
- jsonexists_sql
- min_sql
- max_sql
- arrayagg_sql
- timeslice_sql
- slice_sql
- apply_sql
- grant_sql
- revoke_sql
- grantprivilege_sql
- grantprincipal_sql
- columns_sql
- overlay_sql
- todouble_sql
- string_sql
- median_sql
- overflowtruncatebehavior_sql
- unixseconds_sql
- arraysort_sql
- arraysize_sql
- attach_sql
- detach_sql
- attachoption_sql
- watermarkcolumnconstraint_sql
- encodeproperty_sql
- includeproperty_sql
- xmlelement_sql
- xmlkeyvalueoption_sql
- partitionbyrangeproperty_sql
- partitionbyrangepropertydynamic_sql
- unpivotcolumns_sql
- analyzesample_sql
- analyzestatistics_sql
- analyzehistogram_sql
- analyzedelete_sql
- analyzelistchainedrows_sql
- analyzevalidate_sql
- analyze_sql
- xmltable_sql
- xmlnamespace_sql
- export_sql
- declare_sql
- declareitem_sql
- recursivewithsearch_sql
- parameterizedagg_sql
- anonymousaggfunc_sql
- combinedaggfunc_sql
- combinedparameterizedagg_sql
- show_sql
- install_sql
- liststage_sql
- get_put_sql
- translatecharacters_sql
- decodecase_sql
- semanticview_sql
- getextract_sql
- datefromunixdate_sql
- space_sql
- buildproperty_sql
- refreshtriggerproperty_sql
- modelattribute_sql
- directorystage_sql
- uuid_sql
- initcap_sql
- localtime_sql
- localtimestamp_sql
- weekstart_name
- weekstart_sql
- chr_sql
- weightstring_sql
- block_sql
- functionspecification_sql
- storedprocedure_sql
- ifblock_sql
- casestatement_sql
- whileblock_sql
- loopblock_sql
- repeatblock_sql
- leave_sql
- iterate_sql
- execute_sql
- executesql_sql
- altermodifysqlsecurity_sql
- usingproperty_sql
- renameindex_sql