summaryrefslogtreecommitdiffstats
path: root/sqlglot/generator.py
diff options
context:
space:
mode:
Diffstat (limited to 'sqlglot/generator.py')
-rw-r--r--sqlglot/generator.py93
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