Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
- Add `skip_optimize` model config to opt out of the post-materialization `OPTIMIZE` call without dropping `zorder` / `liquid_clustered_by` / `auto_liquid_cluster` from the table definition. Useful when `OPTIMIZE` is delegated to Predictive Optimization or scheduled out of band. Complements the existing run-wide `DATABRICKS_SKIP_OPTIMIZE` var by allowing project-, folder-, or model-level opt-out via standard dbt config inheritance ([#703](https://github.com/databricks/dbt-databricks/issues/703)).

### Fixes
- Honor the `expression` field on `primary_key` constraints on the V1 materialization path. A primary key declared with `expression: RELY` (or any trailing clause) previously had its expression silently dropped — the key was created without it. ([#1551](https://github.com/databricks/dbt-databricks/pull/1551))
- Apply column-level `databricks_tags` for incremental models on the V1 materialization path (`use_materialization_v2: false`, the default). They were silently dropped at create and on subsequent tag changes; the V1 incremental materialization now applies them, matching the `table` materialization and the V2 path. ([#1520](https://github.com/databricks/dbt-databricks/pull/1520) closes [#1307](https://github.com/databricks/dbt-databricks/issues/1307))
- Raise a `DbtRuntimeError` when a Python model job run terminates with a non-success `result_state` (e.g. `FAILED`/`TIMEDOUT`) instead of returning silently ([#1477](https://github.com/databricks/dbt-databricks/pull/1477))

Expand Down
10 changes: 8 additions & 2 deletions dbt/include/databricks/macros/relations/constraints.sql
Original file line number Diff line number Diff line change
Expand Up @@ -168,17 +168,23 @@
{% endfor %}

{% set joined_names = quoted_names|join(", ") %}
{% set pk_expression = constraint.get('expression') %}

{% set name = constraint.get('name') %}
{% if not name %}
{% if local_md5 %}
{{ exceptions.warn("Constraint of type " ~ type ~ " with no `name` provided. Generating hash instead for relation " ~ relation.identifier) }}
{%- set name = local_md5("primary_key;" ~ relation.identifier ~ ";" ~ column_names ~ ";") -%}
{%- set hash_input = "primary_key;" ~ relation.identifier ~ ";" ~ column_names ~ ";" -%}
{%- if pk_expression -%}
{%- set hash_input = hash_input ~ pk_expression ~ ";" -%}
{%- endif -%}
{%- set name = local_md5(hash_input) -%}
{% else %}
{{ exceptions.raise_compiler_error("Constraint of type " ~ type ~ " with no `name` provided, and no md5 utility.") }}
{% endif %}
{% endif %}
{% set stmt = "alter table " ~ relation.render() ~ " add constraint " ~ name ~ " primary key(" ~ joined_names ~ ");" %}
{% set pk_suffix = (" " ~ pk_expression) if pk_expression else "" %}
{% set stmt = "alter table " ~ relation.render() ~ " add constraint " ~ name ~ " primary key(" ~ joined_names ~ ")" ~ pk_suffix ~ ";" %}
{% do statements.append(stmt) %}
{% elif type == 'foreign_key' %}

Expand Down
33 changes: 33 additions & 0 deletions tests/unit/macros/relations/test_constraint_macros.py
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,23 @@ def test_macros_get_constraint_sql_primary_key(self, template_bundle, model):
)
assert expected in r

def test_macros_get_constraint_sql_primary_key_with_expression(self, template_bundle, model):
# `expression` trails the key list (e.g. RELY), matching the foreign_key branch.
constraint = {
"type": "primary_key",
"name": "myconstraint",
"columns": ["name"],
"expression": "RELY",
}
r = self.render_constraint_sql(template_bundle, constraint, model)

# clean_sql() lowercases the rendered SQL, so the expression is matched as `rely`.
expected = (
"['alter table `some_database`.`some_schema`.`some_table` add constraint "
"myconstraint primary key(`name`) rely;']"
)
assert expected in r

def test_macros_get_constraint_sql_primary_key_with_specified_column(
self, template_bundle, model
):
Expand Down Expand Up @@ -321,6 +338,22 @@ def test_macros_get_constraint_sql_primary_key_noname(self, template_bundle, mod
)
assert expected in r

def test_macros_get_constraint_sql_primary_key_noname_with_expression(
self, template_bundle, model
):
constraint = {"type": "primary_key", "expression": "RELY"}
column = {"name": "id"}

r = self.render_constraint_sql(template_bundle, constraint, model, column)

# clean_sql() lowercases the rendered SQL, including the hash input echoed by the mock.
expected = (
'["alter table `some_database`.`some_schema`.`some_table` add constraint '
"hash(primary_key;some_table;['id'];rely;) "
'primary key(`id`) rely;"]'
)
assert expected in r

def test_macros_get_constraint_sql_foreign_key(self, template_bundle, model):
constraint = {
"type": "foreign_key",
Expand Down
Loading