altimate-code 0.5.1 → 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 (102) hide show
  1. package/CHANGELOG.md +35 -0
  2. package/README.md +1 -5
  3. package/bin/altimate +6 -0
  4. package/bin/altimate-code +6 -0
  5. package/dbt-tools/bin/altimate-dbt +2 -0
  6. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/__init__.py +0 -0
  7. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/fetch_schema.py +35 -0
  8. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/utils.py +353 -0
  9. package/dbt-tools/dist/altimate_python_packages/altimate_packages/altimate/validate_sql.py +114 -0
  10. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/__init__.py +178 -0
  11. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/__main__.py +96 -0
  12. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/_typing.py +17 -0
  13. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/__init__.py +3 -0
  14. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/__init__.py +18 -0
  15. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/_typing.py +18 -0
  16. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/column.py +332 -0
  17. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/dataframe.py +866 -0
  18. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/functions.py +1267 -0
  19. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/group.py +59 -0
  20. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/normalize.py +78 -0
  21. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/operations.py +53 -0
  22. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/readwriter.py +108 -0
  23. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/session.py +190 -0
  24. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/transforms.py +9 -0
  25. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/types.py +212 -0
  26. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/util.py +32 -0
  27. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dataframe/sql/window.py +134 -0
  28. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/__init__.py +118 -0
  29. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/athena.py +166 -0
  30. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/bigquery.py +1331 -0
  31. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/clickhouse.py +1393 -0
  32. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/databricks.py +131 -0
  33. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/dialect.py +1915 -0
  34. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/doris.py +561 -0
  35. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/drill.py +157 -0
  36. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/druid.py +20 -0
  37. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/duckdb.py +1159 -0
  38. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/dune.py +16 -0
  39. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/hive.py +787 -0
  40. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/materialize.py +94 -0
  41. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/mysql.py +1324 -0
  42. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/oracle.py +378 -0
  43. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/postgres.py +778 -0
  44. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/presto.py +788 -0
  45. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/prql.py +203 -0
  46. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/redshift.py +448 -0
  47. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/risingwave.py +78 -0
  48. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/snowflake.py +1464 -0
  49. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/spark.py +202 -0
  50. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/spark2.py +349 -0
  51. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/sqlite.py +320 -0
  52. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/starrocks.py +343 -0
  53. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/tableau.py +61 -0
  54. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/teradata.py +356 -0
  55. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/trino.py +115 -0
  56. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/dialects/tsql.py +1403 -0
  57. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/diff.py +456 -0
  58. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/errors.py +93 -0
  59. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/__init__.py +95 -0
  60. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/context.py +101 -0
  61. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/env.py +246 -0
  62. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/python.py +460 -0
  63. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/executor/table.py +155 -0
  64. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/expressions.py +8870 -0
  65. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/generator.py +4993 -0
  66. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/helper.py +582 -0
  67. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/jsonpath.py +227 -0
  68. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/lineage.py +423 -0
  69. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/__init__.py +11 -0
  70. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/annotate_types.py +589 -0
  71. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/canonicalize.py +222 -0
  72. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_ctes.py +43 -0
  73. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_joins.py +181 -0
  74. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/eliminate_subqueries.py +189 -0
  75. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/isolate_table_selects.py +50 -0
  76. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/merge_subqueries.py +415 -0
  77. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/normalize.py +200 -0
  78. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/normalize_identifiers.py +64 -0
  79. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/optimize_joins.py +91 -0
  80. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/optimizer.py +94 -0
  81. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/pushdown_predicates.py +222 -0
  82. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/pushdown_projections.py +172 -0
  83. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify.py +104 -0
  84. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify_columns.py +1024 -0
  85. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/qualify_tables.py +155 -0
  86. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/scope.py +904 -0
  87. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/simplify.py +1587 -0
  88. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/optimizer/unnest_subqueries.py +302 -0
  89. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/parser.py +8501 -0
  90. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/planner.py +463 -0
  91. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/schema.py +588 -0
  92. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/serde.py +68 -0
  93. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/time.py +687 -0
  94. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/tokens.py +1520 -0
  95. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/transforms.py +1020 -0
  96. package/dbt-tools/dist/altimate_python_packages/altimate_packages/sqlglot/trie.py +81 -0
  97. package/dbt-tools/dist/altimate_python_packages/dbt_core_integration.py +825 -0
  98. package/dbt-tools/dist/altimate_python_packages/dbt_utils.py +157 -0
  99. package/dbt-tools/dist/index.js +23859 -0
  100. package/package.json +13 -13
  101. package/postinstall.mjs +42 -0
  102. package/skills/altimate-setup/SKILL.md +31 -0
@@ -0,0 +1,378 @@
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
+ NormalizationStrategy,
9
+ build_timetostr_or_tochar,
10
+ build_formatted_time,
11
+ no_ilike_sql,
12
+ rename_func,
13
+ strposition_sql,
14
+ to_number_with_nls_param,
15
+ trim_sql,
16
+ )
17
+ from sqlglot.helper import seq_get
18
+ from sqlglot.parser import OPTIONS_TYPE, build_coalesce
19
+ from sqlglot.tokens import TokenType
20
+
21
+ if t.TYPE_CHECKING:
22
+ from sqlglot._typing import E
23
+
24
+
25
+ def _trim_sql(self: Oracle.Generator, expression: exp.Trim) -> str:
26
+ position = expression.args.get("position")
27
+
28
+ if position and position.upper() in ("LEADING", "TRAILING"):
29
+ return self.trim_sql(expression)
30
+
31
+ return trim_sql(self, expression)
32
+
33
+
34
+ def _build_to_timestamp(args: t.List) -> exp.StrToTime | exp.Anonymous:
35
+ if len(args) == 1:
36
+ return exp.Anonymous(this="TO_TIMESTAMP", expressions=args)
37
+
38
+ return build_formatted_time(exp.StrToTime, "oracle")(args)
39
+
40
+
41
+ class Oracle(Dialect):
42
+ ALIAS_POST_TABLESAMPLE = True
43
+ LOCKING_READS_SUPPORTED = True
44
+ TABLESAMPLE_SIZE_IS_PERCENT = True
45
+ NULL_ORDERING = "nulls_are_large"
46
+ ON_CONDITION_EMPTY_BEFORE_ERROR = False
47
+ ALTER_TABLE_ADD_REQUIRED_FOR_EACH_COLUMN = False
48
+
49
+ # See section 8: https://docs.oracle.com/cd/A97630_01/server.920/a96540/sql_elements9a.htm
50
+ NORMALIZATION_STRATEGY = NormalizationStrategy.UPPERCASE
51
+
52
+ # https://docs.oracle.com/database/121/SQLRF/sql_elements004.htm#SQLRF00212
53
+ # https://docs.python.org/3/library/datetime.html#strftime-and-strptime-format-codes
54
+ TIME_MAPPING = {
55
+ "AM": "%p", # Meridian indicator with or without periods
56
+ "A.M.": "%p", # Meridian indicator with or without periods
57
+ "PM": "%p", # Meridian indicator with or without periods
58
+ "P.M.": "%p", # Meridian indicator with or without periods
59
+ "D": "%u", # Day of week (1-7)
60
+ "DAY": "%A", # name of day
61
+ "DD": "%d", # day of month (1-31)
62
+ "DDD": "%j", # day of year (1-366)
63
+ "DY": "%a", # abbreviated name of day
64
+ "HH": "%I", # Hour of day (1-12)
65
+ "HH12": "%I", # alias for HH
66
+ "HH24": "%H", # Hour of day (0-23)
67
+ "IW": "%V", # Calendar week of year (1-52 or 1-53), as defined by the ISO 8601 standard
68
+ "MI": "%M", # Minute (0-59)
69
+ "MM": "%m", # Month (01-12; January = 01)
70
+ "MON": "%b", # Abbreviated name of month
71
+ "MONTH": "%B", # Name of month
72
+ "SS": "%S", # Second (0-59)
73
+ "WW": "%W", # Week of year (1-53)
74
+ "YY": "%y", # 15
75
+ "YYYY": "%Y", # 2015
76
+ "FF6": "%f", # only 6 digits are supported in python formats
77
+ }
78
+
79
+ class Tokenizer(tokens.Tokenizer):
80
+ VAR_SINGLE_TOKENS = {"@", "$", "#"}
81
+
82
+ UNICODE_STRINGS = [
83
+ (prefix + q, q)
84
+ for q in t.cast(t.List[str], tokens.Tokenizer.QUOTES)
85
+ for prefix in ("U", "u")
86
+ ]
87
+
88
+ NESTED_COMMENTS = False
89
+
90
+ KEYWORDS = {
91
+ **tokens.Tokenizer.KEYWORDS,
92
+ "(+)": TokenType.JOIN_MARKER,
93
+ "BINARY_DOUBLE": TokenType.DOUBLE,
94
+ "BINARY_FLOAT": TokenType.FLOAT,
95
+ "BULK COLLECT INTO": TokenType.BULK_COLLECT_INTO,
96
+ "COLUMNS": TokenType.COLUMN,
97
+ "MATCH_RECOGNIZE": TokenType.MATCH_RECOGNIZE,
98
+ "MINUS": TokenType.EXCEPT,
99
+ "NVARCHAR2": TokenType.NVARCHAR,
100
+ "ORDER SIBLINGS BY": TokenType.ORDER_SIBLINGS_BY,
101
+ "SAMPLE": TokenType.TABLE_SAMPLE,
102
+ "START": TokenType.BEGIN,
103
+ "TOP": TokenType.TOP,
104
+ "VARCHAR2": TokenType.VARCHAR,
105
+ }
106
+
107
+ class Parser(parser.Parser):
108
+ WINDOW_BEFORE_PAREN_TOKENS = {TokenType.OVER, TokenType.KEEP}
109
+ VALUES_FOLLOWED_BY_PAREN = False
110
+
111
+ FUNCTIONS = {
112
+ **parser.Parser.FUNCTIONS,
113
+ "CONVERT": exp.ConvertToCharset.from_arg_list,
114
+ "NVL": lambda args: build_coalesce(args, is_nvl=True),
115
+ "SQUARE": lambda args: exp.Pow(this=seq_get(args, 0), expression=exp.Literal.number(2)),
116
+ "TO_CHAR": build_timetostr_or_tochar,
117
+ "TO_TIMESTAMP": _build_to_timestamp,
118
+ "TO_DATE": build_formatted_time(exp.StrToDate, "oracle"),
119
+ "TRUNC": lambda args: exp.DateTrunc(
120
+ unit=seq_get(args, 1) or exp.Literal.string("DD"),
121
+ this=seq_get(args, 0),
122
+ unabbreviate=False,
123
+ ),
124
+ }
125
+
126
+ NO_PAREN_FUNCTION_PARSERS = {
127
+ **parser.Parser.NO_PAREN_FUNCTION_PARSERS,
128
+ "NEXT": lambda self: self._parse_next_value_for(),
129
+ "PRIOR": lambda self: self.expression(exp.Prior, this=self._parse_bitwise()),
130
+ "SYSDATE": lambda self: self.expression(exp.CurrentTimestamp, sysdate=True),
131
+ }
132
+
133
+ FUNCTION_PARSERS: t.Dict[str, t.Callable] = {
134
+ **parser.Parser.FUNCTION_PARSERS,
135
+ "JSON_ARRAY": lambda self: self._parse_json_array(
136
+ exp.JSONArray,
137
+ expressions=self._parse_csv(lambda: self._parse_format_json(self._parse_bitwise())),
138
+ ),
139
+ "JSON_ARRAYAGG": lambda self: self._parse_json_array(
140
+ exp.JSONArrayAgg,
141
+ this=self._parse_format_json(self._parse_bitwise()),
142
+ order=self._parse_order(),
143
+ ),
144
+ "JSON_EXISTS": lambda self: self._parse_json_exists(),
145
+ }
146
+ FUNCTION_PARSERS.pop("CONVERT")
147
+
148
+ PROPERTY_PARSERS = {
149
+ **parser.Parser.PROPERTY_PARSERS,
150
+ "GLOBAL": lambda self: self._match_text_seq("TEMPORARY")
151
+ and self.expression(exp.TemporaryProperty, this="GLOBAL"),
152
+ "PRIVATE": lambda self: self._match_text_seq("TEMPORARY")
153
+ and self.expression(exp.TemporaryProperty, this="PRIVATE"),
154
+ "FORCE": lambda self: self.expression(exp.ForceProperty),
155
+ }
156
+
157
+ QUERY_MODIFIER_PARSERS = {
158
+ **parser.Parser.QUERY_MODIFIER_PARSERS,
159
+ TokenType.ORDER_SIBLINGS_BY: lambda self: ("order", self._parse_order()),
160
+ TokenType.WITH: lambda self: ("options", [self._parse_query_restrictions()]),
161
+ }
162
+
163
+ TYPE_LITERAL_PARSERS = {
164
+ exp.DataType.Type.DATE: lambda self, this, _: self.expression(
165
+ exp.DateStrToDate, this=this
166
+ )
167
+ }
168
+
169
+ # SELECT UNIQUE .. is old-style Oracle syntax for SELECT DISTINCT ..
170
+ # Reference: https://stackoverflow.com/a/336455
171
+ DISTINCT_TOKENS = {TokenType.DISTINCT, TokenType.UNIQUE}
172
+
173
+ QUERY_RESTRICTIONS: OPTIONS_TYPE = {
174
+ "WITH": (
175
+ ("READ", "ONLY"),
176
+ ("CHECK", "OPTION"),
177
+ ),
178
+ }
179
+
180
+ def _parse_json_array(self, expr_type: t.Type[E], **kwargs) -> E:
181
+ return self.expression(
182
+ expr_type,
183
+ null_handling=self._parse_on_handling("NULL", "NULL", "ABSENT"),
184
+ return_type=self._match_text_seq("RETURNING") and self._parse_type(),
185
+ strict=self._match_text_seq("STRICT"),
186
+ **kwargs,
187
+ )
188
+
189
+ def _parse_hint_function_call(self) -> t.Optional[exp.Expression]:
190
+ if not self._curr or not self._next or self._next.token_type != TokenType.L_PAREN:
191
+ return None
192
+
193
+ this = self._curr.text
194
+
195
+ self._advance(2)
196
+ args = self._parse_hint_args()
197
+ this = self.expression(exp.Anonymous, this=this, expressions=args)
198
+ self._match_r_paren(this)
199
+ return this
200
+
201
+ def _parse_hint_args(self):
202
+ args = []
203
+ result = self._parse_var()
204
+
205
+ while result:
206
+ args.append(result)
207
+ result = self._parse_var()
208
+
209
+ return args
210
+
211
+ def _parse_query_restrictions(self) -> t.Optional[exp.Expression]:
212
+ kind = self._parse_var_from_options(self.QUERY_RESTRICTIONS, raise_unmatched=False)
213
+
214
+ if not kind:
215
+ return None
216
+
217
+ return self.expression(
218
+ exp.QueryOption,
219
+ this=kind,
220
+ expression=self._match(TokenType.CONSTRAINT) and self._parse_field(),
221
+ )
222
+
223
+ def _parse_json_exists(self) -> exp.JSONExists:
224
+ this = self._parse_format_json(self._parse_bitwise())
225
+ self._match(TokenType.COMMA)
226
+ return self.expression(
227
+ exp.JSONExists,
228
+ this=this,
229
+ path=self.dialect.to_json_path(self._parse_bitwise()),
230
+ passing=self._match_text_seq("PASSING")
231
+ and self._parse_csv(lambda: self._parse_alias(self._parse_bitwise())),
232
+ on_condition=self._parse_on_condition(),
233
+ )
234
+
235
+ def _parse_into(self) -> t.Optional[exp.Into]:
236
+ # https://docs.oracle.com/en/database/oracle/oracle-database/19/lnpls/SELECT-INTO-statement.html
237
+ bulk_collect = self._match(TokenType.BULK_COLLECT_INTO)
238
+ if not bulk_collect and not self._match(TokenType.INTO):
239
+ return None
240
+
241
+ index = self._index
242
+
243
+ expressions = self._parse_expressions()
244
+ if len(expressions) == 1:
245
+ self._retreat(index)
246
+ self._match(TokenType.TABLE)
247
+ return self.expression(
248
+ exp.Into, this=self._parse_table(schema=True), bulk_collect=bulk_collect
249
+ )
250
+
251
+ return self.expression(exp.Into, bulk_collect=bulk_collect, expressions=expressions)
252
+
253
+ def _parse_connect_with_prior(self):
254
+ return self._parse_assignment()
255
+
256
+ class Generator(generator.Generator):
257
+ LOCKING_READS_SUPPORTED = True
258
+ JOIN_HINTS = False
259
+ TABLE_HINTS = False
260
+ DATA_TYPE_SPECIFIERS_ALLOWED = True
261
+ ALTER_TABLE_INCLUDE_COLUMN_KEYWORD = False
262
+ LIMIT_FETCH = "FETCH"
263
+ TABLESAMPLE_KEYWORDS = "SAMPLE"
264
+ LAST_DAY_SUPPORTS_DATE_PART = False
265
+ SUPPORTS_SELECT_INTO = True
266
+ TZ_TO_WITH_TIME_ZONE = True
267
+ SUPPORTS_WINDOW_EXCLUDE = True
268
+ QUERY_HINT_SEP = " "
269
+
270
+ TYPE_MAPPING = {
271
+ **generator.Generator.TYPE_MAPPING,
272
+ exp.DataType.Type.TINYINT: "SMALLINT",
273
+ exp.DataType.Type.SMALLINT: "SMALLINT",
274
+ exp.DataType.Type.INT: "INT",
275
+ exp.DataType.Type.BIGINT: "INT",
276
+ exp.DataType.Type.DECIMAL: "NUMBER",
277
+ exp.DataType.Type.DOUBLE: "DOUBLE PRECISION",
278
+ exp.DataType.Type.VARCHAR: "VARCHAR2",
279
+ exp.DataType.Type.NVARCHAR: "NVARCHAR2",
280
+ exp.DataType.Type.NCHAR: "NCHAR",
281
+ exp.DataType.Type.TEXT: "CLOB",
282
+ exp.DataType.Type.TIMETZ: "TIME",
283
+ exp.DataType.Type.TIMESTAMPNTZ: "TIMESTAMP",
284
+ exp.DataType.Type.TIMESTAMPTZ: "TIMESTAMP",
285
+ exp.DataType.Type.BINARY: "BLOB",
286
+ exp.DataType.Type.VARBINARY: "BLOB",
287
+ exp.DataType.Type.ROWVERSION: "BLOB",
288
+ }
289
+ TYPE_MAPPING.pop(exp.DataType.Type.BLOB)
290
+
291
+ TRANSFORMS = {
292
+ **generator.Generator.TRANSFORMS,
293
+ exp.DateStrToDate: lambda self, e: self.func(
294
+ "TO_DATE", e.this, exp.Literal.string("YYYY-MM-DD")
295
+ ),
296
+ exp.DateTrunc: lambda self, e: self.func("TRUNC", e.this, e.unit),
297
+ exp.Group: transforms.preprocess([transforms.unalias_group]),
298
+ exp.ILike: no_ilike_sql,
299
+ exp.LogicalOr: rename_func("MAX"),
300
+ exp.LogicalAnd: rename_func("MIN"),
301
+ exp.Mod: rename_func("MOD"),
302
+ exp.Select: transforms.preprocess(
303
+ [
304
+ transforms.eliminate_distinct_on,
305
+ transforms.eliminate_qualify,
306
+ ]
307
+ ),
308
+ exp.StrPosition: lambda self, e: (
309
+ strposition_sql(
310
+ self, e, func_name="INSTR", supports_position=True, supports_occurrence=True
311
+ )
312
+ ),
313
+ exp.StrToTime: lambda self, e: self.func("TO_TIMESTAMP", e.this, self.format_time(e)),
314
+ exp.StrToDate: lambda self, e: self.func("TO_DATE", e.this, self.format_time(e)),
315
+ exp.Subquery: lambda self, e: self.subquery_sql(e, sep=" "),
316
+ exp.Substring: rename_func("SUBSTR"),
317
+ exp.Table: lambda self, e: self.table_sql(e, sep=" "),
318
+ exp.TableSample: lambda self, e: self.tablesample_sql(e),
319
+ exp.TemporaryProperty: lambda _, e: f"{e.name or 'GLOBAL'} TEMPORARY",
320
+ exp.TimeToStr: lambda self, e: self.func("TO_CHAR", e.this, self.format_time(e)),
321
+ exp.ToChar: lambda self, e: self.function_fallback_sql(e),
322
+ exp.ToNumber: to_number_with_nls_param,
323
+ exp.Trim: _trim_sql,
324
+ exp.Unicode: lambda self, e: f"ASCII(UNISTR({self.sql(e.this)}))",
325
+ exp.UnixToTime: lambda self,
326
+ e: f"TO_DATE('1970-01-01', 'YYYY-MM-DD') + ({self.sql(e, 'this')} / 86400)",
327
+ }
328
+
329
+ PROPERTIES_LOCATION = {
330
+ **generator.Generator.PROPERTIES_LOCATION,
331
+ exp.VolatileProperty: exp.Properties.Location.UNSUPPORTED,
332
+ }
333
+
334
+ def currenttimestamp_sql(self, expression: exp.CurrentTimestamp) -> str:
335
+ if expression.args.get("sysdate"):
336
+ return "SYSDATE"
337
+
338
+ this = expression.this
339
+ return self.func("CURRENT_TIMESTAMP", this) if this else "CURRENT_TIMESTAMP"
340
+
341
+ def offset_sql(self, expression: exp.Offset) -> str:
342
+ return f"{super().offset_sql(expression)} ROWS"
343
+
344
+ def add_column_sql(self, expression: exp.Expression) -> str:
345
+ return f"ADD {self.sql(expression)}"
346
+
347
+ def queryoption_sql(self, expression: exp.QueryOption) -> str:
348
+ option = self.sql(expression, "this")
349
+ value = self.sql(expression, "expression")
350
+ value = f" CONSTRAINT {value}" if value else ""
351
+
352
+ return f"{option}{value}"
353
+
354
+ def coalesce_sql(self, expression: exp.Coalesce) -> str:
355
+ func_name = "NVL" if expression.args.get("is_nvl") else "COALESCE"
356
+ return rename_func(func_name)(self, expression)
357
+
358
+ def into_sql(self, expression: exp.Into) -> str:
359
+ into = "INTO" if not expression.args.get("bulk_collect") else "BULK COLLECT INTO"
360
+ if expression.this:
361
+ return f"{self.seg(into)} {self.sql(expression, 'this')}"
362
+
363
+ return f"{self.seg(into)} {self.expressions(expression)}"
364
+
365
+ def hint_sql(self, expression: exp.Hint) -> str:
366
+ expressions = []
367
+
368
+ for expression in expression.expressions:
369
+ if isinstance(expression, exp.Anonymous):
370
+ formatted_args = self.format_args(*expression.expressions, sep=" ")
371
+ expressions.append(f"{self.sql(expression, 'this')}({formatted_args})")
372
+ else:
373
+ expressions.append(self.sql(expression))
374
+
375
+ return f" /*+ {self.expressions(sqls=expressions, sep=self.QUERY_HINT_SEP).strip()} */"
376
+
377
+ def isascii_sql(self, expression: exp.IsAscii) -> str:
378
+ return f"NVL(REGEXP_LIKE({self.sql(expression.this)}, '^[' || CHR(1) || '-' || CHR(127) || ']*$'), TRUE)"