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.optimizer.scope import find_all_in_scope 34from sqlglot.transforms import unqualify_columns 35 36DATE_ADD_OR_SUB = t.Union[exp.DateAdd, exp.TimestampAdd, exp.DateSub] 37 38 39def _sha2_digest_sql(self: PrestoGenerator, expression: exp.SHA2Digest) -> str: 40 length = expression.text("length") or "256" 41 if length not in ("256", "512"): 42 self.unsupported(f"SHA{length} is not supported in Presto") 43 44 this = expression.this 45 if this.is_type(*exp.DataType.TEXT_TYPES): 46 # the native digest takes VARBINARY, so a text-typed argument needs encoding 47 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 48 49 return self.func(f"SHA{length}", this) 50 51 52def _initcap_sql(self: PrestoGenerator, expression: exp.Initcap) -> str: 53 delimiters = expression.expression 54 if delimiters and not ( 55 delimiters.is_string and delimiters.this == self.dialect.INITCAP_DEFAULT_DELIMITER_CHARS 56 ): 57 self.unsupported("INITCAP does not support custom delimiters") 58 59 regex = r"(\w)(\w*)" 60 return f"REGEXP_REPLACE({self.sql(expression, 'this')}, '{regex}', x -> UPPER(x[1]) || LOWER(x[2]))" 61 62 63def _array_sort_sql(self: PrestoGenerator, expression: exp.ArraySort) -> str: 64 if expression.expression: 65 return self.func("ARRAY_SORT", expression.this, expression.expression) 66 67 # ARRAY_SORT puts NULLs last, so reversing it sorts descending with NULLs first 68 asc, nulls_first = array_sort_order(expression) or (True, True) 69 if nulls_first == asc: 70 self.unsupported( 71 "ARRAY_SORT can't sort ascending with NULLs first or descending with NULLs last" 72 ) 73 sort = self.func("ARRAY_SORT", expression.this) 74 return sort if asc else self.func("REVERSE", sort) 75 76 77def _schema_sql(self: PrestoGenerator, expression: exp.Schema) -> str: 78 if isinstance(expression.parent, exp.PartitionedByProperty): 79 # Any columns in the ARRAY[] string literals should not be quoted 80 expression.transform(lambda n: n.name if isinstance(n, exp.Identifier) else n, copy=False) 81 82 partition_exprs = [ 83 self.sql(c) if isinstance(c, (exp.Func, exp.Property)) else self.sql(c, "this") 84 for c in expression.expressions 85 ] 86 return self.sql(exp.Array(expressions=[exp.Literal.string(c) for c in partition_exprs])) 87 88 if expression.parent: 89 for schema in expression.parent.find_all(exp.Schema): 90 if schema is expression: 91 continue 92 93 column_defs = schema.find_all(exp.ColumnDef) 94 if column_defs and isinstance(schema.parent, exp.Property): 95 expression.expressions.extend(column_defs) 96 97 return self.schema_sql(expression) 98 99 100def _quantile_sql(self: PrestoGenerator, expression: exp.Quantile) -> str: 101 self.unsupported("Presto does not support exact quantiles") 102 return self.func("APPROX_PERCENTILE", expression.this, expression.args.get("quantile")) 103 104 105def _str_to_time_sql( 106 self: PrestoGenerator, expression: exp.StrToDate | exp.StrToTime | exp.TsOrDsToDate 107) -> str: 108 return self.func("DATE_PARSE", expression.this, self.format_time(expression)) 109 110 111def _ts_or_ds_to_date_sql(self: PrestoGenerator, expression: exp.TsOrDsToDate) -> str: 112 time_format = self.format_time(expression) 113 dialect_class = type(self.dialect) 114 if time_format and time_format not in (dialect_class.TIME_FORMAT, dialect_class.DATE_FORMAT): 115 return self.sql(exp.cast(_str_to_time_sql(self, expression), exp.DType.DATE)) 116 return self.sql(exp.cast(exp.cast(expression.this, exp.DType.TIMESTAMP), exp.DType.DATE)) 117 118 119def _ts_or_ds_add_sql(self: PrestoGenerator, expression: exp.TsOrDsAdd) -> str: 120 expression = ts_or_ds_add_cast(expression) 121 unit = unit_to_str(expression) 122 return self.func("DATE_ADD", unit, expression.expression, expression.this) 123 124 125def _ts_or_ds_diff_sql(self: PrestoGenerator, expression: exp.TsOrDsDiff) -> str: 126 this = exp.cast(expression.this, exp.DType.TIMESTAMP) 127 expr = exp.cast(expression.expression, exp.DType.TIMESTAMP) 128 unit = unit_to_str(expression) 129 return self.func("DATE_DIFF", unit, expr, this) 130 131 132def _first_last_sql(self: PrestoGenerator, expression: exp.Func) -> str: 133 """ 134 Trino doesn't support FIRST / LAST as functions, but they're valid in the context 135 of MATCH_RECOGNIZE, so we need to preserve them in that case. In all other cases 136 they're converted into an ARBITRARY call. 137 138 Reference: https://trino.io/docs/current/sql/match-recognize.html#logical-navigation-functions 139 """ 140 if isinstance(expression.find_ancestor(exp.MatchRecognize, exp.Select), exp.MatchRecognize): 141 return self.function_fallback_sql(expression) 142 143 return rename_func("ARBITRARY")(self, expression) 144 145 146def _unix_to_time_sql(self: PrestoGenerator, expression: exp.UnixToTime) -> str: 147 scale = expression.args.get("scale") 148 timestamp = self.sql(expression, "this") 149 if scale in (None, exp.UnixToTime.SECONDS): 150 return rename_func("FROM_UNIXTIME")(self, expression) 151 152 return f"FROM_UNIXTIME(CAST({timestamp} AS DOUBLE) / POW(10, {scale}))" 153 154 155def _to_int(self: PrestoGenerator, expression: exp.Expr) -> exp.Expr: 156 if not expression.type: 157 from sqlglot.optimizer.annotate_types import annotate_types 158 159 annotate_types(expression, dialect=self.dialect) 160 if expression.type and expression.type.this not in exp.DataType.INTEGER_TYPES: 161 return exp.cast(expression, to=exp.DType.BIGINT) 162 return expression 163 164 165def _date_delta_sql( 166 name: str, negate_interval: bool = False 167) -> t.Callable[[PrestoGenerator, DATE_ADD_OR_SUB], str]: 168 def _delta_sql(self: PrestoGenerator, expression: DATE_ADD_OR_SUB) -> str: 169 interval = _to_int(self, expression.expression) 170 return self.func( 171 name, 172 unit_to_str(expression), 173 interval * (-1) if negate_interval else interval, 174 expression.this, 175 ) 176 177 return _delta_sql 178 179 180def _date_diff_sql( 181 self: PrestoGenerator, expression: exp.DateDiff | exp.DatetimeDiff | exp.TimestampDiff 182) -> str: 183 # Presto/Trino only expose date_diff(unit, ts1, ts2); it returns ts2 - ts1, so the 184 # operands are emitted as (expression, this) to preserve `this - expression` semantics. 185 this: exp.Expr = expression.this 186 expr: exp.Expr = expression.expression 187 unit = unit_to_str(expression) 188 189 # DATE_DIFF counts complete units between its operands, whereas dialects that set 190 # date_part_boundary count unit boundary crossings, so the operands are truncated 191 # down to the unit to make the two coincide 192 if unit and expression.args.get("date_part_boundary"): 193 raw_unit = expression.args.get("unit") 194 dow = week_unit_to_dow(raw_unit) 195 196 if dow is not None: 197 unit = exp.Literal.string("WEEK") 198 199 # DATE_TRUNC('WEEK', ...) is Monday-based; shifting both operands by the same 200 # delta realigns it to the requested week start without changing the diff 201 shift_days = 1 if dow == 7 else 1 - dow 202 if shift_days: 203 delta = exp.Interval(this=exp.Literal.string(str(shift_days)), unit=exp.var("DAY")) 204 this = exp.Add(this=this, expression=delta) 205 expr = exp.Add(this=expr, expression=delta.copy()) 206 207 if not isinstance(raw_unit, exp.WeekStart) or dow is not None: 208 this = exp.DateTrunc(unit=unit.copy(), this=this) 209 expr = exp.DateTrunc(unit=unit.copy(), this=expr) 210 211 return self.func("DATE_DIFF", unit, expr, this) 212 213 214def _explode_to_unnest_sql(self: PrestoGenerator, expression: exp.Lateral) -> str: 215 explode = expression.this 216 if isinstance(explode, exp.Explode): 217 exploded_type = explode.this.type 218 alias = expression.args.get("alias") 219 220 # This attempts a best-effort transpilation of LATERAL VIEW EXPLODE on a struct array 221 if ( 222 isinstance(alias, exp.TableAlias) 223 and isinstance(exploded_type, exp.DataType) 224 and exploded_type.is_type(exp.DType.ARRAY) 225 and exploded_type.expressions 226 and exploded_type.expressions[0].is_type(exp.DType.STRUCT) 227 ): 228 # When unnesting a ROW in Presto, it produces N columns, so we need to fix the alias 229 alias.set("columns", [c.this.copy() for c in exploded_type.expressions[0].expressions]) 230 elif isinstance(explode, exp.Inline): 231 explode.replace(exp.Explode(this=explode.this.copy())) 232 233 return explode_to_unnest_sql(self, expression) 234 235 236def amend_exploded_column_table(expression: exp.Expr) -> exp.Expr: 237 # We check for expression.type because the columns can be amended only if types were inferred 238 if isinstance(expression, exp.Select) and expression.type: 239 for lateral in expression.args.get("laterals") or []: 240 alias = lateral.args.get("alias") 241 if ( 242 not isinstance(lateral.this, exp.Explode) 243 or not isinstance(alias, exp.TableAlias) 244 or len(alias.columns) != 1 245 ): 246 continue 247 248 new_table = alias.this 249 old_table = alias.columns[0].name.lower() 250 251 # When transpiling a LATERAL VIEW EXPLODE Spark query, the exploded fields may be qualified 252 # with the struct column, resulting in invalid Presto references that need to be amended 253 for column in find_all_in_scope(expression, exp.Column): 254 if column.db.lower() == old_table: 255 column.set("table", column.args["db"].pop()) 256 elif column.table.lower() == old_table: 257 column.set("table", new_table.copy()) 258 elif column.name.lower() == old_table and isinstance(column.parent, exp.Dot): 259 column.parent.replace(exp.column(column.parent.expression, table=new_table)) 260 261 return expression 262 263 264class PrestoGenerator(generator.Generator): 265 SELECT_KINDS: tuple[str, ...] = () 266 SUPPORTS_DECODE_CASE = False 267 SUPPORTS_TEMPORAL_PRECISION = False 268 269 AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS 270 271 INTERVAL_ALLOWS_PLURAL_FORM = False 272 JOIN_HINTS = False 273 CAST_TO_INT_ROUNDS = True 274 TABLE_HINTS = False 275 QUERY_HINTS = False 276 IS_BOOL_ALLOWED = False 277 TZ_TO_WITH_TIME_ZONE = True 278 NVL2_SUPPORTED = False 279 STRUCT_DELIMITER = ("(", ")") 280 LIMIT_ONLY_LITERALS = True 281 SUPPORTS_SINGLE_ARG_CONCAT = False 282 LIKE_PROPERTY_INSIDE_SCHEMA = True 283 MULTI_ARG_DISTINCT = False 284 SUPPORTS_TO_NUMBER = False 285 HEX_FUNC = "TO_HEX" 286 PARSE_JSON_NAME: str | None = "JSON_PARSE" 287 PAD_FILL_PATTERN_IS_REQUIRED = True 288 EXCEPT_INTERSECT_SUPPORT_ALL_CLAUSE = False 289 SUPPORTS_MEDIAN = False 290 ARRAY_SIZE_NAME = "CARDINALITY" 291 292 PROPERTIES_LOCATION = { 293 **generator.Generator.PROPERTIES_LOCATION, 294 exp.LocationProperty: exp.Properties.Location.UNSUPPORTED, 295 exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED, 296 } 297 298 TYPE_MAPPING = { 299 **generator.Generator.TYPE_MAPPING, 300 exp.DType.BINARY: "VARBINARY", 301 exp.DType.BIT: "BOOLEAN", 302 exp.DType.DATETIME: "TIMESTAMP", 303 exp.DType.DATETIME64: "TIMESTAMP", 304 exp.DType.FLOAT: "REAL", 305 exp.DType.HLLSKETCH: "HYPERLOGLOG", 306 exp.DType.INT: "INTEGER", 307 exp.DType.STRUCT: "ROW", 308 exp.DType.TEXT: "VARCHAR", 309 exp.DType.TIMESTAMPTZ: "TIMESTAMP", 310 exp.DType.TIMESTAMPNTZ: "TIMESTAMP", 311 exp.DType.TIMETZ: "TIME", 312 } 313 314 TRANSFORMS = { 315 **generator.Generator.TRANSFORMS, 316 exp.AnyValue: rename_func("ARBITRARY"), 317 exp.ApproxQuantile: lambda self, e: self.func( 318 "APPROX_PERCENTILE", 319 e.this, 320 e.args.get("weight"), 321 e.args.get("quantile"), 322 e.args.get("accuracy"), 323 ), 324 exp.ArgMax: rename_func("MAX_BY"), 325 exp.ArgMin: rename_func("MIN_BY"), 326 exp.Array: transforms.preprocess( 327 [transforms.inherit_struct_field_names], 328 generator=lambda self, e: f"ARRAY[{self.expressions(e, flat=True)}]", 329 ), 330 exp.ArrayAny: rename_func("ANY_MATCH"), 331 exp.ArrayConcat: rename_func("CONCAT"), 332 exp.ArrayContains: rename_func("CONTAINS"), 333 exp.ArraySort: _array_sort_sql, 334 exp.ArrayToString: rename_func("ARRAY_JOIN"), 335 exp.ArrayUniqueAgg: rename_func("SET_AGG"), 336 exp.ArraySlice: array_slice_to_slice_sql, 337 exp.AtTimeZone: rename_func("AT_TIMEZONE"), 338 exp.BitwiseAnd: lambda self, e: self.func("BITWISE_AND", e.this, e.expression), 339 exp.BitwiseLeftShift: rename_func("BITWISE_LEFT_SHIFT"), 340 exp.BitwiseNot: lambda self, e: self.func("BITWISE_NOT", e.this), 341 exp.BitwiseOr: lambda self, e: self.func("BITWISE_OR", e.this, e.expression), 342 exp.BitwiseRightShift: rename_func("BITWISE_RIGHT_SHIFT"), 343 exp.BitwiseXor: lambda self, e: self.func("BITWISE_XOR", e.this, e.expression), 344 exp.Cast: transforms.preprocess([transforms.epoch_cast_to_ts]), 345 exp.CurrentTime: lambda *_: "CURRENT_TIME", 346 exp.CurrentTimestamp: lambda *_: "CURRENT_TIMESTAMP", 347 exp.CurrentUser: lambda *_: "CURRENT_USER", 348 exp.DateAdd: _date_delta_sql("DATE_ADD"), 349 exp.DateDiff: _date_diff_sql, 350 exp.DatetimeDiff: _date_diff_sql, 351 exp.TimestampDiff: _date_diff_sql, 352 exp.DateStrToDate: datestrtodate_sql, 353 exp.DateToDi: lambda self, e: ( 354 f"CAST(DATE_FORMAT({self.sql(e, 'this')}, {type(self.dialect).DATEINT_FORMAT}) AS INT)" 355 ), 356 exp.DateSub: _date_delta_sql("DATE_ADD", negate_interval=True), 357 exp.DayOfWeek: lambda self, e: f"(({self.func('DAY_OF_WEEK', e.this)} % 7) + 1)", 358 exp.DayOfWeekIso: rename_func("DAY_OF_WEEK"), 359 exp.Decode: lambda self, e: encode_decode_sql(self, e, "FROM_UTF8"), 360 exp.DiToDate: lambda self, e: ( 361 f"CAST(DATE_PARSE(CAST({self.sql(e, 'this')} AS VARCHAR), {type(self.dialect).DATEINT_FORMAT}) AS DATE)" 362 ), 363 exp.Encode: lambda self, e: encode_decode_sql(self, e, "TO_UTF8"), 364 exp.FileFormatProperty: lambda self, e: f"format={self.sql(exp.Literal.string(e.name))}", 365 exp.First: _first_last_sql, 366 exp.FromISO8601Date: rename_func("FROM_ISO8601_DATE"), 367 exp.FromISO8601Timestamp: rename_func("FROM_ISO8601_TIMESTAMP"), 368 exp.FromTimeZone: lambda self, e: ( 369 f"WITH_TIMEZONE({self.sql(e, 'this')}, {self.sql(e, 'zone')}) AT TIME ZONE 'UTC'" 370 ), 371 exp.GenerateSeries: sequence_sql, 372 exp.GenerateDateArray: sequence_sql, 373 exp.If: if_sql(), 374 exp.ILike: no_ilike_sql, 375 exp.Initcap: _initcap_sql, 376 exp.Last: _first_last_sql, 377 exp.LastDay: lambda self, e: self.func("LAST_DAY_OF_MONTH", e.this), 378 exp.Lateral: _explode_to_unnest_sql, 379 exp.Left: left_to_substring_sql, 380 exp.Levenshtein: unsupported_args("ins_cost", "del_cost", "sub_cost", "max_dist")( 381 rename_func("LEVENSHTEIN_DISTANCE") 382 ), 383 exp.LogicalAnd: rename_func("BOOL_AND"), 384 exp.LogicalOr: rename_func("BOOL_OR"), 385 exp.Pivot: no_pivot_sql, 386 exp.Quantile: _quantile_sql, 387 exp.RegexpExtract: regexp_extract_sql, 388 exp.RegexpExtractAll: regexp_extract_sql, 389 exp.Right: right_to_substring_sql, 390 exp.Schema: _schema_sql, 391 exp.SchemaCommentProperty: lambda self, e: self.naked_property(e), 392 exp.Select: transforms.preprocess( 393 [ 394 transforms.eliminate_window_clause, 395 transforms.eliminate_qualify, 396 transforms.eliminate_distinct_on, 397 transforms.explode_projection_to_unnest(1, unnest_map=True), 398 transforms.eliminate_semi_and_anti_joins, 399 amend_exploded_column_table, 400 ] 401 ), 402 exp.SqlSecurityProperty: lambda self, e: f"SECURITY {self.sql(e.this)}", 403 exp.StrPosition: lambda self, e: strposition_sql(self, e, supports_occurrence=True), 404 exp.StrToDate: lambda self, e: f"CAST({_str_to_time_sql(self, e)} AS DATE)", 405 exp.StrToMap: rename_func("SPLIT_TO_MAP"), 406 exp.StrToTime: _str_to_time_sql, 407 exp.StructExtract: struct_extract_sql, 408 exp.Table: transforms.preprocess([transforms.unnest_generate_series]), 409 exp.Timestamp: no_timestamp_sql, 410 exp.TimestampAdd: _date_delta_sql("DATE_ADD"), 411 exp.TimestampTrunc: timestamptrunc_sql(), 412 exp.TimeStrToDate: timestrtotime_sql, 413 exp.TimeStrToTime: timestrtotime_sql, 414 exp.TimeStrToUnix: lambda self, e: self.func( 415 "TO_UNIXTIME", self.func("DATE_PARSE", e.this, type(self.dialect).TIME_FORMAT) 416 ), 417 exp.TimeToStr: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 418 exp.TimeToUnix: rename_func("TO_UNIXTIME"), 419 exp.ToChar: lambda self, e: self.func("DATE_FORMAT", e.this, self.format_time(e)), 420 exp.TryCast: transforms.preprocess([transforms.epoch_cast_to_ts]), 421 exp.TsOrDiToDi: lambda self, e: ( 422 f"CAST(SUBSTR(REPLACE(CAST({self.sql(e, 'this')} AS VARCHAR), '-', ''), 1, 8) AS INT)" 423 ), 424 exp.TsOrDsAdd: _ts_or_ds_add_sql, 425 exp.TsOrDsDiff: _ts_or_ds_diff_sql, 426 exp.TsOrDsToDate: _ts_or_ds_to_date_sql, 427 exp.Unhex: rename_func("FROM_HEX"), 428 exp.UnixToStr: lambda self, e: ( 429 f"DATE_FORMAT(FROM_UNIXTIME({self.sql(e, 'this')}), {self.format_time(e)})" 430 ), 431 exp.UnixToTime: _unix_to_time_sql, 432 exp.UnixToTimeStr: lambda self, e: f"CAST(FROM_UNIXTIME({self.sql(e, 'this')}) AS VARCHAR)", 433 exp.VariancePop: rename_func("VAR_POP"), 434 exp.With: transforms.preprocess([transforms.add_recursive_cte_column_names]), 435 exp.WithinGroup: transforms.preprocess([transforms.remove_within_group_for_percentiles]), 436 # Note: Presto's TRUNCATE always returns DOUBLE, even with decimals=0, whereas 437 # most dialects return INT (SQLite also returns REAL, see sqlite.py). This creates 438 # a bidirectional transpilation gap: Presto→Other may change float division to int 439 # division, and vice versa. Modeling precisely would require exp.FloatTrunc or 440 # similar, deemed overengineering for this subtle semantic difference. 441 exp.Trunc: rename_func("TRUNCATE"), 442 exp.Xor: bool_xor_sql, 443 exp.MD5Digest: rename_func("MD5"), 444 exp.SHA: rename_func("SHA1"), 445 exp.SHA1Digest: rename_func("SHA1"), 446 exp.SHA2Digest: _sha2_digest_sql, 447 exp.Substring: rename_func("SUBSTR"), 448 } 449 450 RESERVED_KEYWORDS = { 451 "alter", 452 "and", 453 "as", 454 "between", 455 "by", 456 "case", 457 "cast", 458 "constraint", 459 "create", 460 "cross", 461 "current_time", 462 "current_timestamp", 463 "deallocate", 464 "delete", 465 "describe", 466 "distinct", 467 "drop", 468 "else", 469 "end", 470 "escape", 471 "except", 472 "execute", 473 "exists", 474 "extract", 475 "false", 476 "for", 477 "from", 478 "full", 479 "group", 480 "having", 481 "in", 482 "inner", 483 "insert", 484 "intersect", 485 "into", 486 "is", 487 "join", 488 "left", 489 "like", 490 "natural", 491 "not", 492 "null", 493 "on", 494 "or", 495 "order", 496 "outer", 497 "prepare", 498 "right", 499 "select", 500 "table", 501 "then", 502 "true", 503 "union", 504 "using", 505 "values", 506 "when", 507 "where", 508 "with", 509 } 510 511 def datatype_sql(self, expression: exp.DataType) -> str: 512 if not self.SUPPORTS_TEMPORAL_PRECISION and expression.this in exp.DataType.TEMPORAL_TYPES: 513 if expression.expressions and expression.expressions[0].name != "3": 514 self.unsupported("Presto only supports millisecond precision for temporal types") 515 expression.set("expressions", None) 516 return super().datatype_sql(expression) 517 518 def extract_sql(self, expression: exp.Extract) -> str: 519 date_part = expression.name 520 521 if not date_part.startswith("EPOCH"): 522 return super().extract_sql(expression) 523 524 if date_part == "EPOCH_MILLISECOND": 525 scale = 10**3 526 elif date_part == "EPOCH_MICROSECOND": 527 scale = 10**6 528 elif date_part == "EPOCH_NANOSECOND": 529 scale = 10**9 530 else: 531 scale = None 532 533 value = expression.expression 534 535 ts = exp.cast(value, to=exp.DType.TIMESTAMP.into_expr()) 536 to_unix: exp.Expr = exp.TimeToUnix(this=ts) 537 538 if scale: 539 to_unix = exp.Mul(this=to_unix, expression=exp.Literal.number(scale)) 540 541 return self.sql(to_unix) 542 543 def jsonformat_sql(self, expression: exp.JSONFormat) -> str: 544 this = expression.this 545 is_json = expression.args.get("is_json") 546 547 if this and not (is_json or this.type): 548 from sqlglot.optimizer.annotate_types import annotate_types 549 550 this = annotate_types(this, dialect=self.dialect) 551 552 if not (is_json or this.is_type(exp.DType.JSON)): 553 this.replace(exp.cast(this, exp.DType.JSON)) 554 555 return self.function_fallback_sql(expression) 556 557 def md5_sql(self, expression: exp.MD5) -> str: 558 this = expression.this 559 560 if not this.type: 561 from sqlglot.optimizer.annotate_types import annotate_types 562 563 this = annotate_types(this, dialect=self.dialect) 564 565 if this.is_type(*exp.DataType.TEXT_TYPES): 566 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 567 568 return self.func("LOWER", self.func("TO_HEX", self.func("MD5", self.sql(this)))) 569 570 def sha2_sql(self, expression: exp.SHA2) -> str: 571 length = expression.text("length") or "256" 572 if length not in ("256", "512"): 573 self.unsupported(f"SHA{length} is not supported in Presto") 574 575 this = expression.this 576 577 if this.is_type(*exp.DataType.TEXT_TYPES): 578 this = exp.Encode(this=this, charset=exp.Literal.string("utf-8")) 579 580 return self.func("LOWER", self.func("TO_HEX", self.func(f"SHA{length}", self.sql(this)))) 581 582 def strtounix_sql(self, expression: exp.StrToUnix) -> str: 583 # Since `TO_UNIXTIME` requires a `TIMESTAMP`, we need to parse the argument into one. 584 # To do this, we first try to `DATE_PARSE` it, but since this can fail when there's a 585 # timezone involved, we wrap it in a `TRY` call and use `PARSE_DATETIME` as a fallback, 586 # which seems to be using the same time mapping as Hive, as per: 587 # https://joda-time.sourceforge.net/apidocs/org/joda/time/format/DateTimeFormat.html 588 this = expression.this 589 value_as_text = exp.cast(this, exp.DType.TEXT) 590 value_as_timestamp = exp.cast(this, exp.DType.TIMESTAMP) if this.is_string else this 591 592 parse_without_tz = self.func("DATE_PARSE", value_as_text, self.format_time(expression)) 593 594 formatted_value = self.func("DATE_FORMAT", value_as_timestamp, self.format_time(expression)) 595 parse_with_tz = self.func( 596 "PARSE_DATETIME", 597 formatted_value, 598 self.format_time(expression, Hive.INVERSE_TIME_MAPPING, Hive.INVERSE_TIME_TRIE), 599 ) 600 coalesced = self.func("COALESCE", self.func("TRY", parse_without_tz), parse_with_tz) 601 return self.func("TO_UNIXTIME", coalesced) 602 603 def bracket_sql(self, expression: exp.Bracket) -> str: 604 if expression.args.get("safe"): 605 return bracket_to_element_at_sql(self, expression) 606 return super().bracket_sql(expression) 607 608 def struct_sql(self, expression: exp.Struct) -> str: 609 if not expression.type: 610 from sqlglot.optimizer.annotate_types import annotate_types 611 612 annotate_types(expression, dialect=self.dialect) 613 614 values: list[str] = [] 615 schema: list[str] = [] 616 unknown_type = False 617 618 for e in expression.expressions: 619 if isinstance(e, exp.PropertyEQ): 620 if e.type and e.type.is_type(exp.DType.UNKNOWN): 621 unknown_type = True 622 else: 623 schema.append(f"{self.sql(e, 'this')} {self.sql(e.type)}") 624 values.append(self.sql(e, "expression")) 625 else: 626 values.append(self.sql(e)) 627 628 size = len(expression.expressions) 629 630 if not size or len(schema) != size: 631 if unknown_type: 632 self.unsupported( 633 "Cannot convert untyped key-value definitions (try annotate_types)." 634 ) 635 return self.func("ROW", *values) 636 return f"CAST(ROW({', '.join(values)}) AS ROW({', '.join(schema)}))" 637 638 def interval_sql(self, expression: exp.Interval) -> str: 639 if expression.this and expression.text("unit").upper().startswith("WEEK"): 640 return f"({expression.this.name} * INTERVAL '7' DAY)" 641 return super().interval_sql(expression) 642 643 def transaction_sql(self, expression: exp.Transaction) -> str: 644 modes = expression.args.get("modes") 645 modes = f" {', '.join(modes)}" if modes else "" 646 return f"START TRANSACTION{modes}" 647 648 def offset_limit_modifiers( 649 self, expression: exp.Expr, fetch: bool, limit: exp.Fetch | exp.Limit | None 650 ) -> list[str]: 651 return [ 652 self.sql(expression, "offset"), 653 self.sql(limit), 654 ] 655 656 def create_sql(self, expression: exp.Create) -> str: 657 """ 658 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 659 so we need to remove them 660 """ 661 kind = expression.args["kind"] 662 schema = expression.this 663 if kind == "VIEW" and schema.expressions: 664 expression.this.set("expressions", None) 665 return super().create_sql(expression) 666 667 def delete_sql(self, expression: exp.Delete) -> str: 668 """ 669 Presto only supports DELETE FROM for a single table without an alias, so we need 670 to remove the unnecessary parts. If the original DELETE statement contains more 671 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 672 """ 673 tables = expression.args.get("tables") or [expression.this] 674 if len(tables) > 1: 675 return super().delete_sql(expression) 676 677 table = tables[0] 678 expression.set("this", table) 679 expression.set("tables", None) 680 681 if isinstance(table, exp.Table): 682 table_alias = table.args.get("alias") 683 if table_alias: 684 table_alias.pop() 685 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 686 687 return super().delete_sql(expression) 688 689 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 690 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 691 692 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 693 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 694 if not expression.args.get("variant_extract") or is_json_extract: 695 return self.func( 696 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 697 ) 698 699 this = self.sql(expression, "this") 700 701 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 702 segments = [] 703 for path_key in expression.expression.expressions[1:]: 704 if not isinstance(path_key, exp.JSONPathKey): 705 # Cannot transpile subscripts, wildcards etc to dot notation 706 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 707 continue 708 key = path_key.this 709 if not exp.SAFE_IDENTIFIER_RE.match(key): 710 key = f'"{key}"' 711 segments.append(f".{key}") 712 713 expr = "".join(segments) 714 715 return f"{this}{expr}" 716 717 def groupconcat_sql(self, expression: exp.GroupConcat) -> str: 718 return self.func( 719 "ARRAY_JOIN", 720 self.func("ARRAY_AGG", expression.this), 721 expression.args.get("separator"), 722 )
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:
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
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 if expression.this and expression.text("unit").upper().startswith("WEEK"): 641 return f"({expression.this.name} * INTERVAL '7' DAY)" 642 return super().interval_sql(expression) 643 644 def transaction_sql(self, expression: exp.Transaction) -> str: 645 modes = expression.args.get("modes") 646 modes = f" {', '.join(modes)}" if modes else "" 647 return f"START TRANSACTION{modes}" 648 649 def offset_limit_modifiers( 650 self, expression: exp.Expr, fetch: bool, limit: exp.Fetch | exp.Limit | None 651 ) -> list[str]: 652 return [ 653 self.sql(expression, "offset"), 654 self.sql(limit), 655 ] 656 657 def create_sql(self, expression: exp.Create) -> str: 658 """ 659 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 660 so we need to remove them 661 """ 662 kind = expression.args["kind"] 663 schema = expression.this 664 if kind == "VIEW" and schema.expressions: 665 expression.this.set("expressions", None) 666 return super().create_sql(expression) 667 668 def delete_sql(self, expression: exp.Delete) -> str: 669 """ 670 Presto only supports DELETE FROM for a single table without an alias, so we need 671 to remove the unnecessary parts. If the original DELETE statement contains more 672 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 673 """ 674 tables = expression.args.get("tables") or [expression.this] 675 if len(tables) > 1: 676 return super().delete_sql(expression) 677 678 table = tables[0] 679 expression.set("this", table) 680 expression.set("tables", None) 681 682 if isinstance(table, exp.Table): 683 table_alias = table.args.get("alias") 684 if table_alias: 685 table_alias.pop() 686 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 687 688 return super().delete_sql(expression) 689 690 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 691 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 692 693 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 694 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 695 if not expression.args.get("variant_extract") or is_json_extract: 696 return self.func( 697 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 698 ) 699 700 this = self.sql(expression, "this") 701 702 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 703 segments = [] 704 for path_key in expression.expression.expressions[1:]: 705 if not isinstance(path_key, exp.JSONPathKey): 706 # Cannot transpile subscripts, wildcards etc to dot notation 707 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 708 continue 709 key = path_key.this 710 if not exp.SAFE_IDENTIFIER_RE.match(key): 711 key = f'"{key}"' 712 segments.append(f".{key}") 713 714 expr = "".join(segments) 715 716 return f"{this}{expr}" 717 718 def groupconcat_sql(self, expression: exp.GroupConcat) -> str: 719 return self.func( 720 "ARRAY_JOIN", 721 self.func("ARRAY_AGG", expression.this), 722 expression.args.get("separator"), 723 )
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.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.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.DistStyleProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <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.IncludeProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <class 'sqlglot.expressions.properties.InputModelProperty'>: <PropertiesLocation.POST_SCHEMA: 'POST_SCHEMA'>, <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.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.POST_SCHEMA: 'POST_SCHEMA'>, <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.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.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.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.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 =
{'into', 'execute', 'outer', 'from', 'describe', 'true', 'select', 'cast', 'where', 'or', 'intersect', 'constraint', 'having', 'create', 'not', 'distinct', 'group', 'current_timestamp', 'null', 'false', 'delete', 'alter', 'using', 'is', 'end', 'and', 'inner', 'order', 'right', 'like', 'on', 'when', 'prepare', 'deallocate', 'full', 'left', 'else', 'current_time', 'escape', 'drop', 'exists', 'table', 'union', 'case', 'as', 'except', 'then', 'values', 'by', 'extract', 'between', 'join', 'insert', 'cross', 'for', 'natural', 'in', 'with'}
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)
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)
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)
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))))
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))))
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)
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)}))"
def
offset_limit_modifiers( self, expression: sqlglot.expressions.core.Expr, fetch: bool, limit: sqlglot.expressions.query.Fetch | sqlglot.expressions.query.Limit | None) -> list[str]:
657 def create_sql(self, expression: exp.Create) -> str: 658 """ 659 Presto doesn't support CREATE VIEW with expressions (ex: `CREATE VIEW x (cola)` then `(cola)` is the expression), 660 so we need to remove them 661 """ 662 kind = expression.args["kind"] 663 schema = expression.this 664 if kind == "VIEW" and schema.expressions: 665 expression.this.set("expressions", None) 666 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
668 def delete_sql(self, expression: exp.Delete) -> str: 669 """ 670 Presto only supports DELETE FROM for a single table without an alias, so we need 671 to remove the unnecessary parts. If the original DELETE statement contains more 672 than one table to be deleted, we can't safely map it 1-1 to a Presto statement. 673 """ 674 tables = expression.args.get("tables") or [expression.this] 675 if len(tables) > 1: 676 return super().delete_sql(expression) 677 678 table = tables[0] 679 expression.set("this", table) 680 expression.set("tables", None) 681 682 if isinstance(table, exp.Table): 683 table_alias = table.args.get("alias") 684 if table_alias: 685 table_alias.pop() 686 expression = t.cast(exp.Delete, expression.transform(unqualify_columns)) 687 688 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.
690 def jsonextract_sql(self, expression: exp.JSONExtract) -> str: 691 is_json_extract = self.dialect.settings.get("variant_extract_is_json_extract", True) 692 693 # Generate JSON_EXTRACT unless the user has configured that a Snowflake / Databricks 694 # VARIANT extract (e.g. col:x.y) should map to dot notation (i.e ROW access) in Presto/Trino 695 if not expression.args.get("variant_extract") or is_json_extract: 696 return self.func( 697 "JSON_EXTRACT", expression.this, expression.expression, *expression.expressions 698 ) 699 700 this = self.sql(expression, "this") 701 702 # Convert the JSONPath extraction `JSON_EXTRACT(col, '$.x.y) to a ROW access col.x.y 703 segments = [] 704 for path_key in expression.expression.expressions[1:]: 705 if not isinstance(path_key, exp.JSONPathKey): 706 # Cannot transpile subscripts, wildcards etc to dot notation 707 self.unsupported(f"Cannot transpile JSONPath segment '{path_key}' to ROW access") 708 continue 709 key = path_key.this 710 if not exp.SAFE_IDENTIFIER_RE.match(key): 711 key = f'"{key}"' 712 segments.append(f".{key}") 713 714 expr = "".join(segments) 715 716 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
- 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
- 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
- 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
- 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
- connect_sql
- prior_sql
- join_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
- 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
- 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
- arrayagg_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