From 8b08f9bc0933172346e1eb481052455ff5a4bb7b Mon Sep 17 00:00:00 2001 From: Aarushi Singh Date: Fri, 15 May 2026 12:54:17 +0530 Subject: [PATCH 1/3] fix: handle empty view definition in QueryProcessor (#1459) Signed-off-by: Aarushi Singh --- CHANGELOG.md | 1 + .../databricks/relation_configs/query.py | 13 ++++- tests/unit/relation_configs/test_query.py | 56 ++++++++++++++++++- 3 files changed, 67 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index af874d9b1..44ac0fa54 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ ### Fixes +- Fix `QueryProcessor` crashing with `IndexError: string index out of range` when `view_definition` is empty or missing, such as when reading from streaming-table sources or freshly-created materialized views ([#1459](https://github.com/databricks/dbt-databricks/issues/1459)) - Fix `metric_view` failing with `METRIC_VIEW_INVALID_VIEW_DEFINITION` when models use bare `{{ ref(...) }}` for the `source:` field ([#1361](https://github.com/databricks/dbt-databricks/issues/1361)) - Fix `RefreshConfig.__eq__` self/other typo where two configs with the same `cron` but different `time_zone_value` compared equal - Fix streaming-table DROP-SCHEDULE path that was silently filtered out of the changeset diff --git a/dbt/adapters/databricks/relation_configs/query.py b/dbt/adapters/databricks/relation_configs/query.py index 12d1e3ce1..074b3ccce 100644 --- a/dbt/adapters/databricks/relation_configs/query.py +++ b/dbt/adapters/databricks/relation_configs/query.py @@ -27,7 +27,14 @@ class QueryProcessor(DatabricksComponentProcessor[QueryConfig]): @classmethod def from_relation_results(cls, result: RelationResults) -> QueryConfig: - view_definition = result["information_schema.views"]["view_definition"].strip() + view_definition_raw = result["information_schema.views"].get("view_definition") or "" + view_definition = view_definition_raw.strip() + if not view_definition: + # information_schema.views row was missing or empty — common for + # streaming-sourced derived views and freshly-created MVs whose + # metadata has not yet propagated. Return an empty QueryConfig so + # the materialization falls through to the create path. + return QueryConfig(query="") if view_definition[0] == "(" and view_definition[-1] == ")": view_definition = view_definition[1:-1] return QueryConfig(query=SqlUtils.clean_sql(view_definition)) @@ -48,5 +55,7 @@ class DescribeQueryProcessor(QueryProcessor): @classmethod def from_relation_results(cls, result: RelationResults) -> QueryConfig: table = result["describe_extended"] - row = next(x for x in table if x[0] == "View Text") + row = next((x for x in table if x[0] == "View Text"), None) + if row is None: + return QueryConfig(query="") return QueryConfig(query=SqlUtils.clean_sql(row[1])) diff --git a/tests/unit/relation_configs/test_query.py b/tests/unit/relation_configs/test_query.py index dd58e2c5d..7d66f9eb9 100644 --- a/tests/unit/relation_configs/test_query.py +++ b/tests/unit/relation_configs/test_query.py @@ -4,7 +4,11 @@ from agate import Row from dbt.exceptions import DbtRuntimeError -from dbt.adapters.databricks.relation_configs.query import QueryConfig, QueryProcessor +from dbt.adapters.databricks.relation_configs.query import ( + DescribeQueryProcessor, + QueryConfig, + QueryProcessor, +) sql = "select * from foo" @@ -50,3 +54,53 @@ def test_get_diff__different_query(self): } other = QueryProcessor.from_relation_results(results) assert model.get_diff(other) is model + + def test_from_results__empty_view_definition(self): + """view_definition is empty string — should return QueryConfig(query='') not IndexError.""" + results = {"information_schema.views": Row(["", ""], ["view_definition", "comment"])} + spec = QueryProcessor.from_relation_results(results) + assert spec == QueryConfig(query="") + + def test_from_results__none_view_definition(self): + """view_definition is None — should return QueryConfig(query='').""" + results = {"information_schema.views": Row([None, ""], ["view_definition", "comment"])} + spec = QueryProcessor.from_relation_results(results) + assert spec == QueryConfig(query="") + + def test_from_results__missing_row(self): + """No row returned (e.g. streaming table source) — should return QueryConfig(query='').""" + empty_row = Row(values=set()) + results = {"information_schema.views": empty_row} + spec = QueryProcessor.from_relation_results(results) + assert spec == QueryConfig(query="") + + def test_get_diff__empty_existing_query(self): + """If the persisted query is empty (IS row missing), any new query should detect a diff.""" + existing = QueryConfig(query="") + new = QueryConfig(query="select 1") + assert new.get_diff(existing) is new + + +class TestDescribeQueryProcessor: + def test_from_results__no_view_text_row(self): + """describe_extended has no 'View Text' row — should return QueryConfig(query='').""" + results = { + "describe_extended": [ + ("col_name", "data_type", "comment"), + ("id", "int", ""), + ] + } + spec = DescribeQueryProcessor.from_relation_results(results) + assert spec == QueryConfig(query="") + + def test_from_results__with_view_text_row(self): + """describe_extended has a valid 'View Text' row — should extract query.""" + sql = "select 1 as id" + results = { + "describe_extended": [ + ("col_name", "data_type", "comment"), + ("View Text", sql, ""), + ] + } + spec = DescribeQueryProcessor.from_relation_results(results) + assert spec == QueryConfig(query=sql) From d486149fb7448c335e44df646f60e21ac27291d4 Mon Sep 17 00:00:00 2001 From: Shubham Dhal Date: Mon, 13 Jul 2026 11:33:49 +0530 Subject: [PATCH 2/3] test: add functional coverage for materialized views from streaming tables --- .../materialized_view_tests/fixtures.py | 14 ++++++ .../materialized_view_tests/test_basic.py | 45 +++++++++++++++++++ 2 files changed, 59 insertions(+) diff --git a/tests/functional/adapter/materialized_view_tests/fixtures.py b/tests/functional/adapter/materialized_view_tests/fixtures.py index 00450ad06..77075d77d 100644 --- a/tests/functional/adapter/materialized_view_tests/fixtures.py +++ b/tests/functional/adapter/materialized_view_tests/fixtures.py @@ -221,6 +221,20 @@ def materialized_view_with_every(every_value: str) -> str: select * from {{ ref('mv_metadata_fetch_seed') }} """ +materialized_view_streaming_source_seed_csv = """id,value +1,100 +""".lstrip() + +materialized_view_streaming_source_table_sql = """ +{{ config(materialized='streaming_table') }} +select * from stream {{ ref('materialized_view_streaming_source_seed') }} +""" + +materialized_view_streaming_source_sql = """ +{{ config(materialized='materialized_view') }} +select * from {{ ref('materialized_view_streaming_source_table') }} +""" + mv_norebuild_seed_csv = """id,value 1,100 diff --git a/tests/functional/adapter/materialized_view_tests/test_basic.py b/tests/functional/adapter/materialized_view_tests/test_basic.py index bca205cfd..2f9cbfe90 100644 --- a/tests/functional/adapter/materialized_view_tests/test_basic.py +++ b/tests/functional/adapter/materialized_view_tests/test_basic.py @@ -6,6 +6,7 @@ from dbt.tests.adapter.materialized_view import files from dbt.tests.adapter.materialized_view.basic import MaterializedViewBasic +from tests.functional.adapter.fixtures import RerunSafeMixin from tests.functional.adapter.materialized_view_tests import fixtures @@ -162,6 +163,50 @@ def created_time(): assert created_time() == created_before +@pytest.mark.dlt +@pytest.mark.skip_profile("databricks_cluster", "databricks_uc_cluster") +class TestMaterializedViewStreamingTableSource(RerunSafeMixin, TestMaterializedViewsMixin): + @pytest.fixture(scope="class") + def seeds(self): + return { + "materialized_view_streaming_source_seed.csv": ( + fixtures.materialized_view_streaming_source_seed_csv + ) + } + + @pytest.fixture(scope="class") + def models(self): + return { + "materialized_view_streaming_source_table.sql": ( + fixtures.materialized_view_streaming_source_table_sql + ), + "materialized_view_streaming_source.sql": ( + fixtures.materialized_view_streaming_source_sql + ), + } + + @pytest.fixture(scope="class") + def relations_to_reset(self): + return ( + "materialized_view_streaming_source_seed", + "materialized_view_streaming_source_table", + "materialized_view_streaming_source", + ) + + def test_create_materialized_view_from_streaming_table(self, project): + util.run_dbt(["seed"]) + util.run_dbt(["run", "--select", "+materialized_view_streaming_source"]) + util.run_dbt(["run", "--select", "+materialized_view_streaming_source"]) + + relation = project.adapter.Relation.create( + identifier="materialized_view_streaming_source", + schema=project.test_schema, + database=project.database, + ) + assert self.query_relation_type(project, relation) == "materialized_view" + assert self.query_row_count(project, relation) == 1 + + @pytest.mark.dlt @pytest.mark.skip_profile("databricks_cluster", "databricks_uc_cluster") class TestMaterializedViewLiquidClustering(TestMaterializedViewsMixin): From 99566af04146c7c2b3435398306ce403b850a752 Mon Sep 17 00:00:00 2001 From: Shubham Dhal Date: Mon, 13 Jul 2026 11:34:22 +0530 Subject: [PATCH 3/3] chore: update CHANGELOG for #1462 --- CHANGELOG.md | 47 +++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 45 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20ffbbec9..e441301c3 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,43 @@ -## dbt-databricks 1.12.1 (TBD) +## dbt-databricks 1.12.3 (TBD) + +### Fixes + +- Handle missing or empty view-definition metadata when creating materialized views from streaming tables or newly-created materialized views (thanks @aarushisingh04!) ([#1462](https://github.com/databricks/dbt-databricks/pull/1462) resolves [#1459](https://github.com/databricks/dbt-databricks/issues/1459)) + +## dbt-databricks 1.12.2 (Jul 9, 2026) + +### Features + +- Add catalogs.yml v2 support (requires `use_catalogs_v2: true` in dbt-core) ([#1440](https://github.com/databricks/dbt-databricks/pull/1440)) +- 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)). +- Support the connector's Rust kernel backend via `connection_parameters: {use_kernel: true}` for SQL warehouses, with personal access token or Databricks OAuth (M2M/U2M) auth (requires `databricks-sql-connector[kernel]` on Python 3.10+; Azure service principals are not supported by the kernel) ([#1576](https://github.com/databricks/dbt-databricks/pull/1576)) + +### Fixes +- Stop dropping existing constraints on incremental runs when `contract.enforced` is `false` ([#1557](https://github.com/databricks/dbt-databricks/pull/1557)) +- Recognize the `skip_not_matched_step` merge config in the adapter config schema. It was previously declared with a typo (`skip_non_matched_step`); the merge macro already read the correct key, so merge behavior is unchanged ([#1562](https://github.com/databricks/dbt-databricks/pull/1562)). +- 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. ([#1551](https://github.com/databricks/dbt-databricks/pull/1551)) +- Apply column-level `databricks_tags` for incremental models on the V1 materialization 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)) +- Fix PK/FK constraints declaring an `expression` (e.g. `RELY`) being dropped and re-added on every incremental run. **Regression:** changing the `expression` on an existing PK/FK (`RELY`↔`NORELY`, or an expression-form FK's target) is no longer applied on incremental runs — use `--full-refresh`. ([#1552](https://github.com/databricks/dbt-databricks/pull/1552) closes [#1513](https://github.com/databricks/dbt-databricks/issues/1513)) +- Honor `incremental_apply_config_changes` in the V1 incremental merge path, allowing users to skip metadata diff queries (tags, column_tags, constraints, column_masks, tblproperties, describe_extended) when set to `false`. Matches the existing V2 behavior. ([#1467](https://github.com/databricks/dbt-databricks/pull/1467) partially resolves [#1402](https://github.com/databricks/dbt-databricks/issues/1402)) +- Fix column-level `databricks_tags` on Unity Catalog views updated via `ALTER` (`view_update_via_alter: true`) ([#1526](https://github.com/databricks/dbt-databricks/pull/1526) closes [#1525](https://github.com/databricks/dbt-databricks/issues/1525)) +- Apply `tblproperties` to `metric_view` models at create time, not only on a later alter/replace run ([#1530](https://github.com/databricks/dbt-databricks/pull/1530) closes [#1527](https://github.com/databricks/dbt-databricks/issues/1527)) +- Only emit `INSERT ... BY NAME` in the `replace_where`/`microbatch` strategies on DBR 18.0+ (and SQL warehouses), since older clusters reject the `BY NAME ... REPLACE WHERE` combination with a parse error ([#1539](https://github.com/databricks/dbt-databricks/pull/1539) resolves [#1532](https://github.com/databricks/dbt-databricks/issues/1532)) +- Fix materialized views always rebuilding because Databricks-internal `tblproperties` were read as configuration drift; the diff now compares only the configured properties ([#1350](https://github.com/databricks/dbt-databricks/pull/1350) closes [#1314](https://github.com/databricks/dbt-databricks/issues/1314)). +- Stop metric views with `view_update_via_alter` from re-issuing a redundant `ALTER VIEW ... AS` on every run ([#1546](https://github.com/databricks/dbt-databricks/pull/1546)) +- Fix column comments being permanently dropped from views when `view_update_via_alter` issues `ALTER VIEW AS`; reapply persisted column comments after the query update ([#1357](https://github.com/databricks/dbt-databricks/issues/1357)) + +### Under the Hood + +- Raise the `databricks-sql-connector` upper bound to `<4.3.1` to support `4.3.0` ([#1518](https://github.com/databricks/dbt-databricks/pull/1518)) +- Raise the `dbt-adapters` upper bound to `<1.25.0` ([#1507](https://github.com/databricks/dbt-databricks/pull/1507)) +- Raise the `databricks-sdk` upper bound to `<0.118.0` to pick up 0.117.0, which fixes `WorkspaceClient` construction failing with `CONTEXT_UNAVAILABLE_FOR_REMOTE_CLIENT` on Spark Connect clusters ([#1517](https://github.com/databricks/dbt-databricks/pull/1517) closes [#1252](https://github.com/databricks/dbt-databricks/issues/1252)) +- Raise the `dbt-core` upper bound to `<1.11.13` to include dbt-core 1.11.12 ([#1578](https://github.com/databricks/dbt-databricks/pull/1578)) +- Instrument `add_query`, `get_relation_config`, `is_uniform`, `has_dbr_capability`, and `is_cluster` for dbt's record/replay framework (test-only, no runtime impact) ([#1508](https://github.com/databricks/dbt-databricks/pull/1508)) +- Add a weekly `Kernel Integration Tests` workflow that runs the functional suite against the SQL-warehouse profile through the connector's Rust kernel backend (`DBT_DATABRICKS_USE_KERNEL=1`) (test-only, no runtime impact) ([#1576](https://github.com/databricks/dbt-databricks/pull/1576)). +- Substantially expand adapter test coverage across the functional and unit suites: broaden functional coverage for materializations (table replace-in-place, view→table conversion), incremental strategies and full-refresh recreate, constraints and row filters, tags and column tags, streaming tables, materialized and metric views, `copy_into`, clone, seeds, SQL UDFs, `split_part`, `sync_all_columns` type widening, catalog `table_format`, and Python models — shifting assertions to server-observable state rather than compiled SQL or log output; add unit coverage for the live event/logging classes; make stateful functional tests rerun-safe; and add CI upkeep (a weekly Python-model notebook-folder purge and a longer unit-test timeout) (test-only, no runtime impact). ([#1511](https://github.com/databricks/dbt-databricks/pull/1511), [#1512](https://github.com/databricks/dbt-databricks/pull/1512), [#1514](https://github.com/databricks/dbt-databricks/pull/1514), [#1521](https://github.com/databricks/dbt-databricks/pull/1521), [#1522](https://github.com/databricks/dbt-databricks/pull/1522), [#1523](https://github.com/databricks/dbt-databricks/pull/1523), [#1524](https://github.com/databricks/dbt-databricks/pull/1524), [#1528](https://github.com/databricks/dbt-databricks/pull/1528), [#1529](https://github.com/databricks/dbt-databricks/pull/1529), [#1531](https://github.com/databricks/dbt-databricks/pull/1531), [#1533](https://github.com/databricks/dbt-databricks/pull/1533), [#1534](https://github.com/databricks/dbt-databricks/pull/1534), [#1535](https://github.com/databricks/dbt-databricks/pull/1535), [#1536](https://github.com/databricks/dbt-databricks/pull/1536), [#1537](https://github.com/databricks/dbt-databricks/pull/1537), [#1538](https://github.com/databricks/dbt-databricks/pull/1538), [#1541](https://github.com/databricks/dbt-databricks/pull/1541), [#1542](https://github.com/databricks/dbt-databricks/pull/1542), [#1543](https://github.com/databricks/dbt-databricks/pull/1543), [#1544](https://github.com/databricks/dbt-databricks/pull/1544), [#1545](https://github.com/databricks/dbt-databricks/pull/1545), [#1548](https://github.com/databricks/dbt-databricks/pull/1548), [#1550](https://github.com/databricks/dbt-databricks/pull/1550), [#1553](https://github.com/databricks/dbt-databricks/pull/1553), [#1558](https://github.com/databricks/dbt-databricks/pull/1558), [#1559](https://github.com/databricks/dbt-databricks/pull/1559), [#1564](https://github.com/databricks/dbt-databricks/pull/1564), [#1565](https://github.com/databricks/dbt-databricks/pull/1565), [#1566](https://github.com/databricks/dbt-databricks/pull/1566), [#1568](https://github.com/databricks/dbt-databricks/pull/1568), [#1569](https://github.com/databricks/dbt-databricks/pull/1569), [#1570](https://github.com/databricks/dbt-databricks/pull/1570), [#1571](https://github.com/databricks/dbt-databricks/pull/1571), [#1573](https://github.com/databricks/dbt-databricks/pull/1573), [#1579](https://github.com/databricks/dbt-databricks/pull/1579), [#1580](https://github.com/databricks/dbt-databricks/pull/1580), [#1581](https://github.com/databricks/dbt-databricks/pull/1581), [#1582](https://github.com/databricks/dbt-databricks/pull/1582)) + +## dbt-databricks 1.12.1 (June 10, 2026) ### Features @@ -14,14 +53,19 @@ - Skip `DESCRIBE TABLE EXTENDED ... AS JSON` for foreign/federated tables in `get_columns_in_relation`, avoiding repeated failures and extra latency on those sources ([#1472](https://github.com/databricks/dbt-databricks/pull/1472)) - `EXTRACT_CLUSTER_ID_FROM_HTTP_PATH_REGEX` now stops the capture at `?` / `&`, so any trailing query string on `http_path` no longer corrupts the extracted cluster id. Latent issue on legacy hosts; the fix unblocks SPOG cluster paths. - Gate column-level constraints on `contract.enforced` to match the existing model-level gate, ensuring column-level NOT NULL / PK / FK / CHECK constraints are only applied when `contract.enforced: true` under `use_materialization_v2: true` ([#1470](https://github.com/databricks/dbt-databricks/pull/1470) closes [#1381](https://github.com/databricks/dbt-databricks/issues/1381)) +- Fix managed Iceberg incremental models configured with `partition_by` silently losing their clustering after the first incremental run. Managed Iceberg stores `partition_by` as liquid clustering server-side, so the reconciler now treats `partition_by` as the desired clustering and no longer issues a spurious `ALTER TABLE ... CLUSTER BY NONE` ([#1496](https://github.com/databricks/dbt-databricks/pull/1496) closes [#1495](https://github.com/databricks/dbt-databricks/issues/1495)) ### Under the Hood +- Make the incremental constraint functional tests rerun-safe so a `pytest --reruns` retry no longer inherits mutated state (rewritten `schema.yml`, half-built relations) from the failed attempt (test-only, no runtime impact). ([#1503](https://github.com/databricks/dbt-databricks/pull/1503)) +- Make the column-tag functional tests rerun-safe so a `pytest --reruns` retry no longer inherits mutated state (updated `schema.yml`, leftover column tags, a running streaming-table query) from the failed attempt (test-only, no runtime impact). ([#1499](https://github.com/databricks/dbt-databricks/pull/1499)) - Raise the `dbt-tests-adapter` test-dependency floor to `>=1.20.0` to pick up its `persist_docs` fixture typo fix (test-only, no runtime impact) ([#1490](https://github.com/databricks/dbt-databricks/pull/1490)) - Defer SDK `Config` construction to connection-open time so offline paths (`dbt parse`/`list`/`compile`) don't trigger the host-metadata probe introduced in `databricks-sdk>=0.103`; as a side effect, auth errors now surface at first connection rather than during profile parsing. ([#1474](https://github.com/databricks/dbt-databricks/pull/1474)) - Bump ceilings on `databricks-sdk` (now `<0.105.0`) and `databricks-sql-connector[pyarrow]` (now `<4.3.0`) to admit newer releases; floors unchanged. ([#1474](https://github.com/databricks/dbt-databricks/pull/1474)) +- Tighten the `databricks-sql-connector` ceiling to patch level (`<4.3.0` → `<4.2.7`) so patch upgrades require an intentional bump; the locked version stays at 4.2.6. ([#1497](https://github.com/databricks/dbt-databricks/pull/1497), [#1498](https://github.com/databricks/dbt-databricks/pull/1498)) - Stabilize the `TestChangingSchema*` Python-model functional tests under min-deps (dbt-core 1.11.2), where a sibling class's source schema.yml could leak into their parse and fail with `EnvVarMissingError`. ([#1488](https://github.com/databricks/dbt-databricks/pull/1488)) - **BREAKING:** users who relied on column-level constraints (NOT NULL, primary key, foreign key, check) being applied under `use_materialization_v2: true` without `contract.enforced: true` must now set `contract.enforced: true` explicitly on the model. +- Bump upper bound of dbt-core to `<1.11.12` to include dbt-core 1.11.9, 1.11.10, and 1.11.11 ([#1505](https://github.com/databricks/dbt-databricks/pull/1505)) ## dbt-databricks 1.12.0 (May 18, 2026) @@ -36,7 +80,6 @@ ### Fixes -- Fix `QueryProcessor` crashing with `IndexError: string index out of range` when `view_definition` is empty or missing, such as when reading from streaming-table sources or freshly-created materialized views ([#1459](https://github.com/databricks/dbt-databricks/issues/1459)) - Fix `metric_view` failing with `METRIC_VIEW_INVALID_VIEW_DEFINITION` when models use bare `{{ ref(...) }}` for the `source:` field ([#1361](https://github.com/databricks/dbt-databricks/issues/1361)) - Fix `RefreshConfig.__eq__` self/other typo where two configs with the same `cron` but different `time_zone_value` compared equal - Fix streaming-table DROP-SCHEDULE path that was silently filtered out of the changeset