sqlglotc 30.13.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.
- {sqlglotc-30.13.0/sqlglotc.egg-info → sqlglotc-30.14.0}/PKG-INFO +2 -2
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/array.py +4 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/core.py +1 -1
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/math.py +4 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generator.py +9 -5
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/duckdb.py +60 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/hive.py +20 -11
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/python.py +3 -1
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/tsql.py +3 -2
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/canonicalize_internal_names.py +2 -1
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify.py +1 -1
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify_columns.py +56 -9
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/simplify.py +11 -3
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parser.py +55 -6
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/duckdb.py +1 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0/sqlglotc.egg-info}/PKG-INFO +2 -2
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/requires.txt +1 -1
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/scm_file_list.json +2 -2
- sqlglotc-30.14.0/sqlglotc.egg-info/scm_version.json +8 -0
- sqlglotc-30.13.0/sqlglotc.egg-info/scm_version.json +0 -8
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/MANIFEST.in +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/pyproject.toml +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/setup.cfg +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/setup.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/errors.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/executor/table.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/aggregate.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/builders.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/constraints.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/datatypes.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/ddl.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/dml.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/functions.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/json.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/properties.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/query.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/string.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/expressions/temporal.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/athena.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/bigquery.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/clickhouse.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/databricks.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/dax.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/doris.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/dremio.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/drill.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/druid.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/dune.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/exasol.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/fabric.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/materialize.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/mysql.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/oracle.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/postgres.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/presto.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/prql.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/redshift.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/risingwave.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/singlestore.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/snowflake.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/solr.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/spark.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/spark2.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/sqlite.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/starrocks.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/tableau.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/teradata.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/generators/trino.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/helper.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/lineage.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/annotate_types.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/isolate_table_selects.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/normalize_identifiers.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/qualify_tables.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/resolver.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/optimizer/scope.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/athena.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/base.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/bigquery.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/clickhouse.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/databricks.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/dax.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/doris.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/dremio.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/drill.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/druid.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/dune.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/exasol.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/fabric.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/hive.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/materialize.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/mysql.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/oracle.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/postgres.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/presto.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/prql.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/redshift.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/risingwave.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/singlestore.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/snowflake.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/solr.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/spark.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/spark2.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/sqlite.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/starrocks.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/tableau.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/teradata.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/trino.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/parsers/tsql.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/schema.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/serde.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/time.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/tokenizer_core.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglot/trie.py +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/SOURCES.txt +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/dependency_links.txt +0 -0
- {sqlglotc-30.13.0 → sqlglotc-30.14.0}/sqlglotc.egg-info/top_level.txt +0 -0
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
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.
|
|
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"
|
|
@@ -4440,11 +4440,11 @@ class Generator:
|
|
|
4440
4440
|
return self.binary(expression, ">=")
|
|
4441
4441
|
|
|
4442
4442
|
def is_sql(self, expression: exp.Is) -> str:
|
|
4443
|
+
negate = expression.args.get("negate")
|
|
4443
4444
|
if not self.IS_BOOL_ALLOWED and isinstance(expression.expression, exp.Boolean):
|
|
4444
|
-
|
|
4445
|
-
|
|
4446
|
-
|
|
4447
|
-
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")
|
|
4448
4448
|
|
|
4449
4449
|
def _like_sql(
|
|
4450
4450
|
self,
|
|
@@ -5674,7 +5674,11 @@ class Generator:
|
|
|
5674
5674
|
|
|
5675
5675
|
def arrayagg_sql(self, expression: exp.ArrayAgg) -> str:
|
|
5676
5676
|
array_agg = self.function_fallback_sql(expression)
|
|
5677
|
-
|
|
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)
|
|
5678
5682
|
|
|
5679
5683
|
def slice_sql(self, expression: exp.Slice) -> str:
|
|
5680
5684
|
step = self.sql(expression, "step")
|
|
@@ -2204,6 +2204,25 @@ class DuckDBGenerator(generator.Generator):
|
|
|
2204
2204
|
"""
|
|
2205
2205
|
)
|
|
2206
2206
|
|
|
2207
|
+
# BigQuery's `x IN UNNEST(arr)` NULL semantics:
|
|
2208
|
+
# NULL IN UNNEST([1, 2]) -> NULL
|
|
2209
|
+
# 3 IN UNNEST([1, NULL]) -> NULL
|
|
2210
|
+
# 3 IN UNNEST([1, 2]) -> FALSE
|
|
2211
|
+
# 1 IN UNNEST(NULL) -> FALSE (not NULL)
|
|
2212
|
+
# 1 IN UNNEST([]) -> FALSE
|
|
2213
|
+
# The default `IN (SELECT UNNEST(...))` rewrite creates a correlated subquery
|
|
2214
|
+
# that DuckDB rejects inside non-inner joins, so a CASE expression is used instead.
|
|
2215
|
+
IN_UNNEST_TEMPLATE: exp.Expr = exp.maybe_parse(
|
|
2216
|
+
"""
|
|
2217
|
+
CASE
|
|
2218
|
+
WHEN :arr IS NULL OR ARRAY_LENGTH(:arr) = 0 THEN FALSE
|
|
2219
|
+
WHEN ARRAY_CONTAINS(:arr, :value) THEN TRUE
|
|
2220
|
+
WHEN :value IS NULL OR ARRAY_LENGTH(:arr) <> LIST_COUNT(:arr) THEN NULL
|
|
2221
|
+
ELSE FALSE
|
|
2222
|
+
END
|
|
2223
|
+
"""
|
|
2224
|
+
)
|
|
2225
|
+
|
|
2207
2226
|
STRTOK_TO_ARRAY_TEMPLATE: exp.Expr = exp.maybe_parse(
|
|
2208
2227
|
"""
|
|
2209
2228
|
CASE WHEN :delimiter IS NULL THEN NULL
|
|
@@ -3098,6 +3117,16 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3098
3117
|
|
|
3099
3118
|
return super().tablesample_sql(expression, tablesample_keyword=tablesample_keyword)
|
|
3100
3119
|
|
|
3120
|
+
def in_sql(self, expression: exp.In) -> str:
|
|
3121
|
+
unnest = expression.args.get("unnest")
|
|
3122
|
+
if unnest:
|
|
3123
|
+
return self.sql(
|
|
3124
|
+
exp.replace_placeholders(
|
|
3125
|
+
self.IN_UNNEST_TEMPLATE, arr=unnest.expressions[0], value=expression.this
|
|
3126
|
+
)
|
|
3127
|
+
)
|
|
3128
|
+
return super().in_sql(expression)
|
|
3129
|
+
|
|
3101
3130
|
def join_sql(self, expression: exp.Join) -> str:
|
|
3102
3131
|
if (
|
|
3103
3132
|
not expression.args.get("using")
|
|
@@ -3460,6 +3489,23 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3460
3489
|
)
|
|
3461
3490
|
)
|
|
3462
3491
|
|
|
3492
|
+
def arrayconcatagg_sql(self, expression: exp.ArrayConcatAgg) -> str:
|
|
3493
|
+
this = expression.this
|
|
3494
|
+
|
|
3495
|
+
if isinstance(this, exp.Limit):
|
|
3496
|
+
self.unsupported("LIMIT in ARRAY_CONCAT_AGG cannot be transpiled to DuckDB")
|
|
3497
|
+
this = this.this
|
|
3498
|
+
|
|
3499
|
+
inner = this.this if isinstance(this, exp.Order) else this
|
|
3500
|
+
|
|
3501
|
+
return self.func(
|
|
3502
|
+
"FLATTEN",
|
|
3503
|
+
exp.Filter(
|
|
3504
|
+
this=exp.ArrayAgg(this=this),
|
|
3505
|
+
expression=exp.Where(this=inner.copy().is_(exp.null()).not_()),
|
|
3506
|
+
),
|
|
3507
|
+
)
|
|
3508
|
+
|
|
3463
3509
|
def arrayunionagg_sql(self, expression: exp.ArrayUnionAgg) -> str:
|
|
3464
3510
|
self.unsupported("ARRAY_UNION_AGG is not supported in DuckDB")
|
|
3465
3511
|
return self.function_fallback_sql(expression)
|
|
@@ -3917,6 +3963,12 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3917
3963
|
|
|
3918
3964
|
return super().unnest_sql(expression)
|
|
3919
3965
|
|
|
3966
|
+
def arrayagg_sql(self, expression: exp.ArrayAgg) -> str:
|
|
3967
|
+
if isinstance(expression.this, exp.Limit):
|
|
3968
|
+
self.unsupported("LIMIT inside ARRAY_AGG is not supported in DuckDB")
|
|
3969
|
+
|
|
3970
|
+
return super().arrayagg_sql(expression)
|
|
3971
|
+
|
|
3920
3972
|
def ignorenulls_sql(self, expression: exp.IgnoreNulls) -> str:
|
|
3921
3973
|
this = expression.this
|
|
3922
3974
|
|
|
@@ -3925,6 +3977,14 @@ class DuckDBGenerator(generator.Generator):
|
|
|
3925
3977
|
# window functions that accept it e.g. FIRST_VALUE(... IGNORE NULLS) OVER (...)
|
|
3926
3978
|
return super().ignorenulls_sql(expression)
|
|
3927
3979
|
|
|
3980
|
+
# For ARRAY_AGG(expr IGNORE NULLS ...), convert IGNORE NULLS to a
|
|
3981
|
+
# FILTER(WHERE expr IS NOT NULL) clause by setting nulls_excluded on
|
|
3982
|
+
# the ArrayAgg. The existing _add_arrayagg_null_filter method will
|
|
3983
|
+
# emit the FILTER clause during arrayagg_sql / withingroup_sql.
|
|
3984
|
+
if isinstance(this, exp.ArrayAgg):
|
|
3985
|
+
this.set("nulls_excluded", True)
|
|
3986
|
+
return self.sql(this)
|
|
3987
|
+
|
|
3928
3988
|
if isinstance(this, exp.First):
|
|
3929
3989
|
this = exp.AnyValue(this=this.this)
|
|
3930
3990
|
|
|
@@ -45,27 +45,35 @@ HIVE_TIME_FORMAT = "'yyyy-MM-dd HH:mm:ss'"
|
|
|
45
45
|
HIVE_DATE_FORMAT = "'yyyy-MM-dd'"
|
|
46
46
|
HIVE_DATEINT_FORMAT = "'yyyyMMdd'"
|
|
47
47
|
|
|
48
|
-
# The default formats above, as rendered by the lenient rewrite (non-padded month/day)
|
|
49
|
-
HIVE_NON_PADDED_TIME_FORMATS = ("'yyyy-M-d
|
|
48
|
+
# The default formats above, as rendered by the lenient rewrite (non-padded month/day/time)
|
|
49
|
+
HIVE_NON_PADDED_TIME_FORMATS = ("'yyyy-M-d H:m:s'", "'yyyy-M-d'")
|
|
50
50
|
|
|
51
51
|
# Expressions that parse a string with a format (vs. formatting one, like TimeToStr).
|
|
52
52
|
PARSE_TIME_EXPRESSIONS = (exp.StrToTime, exp.StrToDate, exp.StrToUnix, exp.TsOrDsToDate)
|
|
53
53
|
|
|
54
|
-
CANONICAL_TIME_FORMAT = re.compile(r"%(?:
|
|
54
|
+
CANONICAL_TIME_FORMAT = re.compile(r"%(?:[mdHIMS]strict|[-:].|.)")
|
|
55
55
|
|
|
56
|
-
LAX_TO_NON_PADDED_FORMATS = {
|
|
56
|
+
LAX_TO_NON_PADDED_FORMATS = {
|
|
57
|
+
"%m": "%-m",
|
|
58
|
+
"%d": "%-d",
|
|
59
|
+
"%H": "%-H",
|
|
60
|
+
"%I": "%-I",
|
|
61
|
+
"%M": "%-M",
|
|
62
|
+
"%S": "%-S",
|
|
63
|
+
}
|
|
57
64
|
|
|
58
65
|
|
|
59
66
|
def _lenient_parse_format(fmt: str) -> str:
|
|
60
67
|
"""
|
|
61
|
-
Changes
|
|
62
|
-
parses with or without a leading zero. This is only safe
|
|
63
|
-
adjacent fields parse greedily, so e.g. 'yyyyMd' (from
|
|
68
|
+
Changes a lax month/day/hour/minute/second in a canonical format to its non-padded form
|
|
69
|
+
(e.g. %m -> %-m), which java.time parses with or without a leading zero. This is only safe
|
|
70
|
+
for delimited specifiers, because adjacent fields parse greedily, so e.g. 'yyyyMd' (from
|
|
71
|
+
'%Y%m%d') can't even parse '20200101'.
|
|
64
72
|
|
|
65
73
|
The format is decomposed into specifiers (`formats`) and the interleaved literal text (`parts`).
|
|
66
|
-
Specifier i sits between parts[i] and parts[i + 1]. A
|
|
67
|
-
don't touch a digit run, i.e., neither side is another specifier or a literal digit.
|
|
68
|
-
the pieces are zipped back together to produce the rewritten canonical format.
|
|
74
|
+
Specifier i sits between parts[i] and parts[i + 1]. A specifier is changed only when its
|
|
75
|
+
neighbors don't touch a digit run, i.e., neither side is another specifier or a literal digit.
|
|
76
|
+
At the end, the pieces are zipped back together to produce the rewritten canonical format.
|
|
69
77
|
"""
|
|
70
78
|
parts = CANONICAL_TIME_FORMAT.split(fmt)
|
|
71
79
|
formats = CANONICAL_TIME_FORMAT.findall(fmt)
|
|
@@ -175,7 +183,8 @@ def _is_cast_time_format(self: HiveGenerator, expression: exp.Expr, time_format:
|
|
|
175
183
|
return True
|
|
176
184
|
|
|
177
185
|
if time_format in HIVE_NON_PADDED_TIME_FORMATS:
|
|
178
|
-
# The base render skips the lenient rewrite: a lax
|
|
186
|
+
# The base render skips the lenient rewrite: a lax specifier pads back (e.g. %m -> MM),
|
|
187
|
+
# an explicit non-padded specifier (e.g. %-m) doesn't
|
|
179
188
|
padded_format = generator.Generator.format_time(self, expression)
|
|
180
189
|
return padded_format in (HIVE_TIME_FORMAT, HIVE_DATE_FORMAT)
|
|
181
190
|
|
|
@@ -93,7 +93,9 @@ class PythonGenerator(generator.Generator):
|
|
|
93
93
|
exp.In: lambda self, e: f"{self.sql(e, 'this')} in {{{self.expressions(e, flat=True)}}}",
|
|
94
94
|
exp.Interval: lambda self, e: f"INTERVAL({self.sql(e.this)}, '{self.sql(e.unit)}')",
|
|
95
95
|
exp.Is: lambda self, e: (
|
|
96
|
-
self.binary(e, "
|
|
96
|
+
self.binary(e, "!=" if e.args.get("negate") else "==")
|
|
97
|
+
if isinstance(e.this, exp.Literal)
|
|
98
|
+
else self.binary(e, "is not" if e.args.get("negate") else "is")
|
|
97
99
|
),
|
|
98
100
|
exp.JSONExtract: lambda self, e: self.func(e.key, e.this, e.expression, *e.expressions),
|
|
99
101
|
exp.JSONPath: lambda self, e: f"[{','.join(self.sql(p) for p in e.expressions[1:])}]",
|
|
@@ -378,9 +378,10 @@ class TSQLGenerator(generator.Generator):
|
|
|
378
378
|
return "(1 = 1)" if expression.this else "(1 = 0)"
|
|
379
379
|
|
|
380
380
|
def is_sql(self, expression: exp.Is) -> str:
|
|
381
|
+
negate = expression.args.get("negate")
|
|
381
382
|
if isinstance(expression.expression, exp.Boolean):
|
|
382
|
-
return self.binary(expression, "=")
|
|
383
|
-
return self.binary(expression, "IS")
|
|
383
|
+
return self.binary(expression, "<>" if negate else "=")
|
|
384
|
+
return self.binary(expression, "IS NOT" if negate else "IS")
|
|
384
385
|
|
|
385
386
|
def createable_sql(self, expression: exp.Create, locations: defaultdict) -> str:
|
|
386
387
|
sql = self.sql(expression, "this")
|
|
@@ -245,7 +245,8 @@ def canonicalize_internal_names(expression: E) -> E:
|
|
|
245
245
|
output_map: dict[str, str] = {}
|
|
246
246
|
if isinstance(scope_expr, exp.Select):
|
|
247
247
|
for sel in scope_expr.selects:
|
|
248
|
-
|
|
248
|
+
# Sets default name for subquery projections, both aliased and unaliased
|
|
249
|
+
if isinstance(sel, (exp.Alias, exp.Subquery)) and sel.alias:
|
|
249
250
|
old_alias = sel.alias
|
|
250
251
|
if is_output_scope:
|
|
251
252
|
new_name = old_alias
|
|
@@ -32,7 +32,7 @@ def qualify(
|
|
|
32
32
|
quote_identifiers: bool = True,
|
|
33
33
|
identify: bool = True,
|
|
34
34
|
canonicalize_table_aliases: bool = False,
|
|
35
|
-
on_qualify: t.Callable[[exp.
|
|
35
|
+
on_qualify: t.Callable[[exp.Table], None] | None = None,
|
|
36
36
|
sql: str | None = None,
|
|
37
37
|
) -> E:
|
|
38
38
|
"""
|
|
@@ -819,18 +819,29 @@ def _expand_stars(
|
|
|
819
819
|
for expression in scope_expression.selects:
|
|
820
820
|
tables: list[str] = []
|
|
821
821
|
if isinstance(expression, exp.Star):
|
|
822
|
+
# Only a string literal ILIKE pattern can filter the expansion at optimization time
|
|
823
|
+
ilike = expression.args.get("ilike")
|
|
824
|
+
if ilike and not ilike.is_string:
|
|
825
|
+
new_selections.append(expression)
|
|
826
|
+
continue
|
|
827
|
+
|
|
822
828
|
tables.extend(scope.selected_sources)
|
|
823
829
|
_add_except_columns(expression, tables, except_columns)
|
|
824
830
|
_add_replace_columns(expression, tables, replace_columns)
|
|
825
831
|
_add_rename_columns(expression, tables, rename_columns)
|
|
826
|
-
ilike_pattern = _add_ilike_columns(expression)
|
|
832
|
+
ilike_pattern = _add_ilike_columns(expression, dialect)
|
|
827
833
|
elif expression.is_star:
|
|
828
834
|
if isinstance(expression, exp.Column):
|
|
835
|
+
ilike = expression.this.args.get("ilike")
|
|
836
|
+
if ilike and not ilike.is_string:
|
|
837
|
+
new_selections.append(expression)
|
|
838
|
+
continue
|
|
839
|
+
|
|
829
840
|
tables.append(expression.table)
|
|
830
841
|
_add_except_columns(expression.this, tables, except_columns)
|
|
831
842
|
_add_replace_columns(expression.this, tables, replace_columns)
|
|
832
843
|
_add_rename_columns(expression.this, tables, rename_columns)
|
|
833
|
-
ilike_pattern = _add_ilike_columns(expression.this)
|
|
844
|
+
ilike_pattern = _add_ilike_columns(expression.this, dialect)
|
|
834
845
|
elif isinstance(expression, exp.Dot):
|
|
835
846
|
if dialect.REQUIRES_PARENTHESIZED_STRUCT_ACCESS:
|
|
836
847
|
struct_fields = _expand_struct_stars_with_parens(expression)
|
|
@@ -861,7 +872,10 @@ def _expand_stars(
|
|
|
861
872
|
if pseudocolumns and dialect.EXCLUDES_PSEUDOCOLUMNS_FROM_STAR:
|
|
862
873
|
columns = [name for name in columns if name.upper() not in pseudocolumns]
|
|
863
874
|
|
|
864
|
-
|
|
875
|
+
# If a source exposes duplicate output names (e.g. a derived table re-exposing
|
|
876
|
+
# colliding star-expanded columns), expanding this star would produce ambiguous
|
|
877
|
+
# projections, so we leave it unexpanded.
|
|
878
|
+
if not columns or "*" in columns or len(columns) != len(set(columns)):
|
|
865
879
|
return
|
|
866
880
|
|
|
867
881
|
table_id = id(table)
|
|
@@ -943,13 +957,33 @@ def _output_identifier_quoted(selection: exp.Expr) -> bool:
|
|
|
943
957
|
return isinstance(identifier, exp.Identifier) and identifier.quoted
|
|
944
958
|
|
|
945
959
|
|
|
946
|
-
def _add_ilike_columns(expression: exp.Expr) -> str | None:
|
|
960
|
+
def _add_ilike_columns(expression: exp.Expr, dialect: Dialect) -> str | None:
|
|
947
961
|
ilike = expression.args.get("ilike")
|
|
948
962
|
|
|
949
963
|
if not ilike:
|
|
950
964
|
return None
|
|
951
965
|
|
|
952
|
-
|
|
966
|
+
i = 0
|
|
967
|
+
chars = []
|
|
968
|
+
pattern = ilike.name
|
|
969
|
+
len_pattern = len(pattern)
|
|
970
|
+
|
|
971
|
+
while i < len_pattern:
|
|
972
|
+
c = pattern[i]
|
|
973
|
+
|
|
974
|
+
if c == "\\" and dialect.STAR_ILIKE_BACKSLASH_ESCAPE and i + 1 < len_pattern:
|
|
975
|
+
i += 1
|
|
976
|
+
chars.append(re.escape(pattern[i]))
|
|
977
|
+
elif c == "%":
|
|
978
|
+
chars.append(".*")
|
|
979
|
+
elif c == "_":
|
|
980
|
+
chars.append(".")
|
|
981
|
+
else:
|
|
982
|
+
chars.append(re.escape(c))
|
|
983
|
+
|
|
984
|
+
i += 1
|
|
985
|
+
|
|
986
|
+
return "".join(chars)
|
|
953
987
|
|
|
954
988
|
|
|
955
989
|
def _add_except_columns(expression: exp.Expr, tables, except_columns: dict[int, set[str]]) -> None:
|
|
@@ -1020,15 +1054,28 @@ def qualify_outputs(scope_or_expression: Scope | exp.Expr, dialect: Dialect) ->
|
|
|
1020
1054
|
dialect.normalize_identifier(alias_identifier)
|
|
1021
1055
|
selection.set("alias", exp.TableAlias(this=alias_identifier))
|
|
1022
1056
|
elif not isinstance(selection, (exp.Alias, exp.Aliases)) and not selection.is_star:
|
|
1023
|
-
|
|
1057
|
+
unwrapped = selection.unnest()
|
|
1058
|
+
if isinstance(unwrapped, exp.Column):
|
|
1059
|
+
source_identifier = unwrapped.this
|
|
1060
|
+
elif isinstance(unwrapped, exp.Dot):
|
|
1061
|
+
source_identifier = unwrapped.expression
|
|
1062
|
+
else:
|
|
1063
|
+
source_identifier = None
|
|
1064
|
+
|
|
1024
1065
|
selection = alias(
|
|
1025
1066
|
selection,
|
|
1026
1067
|
alias=selection.output_name or f"_col_{i}",
|
|
1027
1068
|
copy=False,
|
|
1028
1069
|
)
|
|
1029
|
-
if
|
|
1030
|
-
|
|
1031
|
-
|
|
1070
|
+
if isinstance(source_identifier, exp.Identifier):
|
|
1071
|
+
# The alias copies the exact spelling of an existing identifier, so folding it
|
|
1072
|
+
# here would desync it from other occurrences of that identifier; its casing
|
|
1073
|
+
# is `normalize_identifiers`' concern, which has already run (or was skipped
|
|
1074
|
+
# deliberately) by this point
|
|
1075
|
+
if source_identifier.quoted:
|
|
1076
|
+
selection.args["alias"].set("quoted", True)
|
|
1077
|
+
else:
|
|
1078
|
+
dialect.normalize_identifier(selection.args["alias"])
|
|
1032
1079
|
if aliased_column:
|
|
1033
1080
|
selection.set("alias", exp.to_identifier(aliased_column))
|
|
1034
1081
|
|
|
@@ -332,6 +332,8 @@ def eval_boolean(
|
|
|
332
332
|
expression: object, a: SupportsComparison, b: SupportsComparison
|
|
333
333
|
) -> exp.Boolean | None:
|
|
334
334
|
if isinstance(expression, (exp.EQ, exp.Is)):
|
|
335
|
+
if isinstance(expression, exp.Is) and expression.args.get("negate"):
|
|
336
|
+
return boolean_literal(a != b)
|
|
335
337
|
return boolean_literal(a == b)
|
|
336
338
|
if isinstance(expression, exp.NEQ):
|
|
337
339
|
return boolean_literal(a != b)
|
|
@@ -892,8 +894,11 @@ class Simplifier:
|
|
|
892
894
|
self, expression: exp.Expr, left: exp.Expr, right: exp.Expr, or_: bool = False
|
|
893
895
|
) -> exp.Expr | None:
|
|
894
896
|
if isinstance(left, self.COMPARISONS) and isinstance(right, self.COMPARISONS):
|
|
895
|
-
|
|
896
|
-
|
|
897
|
+
if any(isinstance(e, exp.Is) and e.args.get("negate") for e in (left, right)):
|
|
898
|
+
return None
|
|
899
|
+
|
|
900
|
+
ll, lr = left.this, left.expression
|
|
901
|
+
rl, rr = right.this, right.expression
|
|
897
902
|
|
|
898
903
|
largs = {ll, lr}
|
|
899
904
|
rargs = {rl, rr}
|
|
@@ -1194,6 +1199,9 @@ class Simplifier:
|
|
|
1194
1199
|
c = b
|
|
1195
1200
|
not_ = False
|
|
1196
1201
|
|
|
1202
|
+
if expression.args.get("negate"):
|
|
1203
|
+
not_ = not not_
|
|
1204
|
+
|
|
1197
1205
|
if is_null(c):
|
|
1198
1206
|
if isinstance(a, exp.Literal):
|
|
1199
1207
|
return exp.true() if not_ else exp.false()
|
|
@@ -1699,7 +1707,7 @@ class Gen:
|
|
|
1699
1707
|
self._binary(e, " DIV ")
|
|
1700
1708
|
|
|
1701
1709
|
def is_sql(self, e: exp.Is) -> None:
|
|
1702
|
-
self._binary(e, " IS ")
|
|
1710
|
+
self._binary(e, " IS NOT " if e.args.get("negate") else " IS ")
|
|
1703
1711
|
|
|
1704
1712
|
def like_sql(self, e: exp.Like) -> None:
|
|
1705
1713
|
self._binary(e, " NOT Like " if e.args.get("negate") else " Like ")
|
|
@@ -742,6 +742,7 @@ class Parser:
|
|
|
742
742
|
TokenType.OFFSET,
|
|
743
743
|
TokenType.OPERATOR,
|
|
744
744
|
TokenType.ORDINALITY,
|
|
745
|
+
TokenType.OUT,
|
|
745
746
|
TokenType.OVER,
|
|
746
747
|
TokenType.OVERLAPS,
|
|
747
748
|
TokenType.OVERWRITE,
|
|
@@ -1018,7 +1019,10 @@ class Parser:
|
|
|
1018
1019
|
)
|
|
1019
1020
|
),
|
|
1020
1021
|
TokenType.FARROW: lambda self, expressions: self.expression(
|
|
1021
|
-
exp.Kwarg(
|
|
1022
|
+
exp.Kwarg(
|
|
1023
|
+
this=exp.var(expressions[0].name),
|
|
1024
|
+
expression=self._parse_disjunction() or self._parse_select(),
|
|
1025
|
+
)
|
|
1022
1026
|
),
|
|
1023
1027
|
}
|
|
1024
1028
|
|
|
@@ -3542,6 +3546,38 @@ class Parser:
|
|
|
3542
3546
|
|
|
3543
3547
|
this = self._parse_function() if is_function else self._parse_insert_table()
|
|
3544
3548
|
|
|
3549
|
+
# MySQL's INSERT ... SET is normalized into the INSERT ... (cols) VALUES (vals) variant
|
|
3550
|
+
set_values = None
|
|
3551
|
+
if self._match(TokenType.SET):
|
|
3552
|
+
columns = []
|
|
3553
|
+
values = []
|
|
3554
|
+
|
|
3555
|
+
def _parse_set_assignment() -> exp.Expr | None:
|
|
3556
|
+
target = self._parse_column()
|
|
3557
|
+
if isinstance(target, exp.Column) and self._match(TokenType.EQ):
|
|
3558
|
+
if self.dialect.SUPPORTS_VALUES_DEFAULT and self._match(TokenType.DEFAULT):
|
|
3559
|
+
value: exp.Expr | None = exp.var(self._prev.text.upper())
|
|
3560
|
+
else:
|
|
3561
|
+
value = self._parse_disjunction()
|
|
3562
|
+
|
|
3563
|
+
if value:
|
|
3564
|
+
columns.append(target.this)
|
|
3565
|
+
values.append(value)
|
|
3566
|
+
return value
|
|
3567
|
+
|
|
3568
|
+
self.raise_error("Expected column assignment in INSERT ... SET")
|
|
3569
|
+
return None
|
|
3570
|
+
|
|
3571
|
+
self._parse_csv(_parse_set_assignment)
|
|
3572
|
+
|
|
3573
|
+
this = self.expression(exp.Schema(this=this, expressions=columns))
|
|
3574
|
+
set_values = self.expression(
|
|
3575
|
+
exp.Values(
|
|
3576
|
+
expressions=[exp.Tuple(expressions=values)],
|
|
3577
|
+
alias=self._parse_table_alias(),
|
|
3578
|
+
)
|
|
3579
|
+
)
|
|
3580
|
+
|
|
3545
3581
|
returning = self._parse_returning() # TSQL allows RETURNING before source
|
|
3546
3582
|
|
|
3547
3583
|
return self.expression(
|
|
@@ -3557,7 +3593,9 @@ class Parser:
|
|
|
3557
3593
|
partition=self._match(TokenType.PARTITION_BY) and self._parse_partitioned_by(),
|
|
3558
3594
|
settings=self._match_text_seq("SETTINGS") and self._parse_settings_property(),
|
|
3559
3595
|
default=self._match_text_seq("DEFAULT", "VALUES"),
|
|
3560
|
-
expression=
|
|
3596
|
+
expression=set_values
|
|
3597
|
+
or self._parse_derived_table_values()
|
|
3598
|
+
or self._parse_ddl_select(),
|
|
3561
3599
|
conflict=self._parse_on_conflict(),
|
|
3562
3600
|
returning=returning or self._parse_returning(),
|
|
3563
3601
|
overwrite=overwrite,
|
|
@@ -5912,8 +5950,11 @@ class Parser:
|
|
|
5912
5950
|
elif self._match(TokenType.NOTNULL):
|
|
5913
5951
|
# Postgres supports ISNULL and NOTNULL for conditions.
|
|
5914
5952
|
# https://blog.andreiavram.ro/postgresql-null-composite-type/
|
|
5915
|
-
|
|
5916
|
-
|
|
5953
|
+
if self.dialect.NORMALIZE_NOT_NULL:
|
|
5954
|
+
this = self.expression(exp.Is(this=this, expression=exp.Null()))
|
|
5955
|
+
this = self.expression(exp.Not(this=this))
|
|
5956
|
+
else:
|
|
5957
|
+
this = self.expression(exp.Is(this=this, expression=exp.Null(), negate=True))
|
|
5917
5958
|
else:
|
|
5918
5959
|
if negate:
|
|
5919
5960
|
self._retreat(self._index - 1)
|
|
@@ -5969,8 +6010,12 @@ class Parser:
|
|
|
5969
6010
|
self._retreat(index)
|
|
5970
6011
|
return None
|
|
5971
6012
|
|
|
5972
|
-
|
|
5973
|
-
|
|
6013
|
+
if negate and isinstance(expression, exp.Null) and not self.dialect.NORMALIZE_NOT_NULL:
|
|
6014
|
+
this = self.expression(exp.Is(this=this, expression=expression, negate=True))
|
|
6015
|
+
else:
|
|
6016
|
+
this = self.expression(exp.Is(this=this, expression=expression))
|
|
6017
|
+
this = self.expression(exp.Not(this=this)) if negate else this
|
|
6018
|
+
|
|
5974
6019
|
return self._parse_column_ops(this)
|
|
5975
6020
|
|
|
5976
6021
|
def _parse_in(self, this: exp.Expr | None, alias: bool = False) -> exp.In:
|
|
@@ -9737,7 +9782,11 @@ class Parser:
|
|
|
9737
9782
|
this.set("unpack", True)
|
|
9738
9783
|
return this
|
|
9739
9784
|
|
|
9785
|
+
index = self._index
|
|
9740
9786
|
ilike = self._parse_string() if self._match(TokenType.ILIKE) else None
|
|
9787
|
+
if not ilike:
|
|
9788
|
+
# ILIKE without a string pattern is not a star filter, e.g. `* ILIKE (foo)`
|
|
9789
|
+
self._retreat(index)
|
|
9741
9790
|
|
|
9742
9791
|
return self.expression(
|
|
9743
9792
|
exp.Star(
|
|
@@ -129,6 +129,7 @@ class DuckDBParser(parser.Parser):
|
|
|
129
129
|
),
|
|
130
130
|
"EPOCH": exp.TimeToUnix.from_arg_list,
|
|
131
131
|
"EPOCH_MS": lambda args: exp.UnixToTime(this=seq_get(args, 0), scale=exp.UnixToTime.MILLIS),
|
|
132
|
+
"FROM_HEX": exp.Unhex.from_arg_list,
|
|
132
133
|
"GENERATE_SERIES": _build_generate_series(),
|
|
133
134
|
"GET_CURRENT_TIME": exp.CurrentTime.from_arg_list,
|
|
134
135
|
"GET_BIT": lambda args: exp.Getbit(
|
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sqlglotc
|
|
3
|
-
Version: 30.
|
|
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.
|
|
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"
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|