diff options
Diffstat (limited to '')
-rw-r--r-- | sqlglot/generator.py | 93 |
1 files changed, 59 insertions, 34 deletions
diff --git a/sqlglot/generator.py b/sqlglot/generator.py index f1ec398..97cbe15 100644 --- a/sqlglot/generator.py +++ b/sqlglot/generator.py @@ -44,6 +44,8 @@ class Generator: Default: "upper" alias_post_tablesample (bool): if the table alias comes after tablesample Default: False + identifiers_can_start_with_digit (bool): if an unquoted identifier can start with digit + Default: False unsupported_level (ErrorLevel): determines the generator's behavior when it encounters unsupported expressions. Default ErrorLevel.WARN. null_ordering (str): Indicates the default null ordering method to use if not explicitly set. @@ -188,6 +190,8 @@ class Generator: exp.Cluster: exp.Properties.Location.POST_SCHEMA, exp.DataBlocksizeProperty: exp.Properties.Location.POST_NAME, exp.DefinerProperty: exp.Properties.Location.POST_CREATE, + exp.DictRange: exp.Properties.Location.POST_SCHEMA, + exp.DictProperty: exp.Properties.Location.POST_SCHEMA, exp.DistKeyProperty: exp.Properties.Location.POST_SCHEMA, exp.DistStyleProperty: exp.Properties.Location.POST_SCHEMA, exp.EngineProperty: exp.Properties.Location.POST_SCHEMA, @@ -233,6 +237,7 @@ class Generator: JOIN_HINTS = True TABLE_HINTS = True + IS_BOOL = True RESERVED_KEYWORDS: t.Set[str] = set() WITH_SEPARATED_COMMENTS = (exp.Select, exp.From, exp.Where, exp.With) @@ -264,6 +269,7 @@ class Generator: "index_offset", "unnest_column_only", "alias_post_tablesample", + "identifiers_can_start_with_digit", "normalize_functions", "unsupported_level", "unsupported_messages", @@ -304,6 +310,7 @@ class Generator: index_offset=0, unnest_column_only=False, alias_post_tablesample=False, + identifiers_can_start_with_digit=False, normalize_functions="upper", unsupported_level=ErrorLevel.WARN, null_ordering=None, @@ -337,6 +344,7 @@ class Generator: self.index_offset = index_offset self.unnest_column_only = unnest_column_only self.alias_post_tablesample = alias_post_tablesample + self.identifiers_can_start_with_digit = identifiers_can_start_with_digit self.normalize_functions = normalize_functions self.unsupported_level = unsupported_level self.unsupported_messages = [] @@ -634,35 +642,31 @@ class Generator: this = f" {this}" if this else "" return f"UNIQUE{this}" + def createable_sql( + self, expression: exp.Create, locations: dict[exp.Properties.Location, list[exp.Property]] + ) -> str: + return self.sql(expression, "this") + def create_sql(self, expression: exp.Create) -> str: kind = self.sql(expression, "kind").upper() properties = expression.args.get("properties") - properties_exp = expression.copy() properties_locs = self.locate_properties(properties) if properties else {} + + this = self.createable_sql(expression, properties_locs) + + properties_sql = "" if properties_locs.get(exp.Properties.Location.POST_SCHEMA) or properties_locs.get( exp.Properties.Location.POST_WITH ): - properties_exp.set( - "properties", + properties_sql = self.sql( exp.Properties( expressions=[ *properties_locs[exp.Properties.Location.POST_SCHEMA], *properties_locs[exp.Properties.Location.POST_WITH], ] - ), + ) ) - if kind == "TABLE" and properties_locs.get(exp.Properties.Location.POST_NAME): - this_name = self.sql(expression.this, "this") - this_properties = self.properties( - exp.Properties(expressions=properties_locs[exp.Properties.Location.POST_NAME]), - wrapped=False, - ) - this_schema = f"({self.expressions(expression.this)})" - this = f"{this_name}, {this_properties} {this_schema}" - properties_sql = "" - else: - this = self.sql(expression, "this") - properties_sql = self.sql(properties_exp, "properties") + begin = " BEGIN" if expression.args.get("begin") else "" expression_sql = self.sql(expression, "expression") if expression_sql: @@ -894,6 +898,7 @@ class Generator: expression.quoted or should_identify(text, self.identify) or lower in self.RESERVED_KEYWORDS + or (not self.identifiers_can_start_with_digit and text[:1].isdigit()) ): text = f"{self.identifier_start}{text}{self.identifier_end}" return text @@ -1082,7 +1087,7 @@ class Generator: def lockingproperty_sql(self, expression: exp.LockingProperty) -> str: kind = expression.args.get("kind") - this: str = f" {this}" if expression.this else "" + this = f" {self.sql(expression, 'this')}" if expression.this else "" for_or_in = expression.args.get("for_or_in") lock_type = expression.args.get("lock_type") override = " OVERRIDE" if expression.args.get("override") else "" @@ -1313,7 +1318,7 @@ class Generator: op_sql = " ".join( op for op in ( - "NATURAL" if expression.args.get("natural") else None, + expression.method, "GLOBAL" if expression.args.get("global") else None, expression.side, expression.kind, @@ -1573,9 +1578,12 @@ class Generator: def schema_sql(self, expression: exp.Schema) -> str: this = self.sql(expression, "this") this = f"{this} " if this else "" - sql = f"({self.sep('')}{self.expressions(expression)}{self.seg(')', sep='')}" + sql = self.schema_columns_sql(expression) return f"{this}{sql}" + def schema_columns_sql(self, expression: exp.Schema) -> str: + return f"({self.sep('')}{self.expressions(expression)}{self.seg(')', sep='')}" + def star_sql(self, expression: exp.Star) -> str: except_ = self.expressions(expression, key="except", flat=True) except_ = f"{self.seg(self.STAR_MAPPING['except'])} ({except_})" if except_ else "" @@ -1643,32 +1651,26 @@ class Generator: def window_sql(self, expression: exp.Window) -> str: this = self.sql(expression, "this") - partition = self.partition_by_sql(expression) - order = expression.args.get("order") - order_sql = self.order_sql(order, flat=True) if order else "" - - partition_sql = partition + " " if partition and order else partition - - spec = expression.args.get("spec") - spec_sql = " " + self.windowspec_sql(spec) if spec else "" - + order = self.order_sql(order, flat=True) if order else "" + spec = self.sql(expression, "spec") alias = self.sql(expression, "alias") over = self.sql(expression, "over") or "OVER" + this = f"{this} {'AS' if expression.arg_key == 'windows' else over}" first = expression.args.get("first") - if first is not None: - first = " FIRST " if first else " LAST " - first = first or "" + if first is None: + first = "" + else: + first = "FIRST" if first else "LAST" if not partition and not order and not spec and alias: return f"{this} {alias}" - window_args = alias + first + partition_sql + order_sql + spec_sql - - return f"{this} ({window_args.strip()})" + args = " ".join(arg for arg in (alias, first, partition, order, spec) if arg) + return f"{this} ({args})" def partition_by_sql(self, expression: exp.Window | exp.MatchRecognize) -> str: partition = self.expressions(expression, key="partition_by", flat=True) @@ -2125,6 +2127,10 @@ class Generator: return self.binary(expression, "ILIKE ANY") def is_sql(self, expression: exp.Is) -> str: + if not self.IS_BOOL and isinstance(expression.expression, exp.Boolean): + return self.sql( + expression.this if expression.expression.this else exp.not_(expression.this) + ) return self.binary(expression, "IS") def like_sql(self, expression: exp.Like) -> str: @@ -2322,6 +2328,25 @@ class Generator: return self.sql(exp.cast(expression.this, "text")) + def dictproperty_sql(self, expression: exp.DictProperty) -> str: + this = self.sql(expression, "this") + kind = self.sql(expression, "kind") + settings_sql = self.expressions(expression, key="settings", sep=" ") + args = f"({self.sep('')}{settings_sql}{self.seg(')', sep='')}" if settings_sql else "()" + return f"{this}({kind}{args})" + + def dictrange_sql(self, expression: exp.DictRange) -> str: + this = self.sql(expression, "this") + max = self.sql(expression, "max") + min = self.sql(expression, "min") + return f"{this}(MIN {min} MAX {max})" + + def dictsubproperty_sql(self, expression: exp.DictSubProperty) -> str: + return f"{self.sql(expression, 'this')} {self.sql(expression, 'value')}" + + def oncluster_sql(self, expression: exp.OnCluster) -> str: + return "" + def cached_generator( cache: t.Optional[t.Dict[int, str]] = None |