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 @@ -13,6 +13,7 @@
- Fix DBR capability cache being permanently poisoned by a transient version-query failure ([#1398](https://github.com/databricks/dbt-databricks/issues/1398))
- Fix spurious `use_managed_iceberg` behavior-change warning firing on every run for projects that don't use Iceberg ([#1266](https://github.com/databricks/dbt-databricks/issues/1266))
- Warn when `contract.enforced: true` is set on a `materialized_view` model ([#1279](https://github.com/databricks/dbt-databricks/issues/1279))
- Fix `materialized_view` models with `databricks_tags` silently going stale on `dbt run`. `MaterializedViewAPI._describe_relation` was not fetching `information_schema.tags`, so existing tags always parsed as empty, producing a spurious tag diff that routed the materialization to `ALTER ... SET TAGS` instead of `REFRESH MATERIALIZED VIEW` ([#1419](https://github.com/databricks/dbt-databricks/issues/1419))

## dbt-databricks 1.11.7 (Apr 17, 2026)

Expand Down
1 change: 1 addition & 0 deletions dbt/adapters/databricks/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -1091,6 +1091,7 @@ def _describe_relation(
results["information_schema.views"] = get_first_row(
adapter.execute_macro("get_view_description", kwargs=kwargs)
)
results["information_schema.tags"] = adapter.execute_macro("fetch_tags", kwargs=kwargs)
results["show_tblproperties"] = adapter.execute_macro("fetch_tbl_properties", kwargs=kwargs)
return results

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
import pytest
from dbt.adapters.base import BaseRelation
from dbt.tests import util

from dbt.adapters.databricks.relation import DatabricksRelationType

SEED_CSV = """id,value
1,100
2,200
""".lstrip()

MV_WITH_TAGS = """
{{ config(
materialized='materialized_view',
on_configuration_change='apply',
databricks_tags={'deployment': 'DBT'},
) }}
select * from {{ ref('mv_seed') }}
"""


@pytest.mark.dlt
@pytest.mark.skip_profile("databricks_cluster", "databricks_uc_cluster")
class TestMaterializedViewRefreshesWithTags:
@pytest.fixture(scope="class")
def seeds(self):
return {"mv_seed.csv": SEED_CSV}

@pytest.fixture(scope="class")
def models(self):
return {"mv_with_tags.sql": MV_WITH_TAGS}

@staticmethod
def _row_count(project, relation: BaseRelation) -> int:
return project.run_sql(f"select count(*) from {relation}", fetch="one")[0]

def test_mv_refreshes_on_rerun_when_tags_set(self, project):
util.run_dbt(["seed"])
util.run_dbt(["run", "--models", "mv_with_tags"])

mv = project.adapter.Relation.create(
identifier="mv_with_tags",
schema=project.test_schema,
database=project.database,
type=DatabricksRelationType.MaterializedView,
)
seed = project.adapter.Relation.create(
identifier="mv_seed",
schema=project.test_schema,
database=project.database,
)

assert self._row_count(project, mv) == 2

project.run_sql(f"insert into {seed} values (3, 300)")
assert self._row_count(project, mv) == 2

util.run_dbt(["run", "--models", "mv_with_tags"])

# get_relation_config goes through DeltaLiveTableAPIBase.get_from_relation,
# which polls the DLT pipeline until any in-flight refresh completes.
with util.get_connection(project.adapter):
project.adapter.get_relation_config(mv)

assert self._row_count(project, mv) == 3, "MV not refreshed on rerun."
17 changes: 16 additions & 1 deletion tests/unit/relation_configs/test_materialized_view_config.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
from unittest.mock import Mock
from unittest.mock import MagicMock, Mock

from agate import Row, Table

from dbt.adapters.databricks.impl import MaterializedViewAPI
from dbt.adapters.databricks.relation_configs.comment import CommentConfig
from dbt.adapters.databricks.relation_configs.liquid_clustering import LiquidClusteringConfig
from dbt.adapters.databricks.relation_configs.materialized_view import (
Expand Down Expand Up @@ -144,3 +145,17 @@ def test_get_changeset__some_changes(self):
"refresh": RefreshConfig(cron="*/5 * * * *"),
"tags": TagsConfig(set_tags={"a": "b", "c": "d"}),
}


class TestMaterializedViewAPIDescribeRelation:
def test_describe_relation_fetches_tags(self):
# Without fetching tags here, an MV with `databricks_tags` would show a
# spurious tag diff on every run, routing to ALTER instead of REFRESH.
adapter = MagicMock()
adapter.execute_macro.return_value = MagicMock()

results = MaterializedViewAPI._describe_relation(adapter, MagicMock())

assert "information_schema.tags" in results
macro_names = {call.args[0] for call in adapter.execute_macro.call_args_list}
assert "fetch_tags" in macro_names
Loading