Skip to content

Commit f8cd6b1

Browse files
Merge branch 'main' into let-catalogs-be-catalogs
2 parents dd63e79 + 922969c commit f8cd6b1

8 files changed

Lines changed: 87 additions & 50 deletions

File tree

CHANGELOG.md

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,17 @@
1-
## dbt-databricks 1.10.8 (TBD)
1+
## dbt-databricks 1.10.9 (TBD)
2+
3+
### Features
4+
- Support column tags for views using `ALTER TABLE`
5+
6+
## dbt-databricks 1.10.8 (August 4, 2025)
27

38
### Features
49
- Support insert_overwrite incremental strategy for SQL warehouses ([1025](https://github.com/databricks/dbt-databricks/issues/1025))
510

611
### Fixes
712
- Add fallback logic for known error types for `DESCRIBE TABLE EXTENDED .. AS JSON` for better reliability ([1128](https://github.com/databricks/dbt-databricks/issues/1128))
813
- Fix no-op logic for views that is causing some incremental materializations to be skipped ([1122](https://github.com/databricks/dbt-databricks/issues/1122))
14+
- Fix check constraints keep getting replaced [issue-1109](https://github.com/databricks/dbt-databricks/issues/1109)
915

1016
### Under the Hood
1117
- Simplify connection management to align with base adapter. Connections are no longer cached per-thread
@@ -35,7 +41,6 @@
3541
- Fix bug that causes materialization (V2) to fail when data type is long enough to be truncated by DESCRIBE TABLE ([1083](https://github.com/databricks/dbt-databricks/issues/1083))
3642
- Fix the bugs with external tabls cloning [1095](https://github.com/databricks/dbt-databricks/pull/1095) (thanks @samgans!)
3743
- Fix MV/ST materializations with complex data types ([1100](https://github.com/databricks/dbt-databricks/issues/1100))
38-
- fix: check constraints keep getting replaced [issue-1109](https://github.com/databricks/dbt-databricks/issues/1109)
3944

4045
### Under the Hood
4146

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
version = "1.10.7"
1+
version = "1.10.8"

dbt/adapters/databricks/relation_configs/view.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
DatabricksRelationConfigBase,
99
)
1010
from dbt.adapters.databricks.relation_configs.column_comments import ColumnCommentsProcessor
11+
from dbt.adapters.databricks.relation_configs.column_tags import ColumnTagsProcessor
1112
from dbt.adapters.databricks.relation_configs.comment import CommentProcessor
1213
from dbt.adapters.databricks.relation_configs.query import QueryProcessor
1314
from dbt.adapters.databricks.relation_configs.tags import TagsProcessor
@@ -21,6 +22,7 @@ class ViewConfig(DatabricksRelationConfigBase):
2122
QueryProcessor,
2223
CommentProcessor,
2324
ColumnCommentsProcessor,
25+
ColumnTagsProcessor,
2426
]
2527

2628
def get_changeset(self, existing: Self) -> Optional[DatabricksRelationChangeSet]:

dbt/include/databricks/macros/materializations/view.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@
3131
{{ get_create_view_as_sql(target_relation, sql) }}
3232
{%- endcall %}
3333
{{ apply_tags(target_relation, tags) }}
34+
{% set column_tags = adapter.get_column_tags_from_model(config.model) %}
35+
{% if column_tags and column_tags.set_column_tags %}
36+
{{ apply_column_tags(target_relation, column_tags) }}
37+
{% endif %}
3438
{% endif %}
3539
{% set should_revoke = should_revoke(exists_as_view, full_refresh_mode=True) %}
3640
{% do apply_grants(target_relation, grant_config, should_revoke=True) %}
@@ -57,6 +61,11 @@
5761

5862
{%- do apply_tags(target_relation, tags) -%}
5963

64+
{% set column_tags = adapter.get_column_tags_from_model(config.model) %}
65+
{% if column_tags and column_tags.set_column_tags %}
66+
{{ apply_column_tags(target_relation, column_tags) }}
67+
{% endif %}
68+
6069
{{ run_hooks(post_hooks) }}
6170
{% endif %}
6271

@@ -69,6 +78,11 @@
6978
{% set tags = config.get('databricks_tags') %}
7079
{{ execute_multiple_statements(get_replace_sql(existing_relation, target_relation, sql)) }}
7180
{%- do apply_tags(target_relation, tags) -%}
81+
82+
{% set column_tags = adapter.get_column_tags_from_model(config.model) %}
83+
{% if column_tags and column_tags.set_column_tags %}
84+
{{ apply_column_tags(target_relation, column_tags) }}
85+
{% endif %}
7286
{% endmacro %}
7387

7488
{% macro relation_should_be_altered(existing_relation) %}

dbt/include/databricks/macros/relations/components/column_tags.sql

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,12 @@
3434
{%- endmacro -%}
3535

3636
{% macro alter_set_column_tags(relation, column, tags) -%}
37-
ALTER {{ relation.type | replace('_', ' ') }} {{ relation.render() }}
37+
{# ALTER VIEW does not support setting column tags, but ALTER TABLE works for views #}
38+
{%- if relation.type == 'view' -%}
39+
ALTER TABLE {{ relation.render() }}
40+
{%- else -%}
41+
ALTER {{ relation.type | replace('_', ' ') }} {{ relation.render() }}
42+
{%- endif -%}
3843
ALTER COLUMN `{{ column }}`
3944
SET TAGS (
4045
{%- for tag_name, tag_value in tags.items() -%}

dbt/include/databricks/macros/relations/view/create.sql

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,9 +2,6 @@
22
{% if column_mask_exists() %}
33
{% do exceptions.raise_compiler_error("Column masks are not supported for views.") %}
44
{% endif %}
5-
{% if column_tags_exist() %}
6-
{% do exceptions.raise_compiler_error("Column tags are not supported for views.") %}
7-
{% endif %}
85
{{ log("Creating view " ~ relation) }}
96
create or replace view {{ relation.render() }}
107
{%- if config.persist_column_docs() -%}

tests/functional/adapter/column_tags/fixtures.py

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
select 1 as id, 'abc123' as account_number
33
"""
44

5-
model_with_column_tags = """
5+
initial_column_tag_model = """
66
version: 2
77
models:
88
- name: base_model
@@ -16,6 +16,22 @@
1616
sensitive: "true"
1717
"""
1818

19+
updated_column_tag_model = """
20+
version: 2
21+
models:
22+
- name: base_model
23+
config:
24+
materialized: table
25+
columns:
26+
- name: id
27+
databricks_tags:
28+
pii: "false"
29+
- name: account_number
30+
databricks_tags:
31+
pii: "true"
32+
sensitive: "true"
33+
"""
34+
1935
column_tags_seed = """
2036
id,account_number
2137
1,'1234567890'

tests/functional/adapter/column_tags/test_column_tags.py

Lines changed: 40 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -6,67 +6,76 @@
66

77

88
class ColumnTagsMixin(MaterializationV2Mixin):
9+
@pytest.fixture(scope="class")
10+
def models(self):
11+
return {
12+
"base_model.sql": fixtures.base_model_sql,
13+
"schema.yml": fixtures.initial_column_tag_model.replace(
14+
"materialized: table", f"materialized: {self.relation_type}"
15+
),
16+
}
17+
918
def test_column_tags(self, project):
1019
util.run_dbt(["run"])
1120

12-
# Check that column tags were applied
13-
tags = project.run_sql(
14-
f"""
21+
column_tags_query = f"""
1522
SELECT column_name, tag_name, tag_value
1623
FROM `system`.`information_schema`.`column_tags`
1724
WHERE catalog_name = '{project.database}'
1825
AND schema_name = '{project.test_schema}'
1926
AND table_name = 'base_model'
2027
ORDER BY column_name, tag_name
21-
""",
22-
fetch="all",
23-
)
28+
"""
2429

30+
# Check that column tags were applied
31+
tags = project.run_sql(column_tags_query, fetch="all")
2532
expected_tags = {
2633
("account_number", "pii", "true"),
2734
("account_number", "sensitive", "true"),
2835
}
36+
actual_tags = {(row[0], row[1], row[2]) for row in tags}
37+
assert actual_tags == expected_tags
2938

39+
# Run a second time with an updated model
40+
util.write_file(
41+
fixtures.updated_column_tag_model.replace(
42+
"materialized: table", f"materialized: {self.relation_type}"
43+
),
44+
"models",
45+
"schema.yml",
46+
)
47+
util.run_dbt(["run"])
48+
49+
# Check that column tags were updated
50+
tags = project.run_sql(column_tags_query, fetch="all")
51+
expected_tags = {
52+
("id", "pii", "false"),
53+
("account_number", "pii", "true"),
54+
("account_number", "sensitive", "true"),
55+
}
3056
actual_tags = {(row[0], row[1], row[2]) for row in tags}
3157
assert actual_tags == expected_tags
3258

3359

3460
@pytest.mark.skip_profile("databricks_cluster")
3561
class TestColumnTagsTable(ColumnTagsMixin):
36-
@pytest.fixture(scope="class")
37-
def models(self):
38-
return {
39-
"base_model.sql": fixtures.base_model_sql,
40-
"schema.yml": fixtures.model_with_column_tags,
41-
}
62+
relation_type = "table"
4263

4364

4465
@pytest.mark.skip_profile("databricks_cluster")
4566
class TestColumnTagsIncremental(ColumnTagsMixin):
46-
@pytest.fixture(scope="class")
47-
def models(self):
48-
return {
49-
"base_model.sql": fixtures.base_model_sql,
50-
"schema.yml": fixtures.model_with_column_tags.replace(
51-
"materialized: table", "materialized: incremental"
52-
),
53-
}
67+
relation_type = "incremental"
5468

5569

5670
@pytest.mark.skip_profile("databricks_cluster", "databricks_uc_cluster")
5771
class TestColumnTagsMaterializedView(ColumnTagsMixin):
58-
@pytest.fixture(scope="class")
59-
def models(self):
60-
return {
61-
"base_model.sql": fixtures.base_model_sql,
62-
"schema.yml": fixtures.model_with_column_tags.replace(
63-
"materialized: table", "materialized: materialized_view"
64-
),
65-
}
72+
relation_type = "materialized_view"
6673

6774

6875
@pytest.mark.skip_profile("databricks_cluster", "databricks_uc_cluster")
6976
class TestStreamingTableColumnTags(ColumnTagsMixin):
77+
relation_type = "streaming_table"
78+
7079
@pytest.fixture(scope="class")
7180
def seeds(self):
7281
return {
@@ -77,7 +86,7 @@ def seeds(self):
7786
def models(self):
7887
return {
7988
"base_model.sql": fixtures.base_model_streaming_table,
80-
"schema.yml": fixtures.model_with_column_tags.replace(
89+
"schema.yml": fixtures.initial_column_tag_model.replace(
8190
"materialized: table", "materialized: streaming_table"
8291
),
8392
}
@@ -88,16 +97,5 @@ def setup_streaming_table_seed(self, project):
8897

8998

9099
@pytest.mark.skip_profile("databricks_cluster")
91-
class TestViewColumnTagsFailure(MaterializationV2Mixin):
92-
@pytest.fixture(scope="class")
93-
def models(self):
94-
return {
95-
"base_model.sql": fixtures.base_model_sql,
96-
"schema.yml": fixtures.model_with_column_tags.replace(
97-
"materialized: table", "materialized: view"
98-
),
99-
}
100-
101-
def test_view_column_tags_failure(self, project):
102-
result = util.run_dbt(["run"], expect_pass=False)
103-
assert "Column tags are not supported" in result.results[0].message
100+
class TestColumnTagsView(ColumnTagsMixin):
101+
relation_type = "view"

0 commit comments

Comments
 (0)