diff options
Diffstat (limited to 'sqlglot/dialects/redshift.py')
-rw-r--r-- | sqlglot/dialects/redshift.py | 58 |
1 files changed, 30 insertions, 28 deletions
diff --git a/sqlglot/dialects/redshift.py b/sqlglot/dialects/redshift.py index 1b7cf31..55e393a 100644 --- a/sqlglot/dialects/redshift.py +++ b/sqlglot/dialects/redshift.py @@ -8,21 +8,21 @@ from sqlglot.helper import seq_get from sqlglot.tokens import TokenType -def _json_sql(self, e) -> str: - return f'{self.sql(e, "this")}."{e.expression.name}"' +def _json_sql(self: Postgres.Generator, expression: exp.JSONExtract | exp.JSONExtractScalar) -> str: + return f'{self.sql(expression, "this")}."{expression.expression.name}"' class Redshift(Postgres): time_format = "'YYYY-MM-DD HH:MI:SS'" time_mapping = { - **Postgres.time_mapping, # type: ignore + **Postgres.time_mapping, "MON": "%b", "HH": "%H", } class Parser(Postgres.Parser): FUNCTIONS = { - **Postgres.Parser.FUNCTIONS, # type: ignore + **Postgres.Parser.FUNCTIONS, "DATEADD": lambda args: exp.DateAdd( this=seq_get(args, 2), expression=seq_get(args, 1), @@ -45,7 +45,7 @@ class Redshift(Postgres): isinstance(this, exp.DataType) and this.this == exp.DataType.Type.VARCHAR and this.expressions - and this.expressions[0] == exp.column("MAX") + and this.expressions[0].this == exp.column("MAX") ): this.set("expressions", [exp.Var(this="MAX")]) @@ -57,9 +57,7 @@ class Redshift(Postgres): STRING_ESCAPES = ["\\"] KEYWORDS = { - **Postgres.Tokenizer.KEYWORDS, # type: ignore - "GEOMETRY": TokenType.GEOMETRY, - "GEOGRAPHY": TokenType.GEOGRAPHY, + **Postgres.Tokenizer.KEYWORDS, "HLLSKETCH": TokenType.HLLSKETCH, "SUPER": TokenType.SUPER, "SYSDATE": TokenType.CURRENT_TIMESTAMP, @@ -76,22 +74,22 @@ class Redshift(Postgres): class Generator(Postgres.Generator): LOCKING_READS_SUPPORTED = False - SINGLE_STRING_INTERVAL = True + RENAME_TABLE_WITH_DB = False TYPE_MAPPING = { - **Postgres.Generator.TYPE_MAPPING, # type: ignore + **Postgres.Generator.TYPE_MAPPING, exp.DataType.Type.BINARY: "VARBYTE", exp.DataType.Type.VARBINARY: "VARBYTE", exp.DataType.Type.INT: "INTEGER", } PROPERTIES_LOCATION = { - **Postgres.Generator.PROPERTIES_LOCATION, # type: ignore + **Postgres.Generator.PROPERTIES_LOCATION, exp.LikeProperty: exp.Properties.Location.POST_WITH, } TRANSFORMS = { - **Postgres.Generator.TRANSFORMS, # type: ignore + **Postgres.Generator.TRANSFORMS, exp.CurrentTimestamp: lambda self, e: "SYSDATE", exp.DateAdd: lambda self, e: self.func( "DATEADD", exp.var(e.text("unit") or "day"), e.expression, e.this @@ -107,10 +105,13 @@ class Redshift(Postgres): exp.SortKeyProperty: lambda self, e: f"{'COMPOUND ' if e.args['compound'] else ''}SORTKEY({self.format_args(*e.this)})", } + # Postgres maps exp.Pivot to no_pivot_sql, but Redshift support pivots + TRANSFORMS.pop(exp.Pivot) + # Redshift uses the POW | POWER (expr1, expr2) syntax instead of expr1 ^ expr2 (postgres) TRANSFORMS.pop(exp.Pow) - RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot"} + RESERVED_KEYWORDS = {*Postgres.Generator.RESERVED_KEYWORDS, "snapshot", "type"} def values_sql(self, expression: exp.Values) -> str: """ @@ -120,37 +121,36 @@ class Redshift(Postgres): evaluate the expression. You may need to increase `sys.setrecursionlimit` to run and it can also be very slow. """ - if not isinstance(expression.unnest().parent, exp.From): + + # The VALUES clause is still valid in an `INSERT INTO ..` statement, for example + if not expression.find_ancestor(exp.From, exp.Join): return super().values_sql(expression) - rows = [tuple_exp.expressions for tuple_exp in expression.expressions] + + column_names = expression.alias and expression.args["alias"].columns + selects = [] + rows = [tuple_exp.expressions for tuple_exp in expression.expressions] + for i, row in enumerate(rows): - if i == 0 and expression.alias: + if i == 0 and column_names: row = [ exp.alias_(value, column_name) - for value, column_name in zip(row, expression.args["alias"].args["columns"]) + for value, column_name in zip(row, column_names) ] + selects.append(exp.Select(expressions=row)) - subquery_expression = selects[0] + + subquery_expression: exp.Select | exp.Union = selects[0] if len(selects) > 1: for select in selects[1:]: subquery_expression = exp.union(subquery_expression, select, distinct=False) + return self.subquery_sql(subquery_expression.subquery(expression.alias)) def with_properties(self, properties: exp.Properties) -> str: """Redshift doesn't have `WITH` as part of their with_properties so we remove it""" return self.properties(properties, prefix=" ", suffix="") - def renametable_sql(self, expression: exp.RenameTable) -> str: - """Redshift only supports defining the table name itself (not the db) when renaming tables""" - expression = expression.copy() - target_table = expression.this - for arg in target_table.args: - if arg != "this": - target_table.set(arg, None) - this = self.sql(expression, "this") - return f"RENAME TO {this}" - def datatype_sql(self, expression: exp.DataType) -> str: """ Redshift converts the `TEXT` data type to `VARCHAR(255)` by default when people more generally mean @@ -162,6 +162,8 @@ class Redshift(Postgres): expression = expression.copy() expression.set("this", exp.DataType.Type.VARCHAR) precision = expression.args.get("expressions") + if not precision: expression.append("expressions", exp.Var(this="MAX")) + return super().datatype_sql(expression) |