Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
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
11 changes: 11 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,14 @@
## dbt-databricks next

### Fixes

- Warn when documented columns are missing from V1 and V2 table and incremental models, and honor `persist_docs.columns` for V2 column comments ([#1563](https://github.com/databricks/dbt-databricks/pull/1563) ports [dbt-adapters#1684](https://github.com/dbt-labs/dbt-adapters/pull/1684), resolving [dbt-adapters#1690](https://github.com/dbt-labs/dbt-adapters/issues/1690)).
- Extend the missing-column `persist_docs` warning to the view, materialized-view, and streaming-table create paths (post-build validation against the actual relation, gated on `persist_docs.columns`), completing the create-time coverage left as a follow-up to [#1563](https://github.com/databricks/dbt-databricks/pull/1563) ([#1615](https://github.com/databricks/dbt-databricks/pull/1615)).

### Under the Hood

- Remove unused internal logging-event classes (`CredentialLoadError`/`CredentialSaveError`/`CredentialShardEvent`, `PipelineEvent`/`PipelineRefresh`/`PipelineRefreshError`, and the `ConnectionReset`/`ConnectionReuse`/`ConnectionIdleClose`/`ConnectionCreated` connection events) that have had no call sites since the cursor-management and pipeline refactors ([#1547](https://github.com/databricks/dbt-databricks/pull/1547))

## dbt-databricks 1.12.2 (Jul 9, 2026)

### Features
Expand Down
20 changes: 0 additions & 20 deletions dbt/adapters/databricks/events/connection_events.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,26 +33,6 @@ def __str__(self) -> str:
return f"{self.description} - {self.message}"


class ConnectionReset(ConnectionWrapperEvent):
def __init__(self, description: str):
super().__init__(description, "Reset connection handle")


class ConnectionReuse(ConnectionWrapperEvent):
def __init__(self, description: str, prior_name: str):
super().__init__(description, f"Reusing connection previously named {prior_name}")


class ConnectionCreate(ConnectionWrapperEvent):
def __init__(self, description: str):
super().__init__(description, "Creating connection")


class ConnectionIdleClose(ConnectionWrapperEvent):
def __init__(self, description: str):
super().__init__(description, "Recreating due to idleness")


class ConnectionCreated(ConnectionWrapperEvent):
def __init__(self, description: str):
super().__init__(description, "Connection created")
16 changes: 0 additions & 16 deletions dbt/adapters/databricks/events/credential_events.py

This file was deleted.

23 changes: 0 additions & 23 deletions dbt/adapters/databricks/events/pipeline_events.py

This file was deleted.

6 changes: 4 additions & 2 deletions dbt/adapters/databricks/relation_configs/column_comments.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def get_diff(self, other: "ColumnCommentsConfig") -> Optional["ColumnCommentsCon
other_comments_lower = {k.lower(): v for k, v in other.comments.items()}

for column_name, comment in self.comments.items():
# Use case-insensitive comparison for column names
# Missing columns are reported post-build.
if column_name.lower() not in other_comments_lower:
continue
other_comment = other_comments_lower.get(column_name.lower())
if comment != other_comment:
column_name = f"`{column_name}`"
Expand Down Expand Up @@ -53,7 +55,7 @@ def from_relation_config(cls, relation_config: RelationConfig) -> ColumnComments
columns = getattr(relation_config, "columns", {})
persist = False
if relation_config.config:
persist = relation_config.config.persist_docs.get("relation") or False
persist = relation_config.config.persist_docs.get("columns") or False
comments = {}
for column_name, column in columns.items():
if hasattr(column, "description"):
Expand Down
36 changes: 34 additions & 2 deletions dbt/include/databricks/macros/adapters/persist_docs.sql
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,43 @@
{% endif %}
{% if for_columns and config.persist_column_docs() and model.columns %}
{%- set existing_columns = adapter.get_columns_in_relation(relation) -%}
{%- set columns_to_persist_docs = adapter.get_persist_doc_columns(existing_columns, model.columns) -%}
{%- set existing_column_names = existing_columns | map(attribute='name') | list -%}
{%- set valid_columns = dbt_databricks_validate_doc_columns(relation, model.columns, existing_column_names) -%}
{%- set columns_to_persist_docs = adapter.get_persist_doc_columns(existing_columns, valid_columns) -%}
{{ alter_column_comment(relation, columns_to_persist_docs) }}
{% endif %}
{% endmacro %}

{#-- Match column names case-insensitively. --#}
{% macro dbt_databricks_validate_doc_columns(relation, column_dict, existing_column_names) -%}
{%- set existing_lower = existing_column_names | map('lower') | list -%}
{%- set missing = [] -%}
{%- set valid = {} -%}
{%- for column_name in column_dict -%}
{%- if (column_name | lower) in existing_lower -%}
{%- do valid.update({column_name: column_dict[column_name]}) -%}
{%- else -%}
{%- do missing.append(column_name) -%}
{%- endif -%}
{%- endfor -%}
{%- if missing -%}
{%- do exceptions.warn(
"In relation " ~ relation.render() ~ ": The following columns are specified in the schema "
~ "but are not present in the database: " ~ missing | join(", ")
) -%}
{%- endif -%}
{{- return(valid) -}}
{%- endmacro %}

{#-- Validate V2 column docs post-build. --#}
{% macro validate_persist_doc_columns(relation, model) -%}
{% if config.persist_column_docs() and model.columns %}
{%- set existing_columns = adapter.get_columns_in_relation(relation) -%}
{%- set existing_column_names = existing_columns | map(attribute='name') | list -%}
{%- do dbt_databricks_validate_doc_columns(relation, model.columns, existing_column_names) -%}
{% endif %}
{%- endmacro %}

{% macro alter_relation_comment_sql(relation, description) %}
COMMENT ON {{ relation.type.render().upper() }} {{ relation.render() }} IS '{{ description | replace("'", "\\'") }}'
{% endmacro %}
Expand All @@ -53,4 +85,4 @@ COMMENT ON {{ relation.type.render().upper() }} {{ relation.render() }} IS '{{ d
{% set column_path = relation.render() ~ '.' ~ adapter.quote(column) %}
{{ run_query_as(comment_on_column_sql(column_path, escaped_comment), 'main', fetch_result=False) }}
{% endfor %}
{% endmacro %}
{% endmacro %}
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,9 @@
{%- endif -%}
{%- endif -%}

{#-- Validate every create, replace, and merge path. --#}
{% do validate_persist_doc_columns(target_relation, model) %}

{% set should_revoke = should_revoke(existing_relation, full_refresh_mode) %}
{% do apply_grants(target_relation, grant_config, should_revoke) %}
{% do optimize(target_relation) %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@

{{ execute_multiple_statements(build_sql) }}

{% do validate_persist_doc_columns(target_relation, model) %}

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

{% set column_tags = adapter.get_column_tags_from_model(config.model) %}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,8 @@

{{ execute_multiple_statements(build_sql) }}

{% do validate_persist_doc_columns(target_relation, model) %}

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

{% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}
Expand Down
2 changes: 2 additions & 0 deletions dbt/include/databricks/macros/materializations/table.sql
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@
{% endif %}
{% endif %}

{% do validate_persist_doc_columns(target_relation, model) %}

{% set should_revoke = should_revoke(existing_relation, full_refresh_mode=True) %}
{{ apply_grants(target_relation, grant_config, should_revoke) }}
{% do optimize(target_relation) %}
Expand Down
3 changes: 3 additions & 0 deletions dbt/include/databricks/macros/materializations/view.sql
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
{{ apply_column_tags(target_relation, column_tags) }}
{% endif %}
{% endif %}
{% do validate_persist_doc_columns(target_relation, model) %}
{% set should_revoke = should_revoke(exists_as_view, full_refresh_mode=True) %}
{% do apply_grants(target_relation, grant_config, should_revoke=True) %}

Expand Down Expand Up @@ -66,6 +67,8 @@
{{ apply_column_tags(target_relation, column_tags) }}
{% endif %}

{% do validate_persist_doc_columns(target_relation, model) %}

{{ run_hooks(post_hooks) }}
{% endif %}

Expand Down
132 changes: 132 additions & 0 deletions tests/functional/adapter/persist_docs/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,22 @@
select 1 as id, 'alice' as name
"""

missing_column_incremental_sql = """
{{ config(materialized='incremental') }}
select 1 as id, 'Ed' as name
"""

missing_column_incremental_schema = """
version: 2
models:
- name: missing_column_incremental
columns:
- name: id
description: "test id column description"
- name: column_that_does_not_exist
description: "comment that cannot be created"
"""

gate_model_schema = """
version: 2
models:
Expand All @@ -48,3 +64,119 @@
- name: id
description: The id column description
"""

schema_change_incremental_initial_sql = """
{{ config(materialized='incremental', on_schema_change='append_new_columns') }}
select 1 as id
"""

schema_change_incremental_updated_sql = """
{{ config(materialized='incremental', on_schema_change='append_new_columns') }}
select 1 as id, 'new value' as new_col
"""

schema_change_incremental_initial_yml = """
version: 2
models:
- name: schema_change_incremental
columns:
- name: id
description: "id comment"
"""

schema_change_incremental_updated_yml = """
version: 2
models:
- name: schema_change_incremental
columns:
- name: id
description: "id comment"
- name: new_col
description: "new column comment"
"""

alter_view_initial_sql = """
{{ config(materialized='view', view_update_via_alter=true) }}
select 1 as id
"""

alter_view_updated_sql = """
{{ config(materialized='view', view_update_via_alter=true) }}
select 1 as id, 2 as added_col
"""

alter_view_initial_yml = """
version: 2
models:
- name: alter_view
columns:
- name: id
description: "id comment"
"""

alter_view_updated_yml = """
version: 2
models:
- name: alter_view
columns:
- name: id
description: "updated id comment"
- name: added_col
description: "added column comment"
"""

# Create-time coverage for the materializations #1563 did not touch: view, materialized_view,
# streaming_table. Each documents a column absent from the relation; the post-build
# validate_persist_doc_columns check must surface it on create.
missing_column_create_seed = """id,value
1,10
2,20
"""

missing_column_view_sql = """
{{ config(materialized='view') }}
select * from {{ ref('mc_seed') }}
"""

missing_column_view_schema = """
version: 2
models:
- name: missing_column_view
columns:
- name: id
description: "test id column description"
- name: column_that_does_not_exist
description: "comment that cannot be created"
"""

missing_column_mv_sql = """
{{ config(materialized='materialized_view') }}
select * from {{ ref('mc_seed') }}
"""

missing_column_mv_schema = """
version: 2
models:
- name: missing_column_mv
columns:
- name: id
description: "test id column description"
- name: column_that_does_not_exist
description: "comment that cannot be created"
"""

missing_column_st_sql = """
{{ config(materialized='streaming_table') }}
select * from stream {{ ref('mc_seed') }}
"""

missing_column_st_schema = """
version: 2
models:
- name: missing_column_st
columns:
- name: id
description: "test id column description"
- name: column_that_does_not_exist
description: "comment that cannot be created"
"""
Loading