altimate-code 0.5.2 → 0.5.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/bin/altimate +6 -0
  3. package/bin/altimate-code +6 -0
  4. package/dbt-tools/bin/altimate-dbt +2 -0
  5. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/__init__.py +0 -0
  6. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/fetch_schema.py +35 -0
  7. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/utils.py +353 -0
  8. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/validate_sql.py +114 -0
  9. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/__init__.py +178 -0
  10. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/__main__.py +96 -0
  11. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/_typing.py +17 -0
  12. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/__init__.py +3 -0
  13. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/__init__.py +18 -0
  14. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/_typing.py +18 -0
  15. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/column.py +332 -0
  16. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/dataframe.py +866 -0
  17. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/functions.py +1267 -0
  18. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/group.py +59 -0
  19. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/normalize.py +78 -0
  20. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/operations.py +53 -0
  21. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/readwriter.py +108 -0
  22. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/session.py +190 -0
  23. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/transforms.py +9 -0
  24. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/types.py +212 -0
  25. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/util.py +32 -0
  26. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/window.py +134 -0
  27. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/__init__.py +118 -0
  28. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/athena.py +166 -0
  29. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/bigquery.py +1331 -0
  30. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/clickhouse.py +1393 -0
  31. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/databricks.py +131 -0
  32. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/dialect.py +1915 -0
  33. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/doris.py +561 -0
  34. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/drill.py +157 -0
  35. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/druid.py +20 -0
  36. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/duckdb.py +1159 -0
  37. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/dune.py +16 -0
  38. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/hive.py +787 -0
  39. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/materialize.py +94 -0
  40. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/mysql.py +1324 -0
  41. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/oracle.py +378 -0
  42. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/postgres.py +778 -0
  43. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/presto.py +788 -0
  44. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/prql.py +203 -0
  45. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/redshift.py +448 -0
  46. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/risingwave.py +78 -0
  47. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/snowflake.py +1464 -0
  48. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/spark.py +202 -0
  49. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/spark2.py +349 -0
  50. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/sqlite.py +320 -0
  51. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/starrocks.py +343 -0
  52. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/tableau.py +61 -0
  53. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/teradata.py +356 -0
  54. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/trino.py +115 -0
  55. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/tsql.py +1403 -0
  56. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/diff.py +456 -0
  57. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/errors.py +93 -0
  58. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/__init__.py +95 -0
  59. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/context.py +101 -0
  60. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/env.py +246 -0
  61. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/python.py +460 -0
  62. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/table.py +155 -0
  63. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/expressions.py +8870 -0
  64. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/generator.py +4993 -0
  65. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/helper.py +582 -0
  66. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/jsonpath.py +227 -0
  67. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/lineage.py +423 -0
  68. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/__init__.py +11 -0
  69. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/annotate_types.py +589 -0
  70. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/canonicalize.py +222 -0
  71. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_ctes.py +43 -0
  72. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_joins.py +181 -0
  73. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_subqueries.py +189 -0
  74. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/isolate_table_selects.py +50 -0
  75. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/merge_subqueries.py +415 -0
  76. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/normalize.py +200 -0
  77. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/normalize_identifiers.py +64 -0
  78. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/optimize_joins.py +91 -0
  79. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/optimizer.py +94 -0
  80. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/pushdown_predicates.py +222 -0
  81. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/pushdown_projections.py +172 -0
  82. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify.py +104 -0
  83. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify_columns.py +1024 -0
  84. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify_tables.py +155 -0
  85. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/scope.py +904 -0
  86. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/simplify.py +1587 -0
  87. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/unnest_subqueries.py +302 -0
  88. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/parser.py +8501 -0
  89. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/planner.py +463 -0
  90. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/schema.py +588 -0
  91. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/serde.py +68 -0
  92. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/time.py +687 -0
  93. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/tokens.py +1520 -0
  94. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/transforms.py +1020 -0
  95. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/trie.py +81 -0
  96. package/dbt-tools/dist/altimate_python_packages/dbt_core_integration.py +825 -0
  97. package/dbt-tools/dist/altimate_python_packages/dbt_utils.py +157 -0
  98. package/dbt-tools/dist/index.js +23859 -0
  99. package/package.json +13 -13
  100. package/postinstall.mjs +42 -0
  101. package/skills/altimate-setup/SKILL.md +31 -0
@@ -0,0 +1,61 @@
1
+ from __future__ import annotations
2
+
3
+ from sqlglot import exp, generator, parser, tokens, transforms
4
+ from sqlglot.dialects.dialect import Dialect, rename_func, strposition_sql as _strposition_sql
5
+ from sqlglot.helper import seq_get
6
+
7
+
8
+ class Tableau(Dialect):
9
+ LOG_BASE_FIRST = False
10
+
11
+ class Tokenizer(tokens.Tokenizer):
12
+ IDENTIFIERS = [("[", "]")]
13
+ QUOTES = ["'", '"']
14
+
15
+ class Generator(generator.Generator):
16
+ JOIN_HINTS = False
17
+ TABLE_HINTS = False
18
+ QUERY_HINTS = False
19
+
20
+ TRANSFORMS = {
21
+ **generator.Generator.TRANSFORMS,
22
+ exp.Coalesce: rename_func("IFNULL"),
23
+ exp.Select: transforms.preprocess([transforms.eliminate_distinct_on]),
24
+ }
25
+
26
+ PROPERTIES_LOCATION = {
27
+ **generator.Generator.PROPERTIES_LOCATION,
28
+ exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
29
+ }
30
+
31
+ def if_sql(self, expression: exp.If) -> str:
32
+ this = self.sql(expression, "this")
33
+ true = self.sql(expression, "true")
34
+ false = self.sql(expression, "false")
35
+ return f"IF {this} THEN {true} ELSE {false} END"
36
+
37
+ def count_sql(self, expression: exp.Count) -> str:
38
+ this = expression.this
39
+ if isinstance(this, exp.Distinct):
40
+ return self.func("COUNTD", *this.expressions)
41
+ return self.func("COUNT", this)
42
+
43
+ def strposition_sql(self, expression: exp.StrPosition) -> str:
44
+ has_occurrence = "occurrence" in expression.args
45
+ return _strposition_sql(
46
+ self,
47
+ expression,
48
+ func_name="FINDNTH" if has_occurrence else "FIND",
49
+ supports_occurrence=has_occurrence,
50
+ )
51
+
52
+ class Parser(parser.Parser):
53
+ FUNCTIONS = {
54
+ **parser.Parser.FUNCTIONS,
55
+ "COUNTD": lambda args: exp.Count(this=exp.Distinct(expressions=args)),
56
+ "FIND": exp.StrPosition.from_arg_list,
57
+ "FINDNTH": lambda args: exp.StrPosition(
58
+ this=seq_get(args, 0), substr=seq_get(args, 1), occurrence=seq_get(args, 2)
59
+ ),
60
+ }
61
+ NO_PAREN_IF_COMMANDS = False
@@ -0,0 +1,356 @@
1
+ from __future__ import annotations
2
+
3
+ import typing as t
4
+
5
+ from sqlglot import exp, generator, parser, tokens, transforms
6
+ from sqlglot.dialects.dialect import (
7
+ Dialect,
8
+ max_or_greatest,
9
+ min_or_least,
10
+ rename_func,
11
+ strposition_sql,
12
+ to_number_with_nls_param,
13
+ )
14
+ from sqlglot.helper import seq_get
15
+ from sqlglot.tokens import TokenType
16
+
17
+
18
+ def _date_add_sql(
19
+ kind: t.Literal["+", "-"],
20
+ ) -> t.Callable[[Teradata.Generator, exp.DateAdd | exp.DateSub], str]:
21
+ def func(self: Teradata.Generator, expression: exp.DateAdd | exp.DateSub) -> str:
22
+ this = self.sql(expression, "this")
23
+ unit = expression.args.get("unit")
24
+ value = self._simplify_unless_literal(expression.expression)
25
+
26
+ if not isinstance(value, exp.Literal):
27
+ self.unsupported("Cannot add non literal")
28
+
29
+ if isinstance(value, exp.Neg):
30
+ kind_to_op = {"+": "-", "-": "+"}
31
+ value = exp.Literal.string(value.this.to_py())
32
+ else:
33
+ kind_to_op = {"+": "+", "-": "-"}
34
+ value.set("is_string", True)
35
+
36
+ return f"{this} {kind_to_op[kind]} {self.sql(exp.Interval(this=value, unit=unit))}"
37
+
38
+ return func
39
+
40
+
41
+ class Teradata(Dialect):
42
+ SUPPORTS_SEMI_ANTI_JOIN = False
43
+ TYPED_DIVISION = True
44
+
45
+ TIME_MAPPING = {
46
+ "YY": "%y",
47
+ "Y4": "%Y",
48
+ "YYYY": "%Y",
49
+ "M4": "%B",
50
+ "M3": "%b",
51
+ "M": "%-M",
52
+ "MI": "%M",
53
+ "MM": "%m",
54
+ "MMM": "%b",
55
+ "MMMM": "%B",
56
+ "D": "%-d",
57
+ "DD": "%d",
58
+ "D3": "%j",
59
+ "DDD": "%j",
60
+ "H": "%-H",
61
+ "HH": "%H",
62
+ "HH24": "%H",
63
+ "S": "%-S",
64
+ "SS": "%S",
65
+ "SSSSSS": "%f",
66
+ "E": "%a",
67
+ "EE": "%a",
68
+ "E3": "%a",
69
+ "E4": "%A",
70
+ "EEE": "%a",
71
+ "EEEE": "%A",
72
+ }
73
+
74
+ class Tokenizer(tokens.Tokenizer):
75
+ # Tested each of these and they work, although there is no
76
+ # Teradata documentation explicitly mentioning them.
77
+ HEX_STRINGS = [("X'", "'"), ("x'", "'"), ("0x", "")]
78
+ # https://docs.teradata.com/r/Teradata-Database-SQL-Functions-Operators-Expressions-and-Predicates/March-2017/Comparison-Operators-and-Functions/Comparison-Operators/ANSI-Compliance
79
+ # https://docs.teradata.com/r/SQL-Functions-Operators-Expressions-and-Predicates/June-2017/Arithmetic-Trigonometric-Hyperbolic-Operators/Functions
80
+ KEYWORDS = {
81
+ **tokens.Tokenizer.KEYWORDS,
82
+ "**": TokenType.DSTAR,
83
+ "^=": TokenType.NEQ,
84
+ "BYTEINT": TokenType.SMALLINT,
85
+ "COLLECT": TokenType.COMMAND,
86
+ "DEL": TokenType.DELETE,
87
+ "EQ": TokenType.EQ,
88
+ "GE": TokenType.GTE,
89
+ "GT": TokenType.GT,
90
+ "HELP": TokenType.COMMAND,
91
+ "INS": TokenType.INSERT,
92
+ "LE": TokenType.LTE,
93
+ "LT": TokenType.LT,
94
+ "MINUS": TokenType.EXCEPT,
95
+ "MOD": TokenType.MOD,
96
+ "NE": TokenType.NEQ,
97
+ "NOT=": TokenType.NEQ,
98
+ "SAMPLE": TokenType.TABLE_SAMPLE,
99
+ "SEL": TokenType.SELECT,
100
+ "ST_GEOMETRY": TokenType.GEOMETRY,
101
+ "TOP": TokenType.TOP,
102
+ "UPD": TokenType.UPDATE,
103
+ }
104
+ KEYWORDS.pop("/*+")
105
+
106
+ # Teradata does not support % as a modulo operator
107
+ SINGLE_TOKENS = {**tokens.Tokenizer.SINGLE_TOKENS}
108
+ SINGLE_TOKENS.pop("%")
109
+
110
+ class Parser(parser.Parser):
111
+ TABLESAMPLE_CSV = True
112
+ VALUES_FOLLOWED_BY_PAREN = False
113
+
114
+ CHARSET_TRANSLATORS = {
115
+ "GRAPHIC_TO_KANJISJIS",
116
+ "GRAPHIC_TO_LATIN",
117
+ "GRAPHIC_TO_UNICODE",
118
+ "GRAPHIC_TO_UNICODE_PadSpace",
119
+ "KANJI1_KanjiEBCDIC_TO_UNICODE",
120
+ "KANJI1_KanjiEUC_TO_UNICODE",
121
+ "KANJI1_KANJISJIS_TO_UNICODE",
122
+ "KANJI1_SBC_TO_UNICODE",
123
+ "KANJISJIS_TO_GRAPHIC",
124
+ "KANJISJIS_TO_LATIN",
125
+ "KANJISJIS_TO_UNICODE",
126
+ "LATIN_TO_GRAPHIC",
127
+ "LATIN_TO_KANJISJIS",
128
+ "LATIN_TO_UNICODE",
129
+ "LOCALE_TO_UNICODE",
130
+ "UNICODE_TO_GRAPHIC",
131
+ "UNICODE_TO_GRAPHIC_PadGraphic",
132
+ "UNICODE_TO_GRAPHIC_VarGraphic",
133
+ "UNICODE_TO_KANJI1_KanjiEBCDIC",
134
+ "UNICODE_TO_KANJI1_KanjiEUC",
135
+ "UNICODE_TO_KANJI1_KANJISJIS",
136
+ "UNICODE_TO_KANJI1_SBC",
137
+ "UNICODE_TO_KANJISJIS",
138
+ "UNICODE_TO_LATIN",
139
+ "UNICODE_TO_LOCALE",
140
+ "UNICODE_TO_UNICODE_FoldSpace",
141
+ "UNICODE_TO_UNICODE_Fullwidth",
142
+ "UNICODE_TO_UNICODE_Halfwidth",
143
+ "UNICODE_TO_UNICODE_NFC",
144
+ "UNICODE_TO_UNICODE_NFD",
145
+ "UNICODE_TO_UNICODE_NFKC",
146
+ "UNICODE_TO_UNICODE_NFKD",
147
+ }
148
+
149
+ FUNC_TOKENS = {*parser.Parser.FUNC_TOKENS}
150
+ FUNC_TOKENS.remove(TokenType.REPLACE)
151
+
152
+ STATEMENT_PARSERS = {
153
+ **parser.Parser.STATEMENT_PARSERS,
154
+ TokenType.DATABASE: lambda self: self.expression(
155
+ exp.Use, this=self._parse_table(schema=False)
156
+ ),
157
+ TokenType.REPLACE: lambda self: self._parse_create(),
158
+ }
159
+
160
+ FUNCTION_PARSERS = {
161
+ **parser.Parser.FUNCTION_PARSERS,
162
+ # https://docs.teradata.com/r/SQL-Functions-Operators-Expressions-and-Predicates/June-2017/Data-Type-Conversions/TRYCAST
163
+ "TRYCAST": parser.Parser.FUNCTION_PARSERS["TRY_CAST"],
164
+ "RANGE_N": lambda self: self._parse_rangen(),
165
+ "TRANSLATE": lambda self: self._parse_translate(),
166
+ }
167
+
168
+ FUNCTIONS = {
169
+ **parser.Parser.FUNCTIONS,
170
+ "CARDINALITY": exp.ArraySize.from_arg_list,
171
+ "RANDOM": lambda args: exp.Rand(lower=seq_get(args, 0), upper=seq_get(args, 1)),
172
+ }
173
+
174
+ EXPONENT = {
175
+ TokenType.DSTAR: exp.Pow,
176
+ }
177
+
178
+ def _parse_translate(self) -> exp.TranslateCharacters:
179
+ this = self._parse_assignment()
180
+ self._match(TokenType.USING)
181
+ self._match_texts(self.CHARSET_TRANSLATORS)
182
+
183
+ return self.expression(
184
+ exp.TranslateCharacters,
185
+ this=this,
186
+ expression=self._prev.text.upper(),
187
+ with_error=self._match_text_seq("WITH", "ERROR"),
188
+ )
189
+
190
+ # FROM before SET in Teradata UPDATE syntax
191
+ # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause
192
+ def _parse_update(self) -> exp.Update:
193
+ return self.expression(
194
+ exp.Update,
195
+ **{ # type: ignore
196
+ "this": self._parse_table(alias_tokens=self.UPDATE_ALIAS_TOKENS),
197
+ "from": self._parse_from(joins=True),
198
+ "expressions": self._match(TokenType.SET)
199
+ and self._parse_csv(self._parse_equality),
200
+ "where": self._parse_where(),
201
+ },
202
+ )
203
+
204
+ def _parse_rangen(self):
205
+ this = self._parse_id_var()
206
+ self._match(TokenType.BETWEEN)
207
+
208
+ expressions = self._parse_csv(self._parse_assignment)
209
+ each = self._match_text_seq("EACH") and self._parse_assignment()
210
+
211
+ return self.expression(exp.RangeN, this=this, expressions=expressions, each=each)
212
+
213
+ def _parse_index_params(self) -> exp.IndexParameters:
214
+ this = super()._parse_index_params()
215
+
216
+ if this.args.get("on"):
217
+ this.set("on", None)
218
+ self._retreat(self._index - 2)
219
+ return this
220
+
221
+ class Generator(generator.Generator):
222
+ LIMIT_IS_TOP = True
223
+ JOIN_HINTS = False
224
+ TABLE_HINTS = False
225
+ QUERY_HINTS = False
226
+ TABLESAMPLE_KEYWORDS = "SAMPLE"
227
+ LAST_DAY_SUPPORTS_DATE_PART = False
228
+ CAN_IMPLEMENT_ARRAY_ANY = True
229
+ TZ_TO_WITH_TIME_ZONE = True
230
+ ARRAY_SIZE_NAME = "CARDINALITY"
231
+
232
+ TYPE_MAPPING = {
233
+ **generator.Generator.TYPE_MAPPING,
234
+ exp.DataType.Type.GEOMETRY: "ST_GEOMETRY",
235
+ exp.DataType.Type.DOUBLE: "DOUBLE PRECISION",
236
+ exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
237
+ }
238
+
239
+ PROPERTIES_LOCATION = {
240
+ **generator.Generator.PROPERTIES_LOCATION,
241
+ exp.OnCommitProperty: exp.Properties.Location.POST_INDEX,
242
+ exp.PartitionedByProperty: exp.Properties.Location.POST_EXPRESSION,
243
+ exp.StabilityProperty: exp.Properties.Location.POST_CREATE,
244
+ }
245
+
246
+ TRANSFORMS = {
247
+ **generator.Generator.TRANSFORMS,
248
+ exp.ArgMax: rename_func("MAX_BY"),
249
+ exp.ArgMin: rename_func("MIN_BY"),
250
+ exp.Max: max_or_greatest,
251
+ exp.Min: min_or_least,
252
+ exp.Pow: lambda self, e: self.binary(e, "**"),
253
+ exp.Rand: lambda self, e: self.func("RANDOM", e.args.get("lower"), e.args.get("upper")),
254
+ exp.Select: transforms.preprocess(
255
+ [transforms.eliminate_distinct_on, transforms.eliminate_semi_and_anti_joins]
256
+ ),
257
+ exp.StrPosition: lambda self, e: (
258
+ strposition_sql(
259
+ self, e, func_name="INSTR", supports_position=True, supports_occurrence=True
260
+ )
261
+ ),
262
+ exp.StrToDate: lambda self,
263
+ e: f"CAST({self.sql(e, 'this')} AS DATE FORMAT {self.format_time(e)})",
264
+ exp.ToChar: lambda self, e: self.function_fallback_sql(e),
265
+ exp.ToNumber: to_number_with_nls_param,
266
+ exp.Use: lambda self, e: f"DATABASE {self.sql(e, 'this')}",
267
+ exp.DateAdd: _date_add_sql("+"),
268
+ exp.DateSub: _date_add_sql("-"),
269
+ exp.Quarter: lambda self, e: self.sql(exp.Extract(this="QUARTER", expression=e.this)),
270
+ }
271
+
272
+ def currenttimestamp_sql(self, expression: exp.CurrentTimestamp) -> str:
273
+ prefix, suffix = ("(", ")") if expression.this else ("", "")
274
+ return self.func("CURRENT_TIMESTAMP", expression.this, prefix=prefix, suffix=suffix)
275
+
276
+ def cast_sql(self, expression: exp.Cast, safe_prefix: t.Optional[str] = None) -> str:
277
+ if expression.to.this == exp.DataType.Type.UNKNOWN and expression.args.get("format"):
278
+ # We don't actually want to print the unknown type in CAST(<value> AS FORMAT <format>)
279
+ expression.to.pop()
280
+
281
+ return super().cast_sql(expression, safe_prefix=safe_prefix)
282
+
283
+ def trycast_sql(self, expression: exp.TryCast) -> str:
284
+ return self.cast_sql(expression, safe_prefix="TRY")
285
+
286
+ def tablesample_sql(
287
+ self,
288
+ expression: exp.TableSample,
289
+ tablesample_keyword: t.Optional[str] = None,
290
+ ) -> str:
291
+ return f"{self.sql(expression, 'this')} SAMPLE {self.expressions(expression)}"
292
+
293
+ def partitionedbyproperty_sql(self, expression: exp.PartitionedByProperty) -> str:
294
+ return f"PARTITION BY {self.sql(expression, 'this')}"
295
+
296
+ # FROM before SET in Teradata UPDATE syntax
297
+ # https://docs.teradata.com/r/Enterprise_IntelliFlex_VMware/Teradata-VantageTM-SQL-Data-Manipulation-Language-17.20/Statement-Syntax/UPDATE/UPDATE-Syntax-Basic-Form-FROM-Clause
298
+ def update_sql(self, expression: exp.Update) -> str:
299
+ this = self.sql(expression, "this")
300
+ from_sql = self.sql(expression, "from")
301
+ set_sql = self.expressions(expression, flat=True)
302
+ where_sql = self.sql(expression, "where")
303
+ sql = f"UPDATE {this}{from_sql} SET {set_sql}{where_sql}"
304
+ return self.prepend_ctes(expression, sql)
305
+
306
+ def mod_sql(self, expression: exp.Mod) -> str:
307
+ return self.binary(expression, "MOD")
308
+
309
+ def datatype_sql(self, expression: exp.DataType) -> str:
310
+ type_sql = super().datatype_sql(expression)
311
+ prefix_sql = expression.args.get("prefix")
312
+ return f"SYSUDTLIB.{type_sql}" if prefix_sql else type_sql
313
+
314
+ def rangen_sql(self, expression: exp.RangeN) -> str:
315
+ this = self.sql(expression, "this")
316
+ expressions_sql = self.expressions(expression)
317
+ each_sql = self.sql(expression, "each")
318
+ each_sql = f" EACH {each_sql}" if each_sql else ""
319
+
320
+ return f"RANGE_N({this} BETWEEN {expressions_sql}{each_sql})"
321
+
322
+ def createable_sql(self, expression: exp.Create, locations: t.DefaultDict) -> str:
323
+ kind = self.sql(expression, "kind").upper()
324
+ if kind == "TABLE" and locations.get(exp.Properties.Location.POST_NAME):
325
+ this_name = self.sql(expression.this, "this")
326
+ this_properties = self.properties(
327
+ exp.Properties(expressions=locations[exp.Properties.Location.POST_NAME]),
328
+ wrapped=False,
329
+ prefix=",",
330
+ )
331
+ this_schema = self.schema_columns_sql(expression.this)
332
+ return f"{this_name}{this_properties}{self.sep()}{this_schema}"
333
+
334
+ return super().createable_sql(expression, locations)
335
+
336
+ def extract_sql(self, expression: exp.Extract) -> str:
337
+ this = self.sql(expression, "this")
338
+ if this.upper() != "QUARTER":
339
+ return super().extract_sql(expression)
340
+
341
+ to_char = exp.func("to_char", expression.expression, exp.Literal.string("Q"))
342
+ return self.sql(exp.cast(to_char, exp.DataType.Type.INT))
343
+
344
+ def interval_sql(self, expression: exp.Interval) -> str:
345
+ multiplier = 0
346
+ unit = expression.text("unit")
347
+
348
+ if unit.startswith("WEEK"):
349
+ multiplier = 7
350
+ elif unit.startswith("QUARTER"):
351
+ multiplier = 90
352
+
353
+ if multiplier:
354
+ return f"({multiplier} * {super().interval_sql(exp.Interval(this=expression.this, unit=exp.var('DAY')))})"
355
+
356
+ return super().interval_sql(expression)
@@ -0,0 +1,115 @@
1
+ from __future__ import annotations
2
+
3
+ from sqlglot import exp, parser, transforms
4
+ from sqlglot.dialects.dialect import (
5
+ merge_without_target_sql,
6
+ trim_sql,
7
+ timestrtotime_sql,
8
+ groupconcat_sql,
9
+ )
10
+ from sqlglot.dialects.presto import amend_exploded_column_table, Presto
11
+ from sqlglot.tokens import TokenType
12
+ import typing as t
13
+
14
+
15
+ class Trino(Presto):
16
+ SUPPORTS_USER_DEFINED_TYPES = False
17
+ LOG_BASE_FIRST = True
18
+
19
+ class Parser(Presto.Parser):
20
+ FUNCTION_PARSERS = {
21
+ **Presto.Parser.FUNCTION_PARSERS,
22
+ "TRIM": lambda self: self._parse_trim(),
23
+ "JSON_QUERY": lambda self: self._parse_json_query(),
24
+ "LISTAGG": lambda self: self._parse_string_agg(),
25
+ }
26
+
27
+ JSON_QUERY_OPTIONS: parser.OPTIONS_TYPE = {
28
+ **dict.fromkeys(
29
+ ("WITH", "WITHOUT"),
30
+ (
31
+ ("WRAPPER"),
32
+ ("ARRAY", "WRAPPER"),
33
+ ("CONDITIONAL", "WRAPPER"),
34
+ ("CONDITIONAL", "ARRAY", "WRAPPED"),
35
+ ("UNCONDITIONAL", "WRAPPER"),
36
+ ("UNCONDITIONAL", "ARRAY", "WRAPPER"),
37
+ ),
38
+ ),
39
+ }
40
+
41
+ def _parse_json_query_quote(self) -> t.Optional[exp.JSONExtractQuote]:
42
+ if not (
43
+ self._match_text_seq("KEEP", "QUOTES") or self._match_text_seq("OMIT", "QUOTES")
44
+ ):
45
+ return None
46
+
47
+ return self.expression(
48
+ exp.JSONExtractQuote,
49
+ option=self._tokens[self._index - 2].text.upper(),
50
+ scalar=self._match_text_seq("ON", "SCALAR", "STRING"),
51
+ )
52
+
53
+ def _parse_json_query(self) -> exp.JSONExtract:
54
+ return self.expression(
55
+ exp.JSONExtract,
56
+ this=self._parse_bitwise(),
57
+ expression=self._match(TokenType.COMMA) and self._parse_bitwise(),
58
+ option=self._parse_var_from_options(self.JSON_QUERY_OPTIONS, raise_unmatched=False),
59
+ json_query=True,
60
+ quote=self._parse_json_query_quote(),
61
+ on_condition=self._parse_on_condition(),
62
+ )
63
+
64
+ class Generator(Presto.Generator):
65
+ PROPERTIES_LOCATION = {
66
+ **Presto.Generator.PROPERTIES_LOCATION,
67
+ exp.LocationProperty: exp.Properties.Location.POST_WITH,
68
+ }
69
+
70
+ TRANSFORMS = {
71
+ **Presto.Generator.TRANSFORMS,
72
+ exp.ArraySum: lambda self,
73
+ e: f"REDUCE({self.sql(e, 'this')}, 0, (acc, x) -> acc + x, acc -> acc)",
74
+ exp.ArrayUniqueAgg: lambda self, e: f"ARRAY_AGG(DISTINCT {self.sql(e, 'this')})",
75
+ exp.GroupConcat: lambda self, e: groupconcat_sql(self, e, on_overflow=True),
76
+ exp.LocationProperty: lambda self, e: self.property_sql(e),
77
+ exp.Merge: merge_without_target_sql,
78
+ exp.Select: transforms.preprocess(
79
+ [
80
+ transforms.eliminate_qualify,
81
+ transforms.eliminate_distinct_on,
82
+ transforms.explode_projection_to_unnest(1),
83
+ transforms.eliminate_semi_and_anti_joins,
84
+ amend_exploded_column_table,
85
+ ]
86
+ ),
87
+ exp.TimeStrToTime: lambda self, e: timestrtotime_sql(self, e, include_precision=True),
88
+ exp.Trim: trim_sql,
89
+ }
90
+
91
+ SUPPORTED_JSON_PATH_PARTS = {
92
+ exp.JSONPathKey,
93
+ exp.JSONPathRoot,
94
+ exp.JSONPathSubscript,
95
+ }
96
+
97
+ def jsonextract_sql(self, expression: exp.JSONExtract) -> str:
98
+ if not expression.args.get("json_query"):
99
+ return super().jsonextract_sql(expression)
100
+
101
+ json_path = self.sql(expression, "expression")
102
+ option = self.sql(expression, "option")
103
+ option = f" {option}" if option else ""
104
+
105
+ quote = self.sql(expression, "quote")
106
+ quote = f" {quote}" if quote else ""
107
+
108
+ on_condition = self.sql(expression, "on_condition")
109
+ on_condition = f" {on_condition}" if on_condition else ""
110
+
111
+ return self.func(
112
+ "JSON_QUERY",
113
+ expression.this,
114
+ json_path + option + quote + on_condition,
115
+ )