Skip to content

Commit c5d008b

Browse files
authored
fix(clickhouse): combine physical_properties into one SETTINGS clause (#5817)
Signed-off-by: mokashang <shangmengjiajiajia@gmail.com>
1 parent 0a5980c commit c5d008b

2 files changed

Lines changed: 42 additions & 8 deletions

File tree

sqlmesh/core/engine_adapter/clickhouse.py

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -716,8 +716,12 @@ def use_server_nulls_for_unmatched_after_join(
716716
return query
717717

718718
def _build_settings_property(
719-
self, key: str, value: exp.Expr | str | int | float
719+
self, settings: t.Mapping[str, exp.Expr | str | int | float]
720720
) -> exp.SettingsProperty:
721+
# ClickHouse requires every key=value pair to live under a single
722+
# SETTINGS clause (`SETTINGS a = 1, b = 2`). Emitting one
723+
# SettingsProperty per pair produces repeated SETTINGS keywords and a
724+
# syntax error at execution time.
721725
return exp.SettingsProperty(
722726
expressions=[
723727
exp.EQ(
@@ -726,6 +730,7 @@ def _build_settings_property(
726730
if isinstance(value, exp.Expr)
727731
else exp.Literal(this=value, is_string=isinstance(value, str)),
728732
)
733+
for key, value in settings.items()
729734
]
730735
)
731736

@@ -827,9 +832,7 @@ def _build_table_properties_exp(
827832
properties.append(exp.EmptyProperty())
828833

829834
if table_properties_copy:
830-
properties.extend(
831-
[self._build_settings_property(k, v) for k, v in table_properties_copy.items()]
832-
)
835+
properties.append(self._build_settings_property(table_properties_copy))
833836

834837
if table_description:
835838
properties.append(
@@ -858,9 +861,7 @@ def _build_view_properties_exp(
858861
properties.append(exp.OnCluster(this=exp.to_identifier(self.cluster)))
859862

860863
if view_properties_copy:
861-
properties.extend(
862-
[self._build_settings_property(k, v) for k, v in view_properties_copy.items()]
863-
)
864+
properties.append(self._build_settings_property(view_properties_copy))
864865

865866
if table_description:
866867
properties.append(

tests/core/engine_adapter/test_clickhouse.py

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -316,13 +316,32 @@ def build_properties_sql(storage_format="", order_by="", primary_key="", propert
316316
== "ENGINE=MergeTree ORDER BY (a, b + 1) PRIMARY KEY (a, b)"
317317
)
318318

319+
# Multiple physical_properties must be combined into a single comma-separated
320+
# SETTINGS clause. ClickHouse rejects repeated SETTINGS keywords with a syntax
321+
# error (see https://github.com/SQLMesh/sqlmesh/issues/5803).
319322
assert (
320323
build_properties_sql(
321324
order_by="ORDER_BY = (a, b + 1),",
322325
primary_key="PRIMARY_KEY = (a, b),",
323326
properties="PROP1 = 1, PROP2 = '2'",
324327
)
325-
== "ENGINE=MergeTree ORDER BY (a, b + 1) PRIMARY KEY (a, b) SETTINGS prop1 = 1 SETTINGS prop2 = '2'"
328+
== "ENGINE=MergeTree ORDER BY (a, b + 1) PRIMARY KEY (a, b) SETTINGS prop1 = 1, prop2 = '2'"
329+
)
330+
331+
# Regression test for #5803: three or more SETTINGS entries also combine.
332+
assert (
333+
build_properties_sql(
334+
order_by="ORDER_BY = (orders_id),",
335+
properties=(
336+
"min_age_to_force_merge_seconds = 3600, "
337+
"min_age_to_force_merge_on_partition_only = 1, "
338+
"index_granularity = 8192"
339+
),
340+
)
341+
== "ENGINE=MergeTree ORDER BY (orders_id) "
342+
"SETTINGS min_age_to_force_merge_seconds = 3600, "
343+
"min_age_to_force_merge_on_partition_only = 1, "
344+
"index_granularity = 8192"
326345
)
327346

328347
assert (
@@ -345,6 +364,20 @@ def build_properties_sql(storage_format="", order_by="", primary_key="", propert
345364
)
346365

347366

367+
def test_view_properties_combine_settings(adapter: ClickhouseEngineAdapter):
368+
# View properties hit the same SettingsProperty code path as table
369+
# properties (#5803): multiple entries must collapse into one SETTINGS
370+
# clause rather than emit repeated SETTINGS keywords.
371+
view_properties_exp = adapter._build_view_properties_exp(
372+
view_properties={
373+
"prop1": exp.Literal.number(1),
374+
"prop2": exp.Literal.string("2"),
375+
}
376+
)
377+
assert view_properties_exp is not None
378+
assert view_properties_exp.sql("clickhouse") == "SETTINGS prop1 = 1, prop2 = '2'"
379+
380+
348381
def test_partitioned_by_expr(make_mocked_engine_adapter: t.Callable):
349382
# user doesn't specify, unknown time column type
350383
model = load_sql_based_model(

0 commit comments

Comments
 (0)