sqlglotc 30.12.0__tar.gz → 30.14.0__tar.gz

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 (119) hide show
  1. {sqlglotc-30.12.0/sqlglotc.egg-info → sqlglotc-30.14.0}/PKG-INFO +3 -3
  2. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/pyproject.toml +2 -2
  3. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/setup.py +7 -0
  4. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/aggregate.py +5 -4
  5. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/array.py +4 -0
  6. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/constraints.py +5 -0
  7. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/core.py +1 -1
  8. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/ddl.py +1 -1
  9. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/math.py +8 -0
  10. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/string.py +11 -0
  11. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/temporal.py +14 -3
  12. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generator.py +36 -20
  13. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/bigquery.py +30 -0
  14. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/databricks.py +13 -0
  15. sqlglotc-30.14.0/sqlglot/generators/dax.py +7 -0
  16. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/dremio.py +8 -0
  17. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/drill.py +17 -1
  18. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/duckdb.py +89 -59
  19. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/hive.py +87 -27
  20. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/oracle.py +1 -0
  21. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/postgres.py +8 -2
  22. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/presto.py +64 -5
  23. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/python.py +3 -1
  24. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/snowflake.py +57 -1
  25. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/spark.py +0 -1
  26. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/spark2.py +23 -0
  27. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/sqlite.py +6 -1
  28. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/trino.py +1 -0
  29. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/tsql.py +8 -4
  30. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/annotate_types.py +22 -8
  31. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/canonicalize_internal_names.py +21 -7
  32. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify.py +1 -1
  33. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify_columns.py +136 -27
  34. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/resolver.py +23 -10
  35. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/scope.py +4 -2
  36. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/simplify.py +13 -8
  37. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parser.py +167 -55
  38. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/bigquery.py +32 -18
  39. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/clickhouse.py +10 -1
  40. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/databricks.py +15 -0
  41. sqlglotc-30.14.0/sqlglot/parsers/dax.py +48 -0
  42. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/drill.py +8 -0
  43. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/duckdb.py +5 -0
  44. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/exasol.py +1 -1
  45. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/hive.py +2 -18
  46. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/mysql.py +3 -0
  47. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/oracle.py +5 -2
  48. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/presto.py +6 -2
  49. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/snowflake.py +5 -4
  50. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/spark2.py +1 -1
  51. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/tsql.py +10 -0
  52. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/time.py +23 -23
  53. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/tokenizer_core.py +12 -3
  54. {sqlglotc-30.12.0 → sqlglotc-30.14.0/sqlglotc.egg-info}/PKG-INFO +3 -3
  55. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/SOURCES.txt +2 -0
  56. sqlglotc-30.14.0/sqlglotc.egg-info/requires.txt +6 -0
  57. sqlglotc-30.14.0/sqlglotc.egg-info/scm_file_list.json +7 -0
  58. sqlglotc-30.14.0/sqlglotc.egg-info/scm_version.json +8 -0
  59. sqlglotc-30.12.0/sqlglotc.egg-info/requires.txt +0 -6
  60. sqlglotc-30.12.0/sqlglotc.egg-info/scm_file_list.json +0 -7
  61. sqlglotc-30.12.0/sqlglotc.egg-info/scm_version.json +0 -8
  62. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/MANIFEST.in +0 -0
  63. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/setup.cfg +0 -0
  64. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/errors.py +0 -0
  65. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/executor/table.py +0 -0
  66. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/builders.py +0 -0
  67. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/datatypes.py +0 -0
  68. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/dml.py +0 -0
  69. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/functions.py +0 -0
  70. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/json.py +0 -0
  71. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/properties.py +0 -0
  72. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/expressions/query.py +0 -0
  73. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/athena.py +0 -0
  74. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/clickhouse.py +0 -0
  75. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/doris.py +0 -0
  76. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/druid.py +0 -0
  77. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/dune.py +0 -0
  78. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/exasol.py +0 -0
  79. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/fabric.py +0 -0
  80. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/materialize.py +0 -0
  81. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/mysql.py +0 -0
  82. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/prql.py +0 -0
  83. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/redshift.py +0 -0
  84. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/risingwave.py +0 -0
  85. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/singlestore.py +0 -0
  86. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/solr.py +0 -0
  87. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/starrocks.py +0 -0
  88. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/tableau.py +0 -0
  89. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/generators/teradata.py +0 -0
  90. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/helper.py +0 -0
  91. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/lineage.py +0 -0
  92. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
  93. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
  94. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify_tables.py +0 -0
  95. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/athena.py +0 -0
  96. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/base.py +0 -0
  97. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/doris.py +0 -0
  98. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/dremio.py +0 -0
  99. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/druid.py +0 -0
  100. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/dune.py +0 -0
  101. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/fabric.py +0 -0
  102. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/materialize.py +0 -0
  103. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/postgres.py +0 -0
  104. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/prql.py +0 -0
  105. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/redshift.py +0 -0
  106. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/risingwave.py +0 -0
  107. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/singlestore.py +0 -0
  108. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/solr.py +0 -0
  109. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/spark.py +0 -0
  110. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/sqlite.py +0 -0
  111. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/starrocks.py +0 -0
  112. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/tableau.py +0 -0
  113. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/teradata.py +0 -0
  114. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/parsers/trino.py +0 -0
  115. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/schema.py +0 -0
  116. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/serde.py +0 -0
  117. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglot/trie.py +0 -0
  118. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
  119. {sqlglotc-30.12.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/top_level.txt +0 -0
@@ -1,15 +1,15 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sqlglotc
3
- Version: 30.12.0
3
+ Version: 30.14.0
4
4
  Summary: mypyc-compiled extensions for sqlglot
5
5
  Author-email: Toby Mao <toby.mao@gmail.com>
6
6
  License-Expression: MIT
7
7
  Project-URL: Homepage, https://sqlglot.com/
8
8
  Project-URL: Repository, https://github.com/tobymao/sqlglot
9
9
  Requires-Python: >=3.10
10
- Requires-Dist: sqlglot==30.12.0
10
+ Requires-Dist: sqlglot==30.14.0
11
11
  Provides-Extra: dev
12
12
  Requires-Dist: setuptools>=61.0; extra == "dev"
13
13
  Requires-Dist: setuptools_scm; extra == "dev"
14
- Requires-Dist: sqlglot-mypy>=2.1.0.post3; extra == "dev"
14
+ Requires-Dist: sqlglot-mypy>=2.1.0.post9; extra == "dev"
15
15
  Dynamic: requires-dist
@@ -7,7 +7,7 @@ license = "MIT"
7
7
  requires-python = ">= 3.10"
8
8
 
9
9
  [project.optional-dependencies]
10
- dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 2.1.0.post3"]
10
+ dev = ["setuptools >= 61.0", "setuptools_scm", "sqlglot-mypy >= 2.1.0.post9"]
11
11
 
12
12
  [project.urls]
13
13
  Homepage = "https://sqlglot.com/"
@@ -17,7 +17,7 @@ Repository = "https://github.com/tobymao/sqlglot"
17
17
  requires = [
18
18
  "setuptools >= 61.0",
19
19
  "setuptools_scm",
20
- "sqlglot-mypy >= 2.1.0.post3",
20
+ "sqlglot-mypy >= 2.1.0.post9",
21
21
  "types-python-dateutil",
22
22
  "sqlglot",
23
23
  ]
@@ -90,6 +90,13 @@ def _source_paths():
90
90
 
91
91
 
92
92
  class build_ext(_build_ext):
93
+ def finalize_options(self):
94
+ super().finalize_options()
95
+ # Compile in parallel by default; builds driven by pip (wheel/sdist installs)
96
+ # have no way to pass -j. An explicit -j on the command line still wins.
97
+ if self.parallel is None:
98
+ self.parallel = os.cpu_count() or 1
99
+
93
100
  def copy_extensions_to_source(self):
94
101
  """For editable installs, put sqlglot.* .so files in the sqlglot source dir."""
95
102
  for ext in self.extensions:
@@ -102,6 +102,7 @@ class Count(Expression, AggFunc):
102
102
 
103
103
  class CountIf(Expression, AggFunc):
104
104
  _sql_names = ["COUNT_IF", "COUNTIF"]
105
+ arg_types = {"this": True, "zero_on_all_null": False}
105
106
 
106
107
 
107
108
  class CovarPop(Expression, AggFunc):
@@ -255,19 +256,19 @@ class RegrAvgy(Expression, AggFunc):
255
256
 
256
257
 
257
258
  class RegrCount(Expression, AggFunc):
258
- arg_types = {"this": True, "expression": True}
259
+ arg_types = {"this": True, "expression": False}
259
260
 
260
261
 
261
262
  class RegrIntercept(Expression, AggFunc):
262
- arg_types = {"this": True, "expression": True}
263
+ arg_types = {"this": True, "expression": False}
263
264
 
264
265
 
265
266
  class RegrR2(Expression, AggFunc):
266
- arg_types = {"this": True, "expression": True}
267
+ arg_types = {"this": True, "expression": False}
267
268
 
268
269
 
269
270
  class RegrSlope(Expression, AggFunc):
270
- arg_types = {"this": True, "expression": True}
271
+ arg_types = {"this": True, "expression": False}
271
272
 
272
273
 
273
274
  class RegrSxx(Expression, AggFunc):
@@ -90,6 +90,10 @@ class ArraySort(Expression, Func):
90
90
  arg_types = {"this": True, "expression": False}
91
91
 
92
92
 
93
+ class Shuffle(Expression, Func):
94
+ pass
95
+
96
+
93
97
  class SortArray(Expression, Func):
94
98
  arg_types = {"this": True, "asc": False, "nulls_first": False}
95
99
 
@@ -220,6 +220,11 @@ class PrimaryKey(Expression):
220
220
  arg_types = {"this": False, "expressions": True, "options": False, "include": False}
221
221
 
222
222
 
223
+ # https://docs.databricks.com/aws/en/sql/language-manual/sql-ref-syntax-ddl-create-table-constraint
224
+ class TimeseriesKey(Expression):
225
+ pass
226
+
227
+
223
228
  class IndexParameters(Expression):
224
229
  arg_types = {
225
230
  "using": False,
@@ -2184,7 +2184,7 @@ class IntDiv(Expression, Binary):
2184
2184
 
2185
2185
 
2186
2186
  class Is(Expression, Binary, Predicate):
2187
- pass
2187
+ arg_types = {"this": True, "expression": True, "negate": False}
2188
2188
 
2189
2189
 
2190
2190
  class Like(Expression, Binary, Predicate):
@@ -432,7 +432,7 @@ class NextValueFor(Expression, Func):
432
432
 
433
433
 
434
434
  class Execute(Expression):
435
- arg_types = {"this": True, "expressions": False}
435
+ arg_types = {"this": True, "expressions": False, "return_status": False}
436
436
 
437
437
  @property
438
438
  def name(self) -> str:
@@ -164,10 +164,18 @@ class Log(Expression, Func):
164
164
  arg_types = {"this": True, "expression": False}
165
165
 
166
166
 
167
+ class Nanvl(Expression, Func):
168
+ arg_types = {"this": True, "expression": True}
169
+
170
+
167
171
  class Pi(Expression, Func):
168
172
  arg_types = {}
169
173
 
170
174
 
175
+ class Rint(Expression, Func):
176
+ pass
177
+
178
+
171
179
  class Round(Expression, Func):
172
180
  arg_types = {
173
181
  "this": True,
@@ -477,6 +477,17 @@ class RegexpSplit(Expression, Func):
477
477
  arg_types = {"this": True, "expression": True, "limit": False}
478
478
 
479
479
 
480
+ class RegexpSubstr(Expression, Func):
481
+ arg_types = {
482
+ "this": True,
483
+ "expression": True,
484
+ "position": False,
485
+ "occurrence": False,
486
+ "parameters": False,
487
+ "group": False,
488
+ }
489
+
490
+
480
491
  # Hashing / cryptographic
481
492
 
482
493
 
@@ -106,7 +106,7 @@ class DatetimeAdd(Expression, Func, IntervalOp):
106
106
 
107
107
 
108
108
  class DatetimeDiff(Expression, Func, TimeUnit):
109
- arg_types = {"this": True, "expression": True, "unit": False}
109
+ arg_types = {"this": True, "expression": True, "unit": False, "date_part_boundary": False}
110
110
 
111
111
 
112
112
  class DatetimeSub(Expression, Func, IntervalOp):
@@ -441,6 +441,10 @@ class FromISO8601Date(Expression, Func):
441
441
  _sql_names = ["FROM_ISO8601_DATE"]
442
442
 
443
443
 
444
+ class FromISO8601TimestampNanos(Expression, Func):
445
+ _sql_names = ["FROM_ISO8601_TIMESTAMP_NANOS"]
446
+
447
+
444
448
  class ParseDatetime(Expression, Func):
445
449
  arg_types = {"this": True, "format": False, "zone": False, "default_year": False}
446
450
 
@@ -450,11 +454,18 @@ class ParseTime(Expression, Func):
450
454
 
451
455
 
452
456
  class StrToDate(Expression, Func):
453
- arg_types = {"this": True, "format": False, "safe": False}
457
+ arg_types = {"this": True, "format": False, "safe": False, "default_year": False}
454
458
 
455
459
 
456
460
  class StrToTime(Expression, Func):
457
- arg_types = {"this": True, "format": True, "zone": False, "safe": False, "target_type": False}
461
+ arg_types = {
462
+ "this": True,
463
+ "format": True,
464
+ "zone": False,
465
+ "safe": False,
466
+ "target_type": False,
467
+ "default_year": False,
468
+ }
458
469
 
459
470
 
460
471
  class StrToUnix(Expression, Func):
@@ -402,9 +402,6 @@ class Generator:
402
402
  # UNNEST WITH ORDINALITY (presto) instead of UNNEST WITH OFFSET (bigquery)
403
403
  UNNEST_WITH_ORDINALITY = True
404
404
 
405
- # Whether FILTER (WHERE cond) can be used for conditional aggregation
406
- AGGREGATE_FILTER_SUPPORTED = True
407
-
408
405
  # Whether JOIN sides (LEFT, RIGHT) are supported in conjunction with SEMI/ANTI join kinds
409
406
  SEMI_ANTI_JOIN_WITH_SIDE = True
410
407
 
@@ -429,6 +426,9 @@ class Generator:
429
426
  # The keyword to use when specifying the seed of a sample clause
430
427
  TABLESAMPLE_SEED_KEYWORD = "SEED"
431
428
 
429
+ # Whether the historical data clause (AT ... / BEFORE ...) is generated after the table alias
430
+ HISTORICAL_DATA_POST_ALIAS = False
431
+
432
432
  # Whether COLLATE is a function instead of a binary operator
433
433
  COLLATE_IS_FUNC = False
434
434
 
@@ -1905,16 +1905,9 @@ class Generator:
1905
1905
  return f"{percent}{rows}{with_ties}"
1906
1906
 
1907
1907
  def filter_sql(self, expression: exp.Filter) -> str:
1908
- if self.AGGREGATE_FILTER_SUPPORTED:
1909
- this = self.sql(expression, "this")
1910
- where = self.sql(expression, "expression").strip()
1911
- return f"{this} FILTER({where})"
1912
-
1913
- agg = expression.this
1914
- agg_arg = agg.this
1915
- cond = expression.expression.this
1916
- agg_arg.replace(exp.If(this=cond.copy(), true=agg_arg.copy()))
1917
- return self.sql(agg)
1908
+ this = self.sql(expression, "this")
1909
+ where = self.sql(expression, "expression").strip()
1910
+ return f"{this} FILTER({where})"
1918
1911
 
1919
1912
  def hint_sql(self, expression: exp.Hint) -> str:
1920
1913
  if not self.QUERY_HINTS:
@@ -2433,7 +2426,10 @@ class Generator:
2433
2426
 
2434
2427
  when = self.sql(expression, "when")
2435
2428
  if when:
2436
- table = f"{table} {when}"
2429
+ if self.HISTORICAL_DATA_POST_ALIAS:
2430
+ alias = f"{alias} {when}"
2431
+ else:
2432
+ table = f"{table} {when}"
2437
2433
 
2438
2434
  changes = self.sql(expression, "changes")
2439
2435
  changes = f" {changes}" if changes else ""
@@ -3243,7 +3239,12 @@ class Generator:
3243
3239
  limit = expression.args.get("limit")
3244
3240
 
3245
3241
  if self.LIMIT_FETCH == "LIMIT" and isinstance(limit, exp.Fetch):
3246
- limit = exp.Limit(expression=exp.maybe_copy(limit.args.get("count")))
3242
+ count = limit.args.get("count")
3243
+ # "FETCH FIRST ROWS ONLY" without a count means one row per the SQL
3244
+ # standard; emitting a bare "LIMIT" here would produce invalid SQL.
3245
+ limit = exp.Limit(
3246
+ expression=exp.maybe_copy(count) if count is not None else exp.Literal.number(1)
3247
+ )
3247
3248
  elif self.LIMIT_FETCH == "FETCH" and isinstance(limit, exp.Limit):
3248
3249
  limit = exp.Fetch(direction="FIRST", count=exp.maybe_copy(limit.expression))
3249
3250
 
@@ -3723,6 +3724,10 @@ class Generator:
3723
3724
  options = f" {options}" if options else ""
3724
3725
  return f"PRIMARY KEY{this} ({expressions}){include}{options}"
3725
3726
 
3727
+ def timeserieskey_sql(self, expression: exp.TimeseriesKey) -> str:
3728
+ self.unsupported("TIMESERIES primary key columns are not supported")
3729
+ return self.sql(expression, "this")
3730
+
3726
3731
  def if_sql(self, expression: exp.If) -> str:
3727
3732
  return self.case_sql(exp.Case(ifs=[expression], default=expression.args.get("false")))
3728
3733
 
@@ -4008,6 +4013,9 @@ class Generator:
4008
4013
  def fromiso8601timestamp_sql(self, expression: exp.FromISO8601Timestamp) -> str:
4009
4014
  return self.sql(exp.cast(expression.this, exp.DType.TIMESTAMPTZ))
4010
4015
 
4016
+ def fromiso8601timestampnanos_sql(self, expression: exp.FromISO8601TimestampNanos) -> str:
4017
+ return self.sql(exp.cast(expression.this, exp.DType.TIMESTAMPTZ))
4018
+
4011
4019
  def add_sql(self, expression: exp.Add) -> str:
4012
4020
  return self.binary(expression, "+")
4013
4021
 
@@ -4087,6 +4095,10 @@ class Generator:
4087
4095
  def strtotime_sql(self, expression: exp.StrToTime) -> str:
4088
4096
  return self.func("STR_TO_TIME", expression.this, expression.args.get("format"))
4089
4097
 
4098
+ # Base implementation that excludes the safe and default_year metadata args
4099
+ def strtodate_sql(self, expression: exp.StrToDate) -> str:
4100
+ return self.func("STR_TO_DATE", expression.this, expression.args.get("format"))
4101
+
4090
4102
  def parsedatetime_sql(self, expression: exp.ParseDatetime) -> str:
4091
4103
  return self.func(
4092
4104
  "PARSE_DATETIME",
@@ -4428,11 +4440,11 @@ class Generator:
4428
4440
  return self.binary(expression, ">=")
4429
4441
 
4430
4442
  def is_sql(self, expression: exp.Is) -> str:
4443
+ negate = expression.args.get("negate")
4431
4444
  if not self.IS_BOOL_ALLOWED and isinstance(expression.expression, exp.Boolean):
4432
- return self.sql(
4433
- expression.this if expression.expression.this else exp.not_(expression.this)
4434
- )
4435
- return self.binary(expression, "IS")
4445
+ positive = bool(expression.expression.this) != bool(negate)
4446
+ return self.sql(expression.this if positive else exp.not_(expression.this))
4447
+ return self.binary(expression, "IS NOT" if negate else "IS")
4436
4448
 
4437
4449
  def _like_sql(
4438
4450
  self,
@@ -5662,7 +5674,11 @@ class Generator:
5662
5674
 
5663
5675
  def arrayagg_sql(self, expression: exp.ArrayAgg) -> str:
5664
5676
  array_agg = self.function_fallback_sql(expression)
5665
- return self._add_arrayagg_null_filter(array_agg, expression, expression.this)
5677
+ column_expr = expression.this
5678
+ if isinstance(column_expr, exp.Order):
5679
+ column_expr = column_expr.this
5680
+
5681
+ return self._add_arrayagg_null_filter(array_agg, expression, column_expr)
5666
5682
 
5667
5683
  def slice_sql(self, expression: exp.Slice) -> str:
5668
5684
  step = self.sql(expression, "step")
@@ -137,6 +137,34 @@ def _pushdown_cte_column_names(expression: exp.Expr) -> exp.Expr:
137
137
  return expression
138
138
 
139
139
 
140
+ def _unnest_explode_generate_series(expression: exp.Expr) -> exp.Expr:
141
+ """
142
+ Rewrites exploding GENERATE_SERIES projections into table references, e.g.
143
+
144
+ SELECT GENERATE_SERIES(1, 2) AS x -> SELECT x FROM GENERATE_SERIES(1, 2) AS x
145
+ SELECT y, GENERATE_SERIES(1, 2) AS x FROM t -> SELECT y, x FROM t CROSS JOIN GENERATE_SERIES(1, 2) AS x
146
+
147
+ since BigQuery can't explode in the projection and must unnest it in the FROM clause instead.
148
+ The resulting table reference is unnested downstream by `transforms.unnest_generate_series`.
149
+ """
150
+ if isinstance(expression, exp.Select):
151
+ for projection in expression.selects:
152
+ if isinstance(series := projection.unalias(), exp.ExplodingGenerateSeries):
153
+ column_name = projection.output_name or "_gen_series_value"
154
+
155
+ projection.replace(exp.column(column_name))
156
+ table = exp.Table(
157
+ this=series, alias=exp.TableAlias(this=exp.to_identifier(column_name))
158
+ )
159
+
160
+ if expression.args.get("from_"):
161
+ expression.join(table, copy=False, join_type="CROSS")
162
+ else:
163
+ expression.set("from_", exp.From(this=table))
164
+
165
+ return expression
166
+
167
+
140
168
  def _array_contains_sql(self: BigQueryGenerator, expression: exp.ArrayContains) -> str:
141
169
  return self.sql(
142
170
  exp.Exists(
@@ -358,6 +386,7 @@ class BigQueryGenerator(generator.Generator):
358
386
  exp.ParseDatetime: lambda self, e: self.func("PARSE_DATETIME", self.format_time(e), e.this),
359
387
  exp.Select: transforms.preprocess(
360
388
  [
389
+ _unnest_explode_generate_series,
361
390
  transforms.explode_projection_to_unnest(),
362
391
  transforms.unqualify_unnest,
363
392
  transforms.eliminate_distinct_on,
@@ -379,6 +408,7 @@ class BigQueryGenerator(generator.Generator):
379
408
  exp.StrToDate: _str_to_datetime_sql,
380
409
  exp.StrToTime: _str_to_datetime_sql,
381
410
  exp.SessionUser: lambda *_: "SESSION_USER()",
411
+ exp.Table: transforms.preprocess([transforms.unnest_generate_series]),
382
412
  exp.TimeAdd: date_add_interval_sql("TIME", "ADD"),
383
413
  exp.TimeFromParts: rename_func("TIME"),
384
414
  exp.TimestampFromParts: rename_func("DATETIME"),
@@ -57,6 +57,9 @@ class DatabricksGenerator(SparkGenerator):
57
57
  exp.CurrentCatalog: lambda *_: "CURRENT_CATALOG()",
58
58
  exp.RegexpLike: None,
59
59
  exp.TryCast: None,
60
+ exp.RegrAvgx: lambda self, e: self._regr_sql(e),
61
+ exp.RegrSxx: lambda self, e: self._regr_sql(e),
62
+ exp.RegrSyy: lambda self, e: self._regr_sql(e),
60
63
  }.items()
61
64
  if v is not None
62
65
  }
@@ -90,6 +93,9 @@ class DatabricksGenerator(SparkGenerator):
90
93
 
91
94
  return super().columndef_sql(expression, sep)
92
95
 
96
+ def timeserieskey_sql(self, expression: exp.TimeseriesKey) -> str:
97
+ return f"{self.sql(expression, 'this')} TIMESERIES"
98
+
93
99
  def jsonpath_sql(self, expression: exp.JSONPath) -> str:
94
100
  expression.set("escape", None)
95
101
  path = super().jsonpath_sql(expression)
@@ -109,6 +115,13 @@ class DatabricksGenerator(SparkGenerator):
109
115
 
110
116
  return self.func("UNIFORM", expression.this, expression.expression, seed)
111
117
 
118
+ def _regr_sql(self, expression: exp.RegrAvgx | exp.RegrSxx | exp.RegrSyy) -> str:
119
+ name = expression.sql_name()
120
+ x = expression.expression
121
+ if isinstance(x, exp.Distinct):
122
+ return self.func(name, exp.Distinct(expressions=[expression.this]), *x.expressions)
123
+ return self.func(name, expression.this, x)
124
+
112
125
  def clusterproperty_sql(self, expression):
113
126
  this = self.sql(expression, "this") or f"({self.expressions(expression, flat=True)})"
114
127
  return f"CLUSTER BY {this}"
@@ -0,0 +1,7 @@
1
+ from __future__ import annotations
2
+
3
+ from sqlglot import generator
4
+
5
+
6
+ class DAXGenerator(generator.Generator):
7
+ AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS
@@ -72,6 +72,14 @@ class DremioGenerator(generator.Generator):
72
72
  exp.GenerateSeries: rename_func("ARRAY_GENERATE_RANGE"),
73
73
  }
74
74
 
75
+ def version_sql(self, expression: exp.Version) -> str:
76
+ if expression.text("kind") == "AS OF":
77
+ this = "SNAPSHOT" if expression.name == "VERSION" else expression.name
78
+ return f"AT {this} {self.sql(expression, 'expression')}"
79
+
80
+ self.unsupported("Range time travel is not supported in Dremio")
81
+ return super().version_sql(expression)
82
+
75
83
  def datatype_sql(self, expression: exp.DataType) -> str:
76
84
  """
77
85
  Reject time-zone-aware TIMESTAMPs, which Dremio does not accept
@@ -29,6 +29,7 @@ class DrillGenerator(generator.Generator):
29
29
  TRY_SUPPORTED = False
30
30
  SUPPORTS_UESCAPE = False
31
31
  SUPPORTS_DECODE_CASE = False
32
+ SUPPORTS_LIKE_QUANTIFIERS = False
32
33
 
33
34
  AFTER_HAVING_MODIFIER_TRANSFORMS = generator.AFTER_HAVING_MODIFIER_TRANSFORMS
34
35
 
@@ -76,7 +77,6 @@ class DrillGenerator(generator.Generator):
76
77
  exp.If: lambda self, e: (
77
78
  f"`IF`({self.format_args(e.this, e.args.get('true'), e.args.get('false'))})"
78
79
  ),
79
- exp.ILike: lambda self, e: self.binary(e, "`ILIKE`"),
80
80
  exp.Levenshtein: unsupported_args("ins_cost", "del_cost", "sub_cost", "max_dist")(
81
81
  rename_func("LEVENSHTEIN_DISTANCE")
82
82
  ),
@@ -104,6 +104,22 @@ class DrillGenerator(generator.Generator):
104
104
  ),
105
105
  }
106
106
 
107
+ def ilike_sql(self, expression: exp.ILike) -> str:
108
+ if isinstance(expression.expression, (exp.All, exp.Any)):
109
+ return super().ilike_sql(expression)
110
+ return self._ilike_func_sql(expression)
111
+
112
+ def escape_sql(self, expression: exp.Escape) -> str:
113
+ # Drill takes the escape character as ILIKE's third argument instead of an ESCAPE clause
114
+ this = expression.this
115
+ if isinstance(this, exp.ILike) and not isinstance(this.expression, (exp.All, exp.Any)):
116
+ return self._ilike_func_sql(this, expression.expression)
117
+ return super().escape_sql(expression)
118
+
119
+ def _ilike_func_sql(self, expression: exp.ILike, escape: exp.Expr | None = None) -> str:
120
+ ilike = self.func("ILIKE", expression.this, expression.expression, escape)
121
+ return f"NOT {ilike}" if expression.args.get("negate") else ilike
122
+
107
123
 
108
124
  def _drill_dateint_format() -> str:
109
125
  from sqlglot.dialects.drill import Drill