Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
e6926f6
feat: declare CATALOG_V2_CONFIGS for catalogs.yml v2 support
aahel May 4, 2026
e2d0688
Remove stale comment from UnityDatabricksConfig
aahel May 5, 2026
0385844
Merge branch 'main' into feat/catalogs-v2-configs
aahel May 5, 2026
0e119f6
minor fixes
aahel May 5, 2026
a5d37c9
Merge branch 'feat/catalogs-v2-configs' of github.com:aahel/dbt-datab…
aahel May 5, 2026
adfc0ee
Rearchitect to adapter-owned bridge: replace CATALOG_V2_CONFIGS with …
aahel May 11, 2026
f2f535e
Update changelog for catalogs v2 rearchitecture
aahel May 11, 2026
0ad94f1
Simplify changelog entry
aahel May 11, 2026
0f63049
Rewrite v2 catalog tests for new bridge architecture
aahel May 11, 2026
fda34d6
Rename test_v2_catalog_configs.py to test_catalogs_v2.py
aahel May 11, 2026
80e9d18
Fix location_root blank check, remove unused import, add empty string…
aahel May 11, 2026
408c64a
Merge branch 'main' into feat/catalogs-v2-configs
aahel May 11, 2026
1217a51
Merge remote-tracking branch 'origin/main' into feat/catalogs-v2-configs
aahel May 25, 2026
570b377
Merge remote-tracking branch 'fork/feat/catalogs-v2-configs' into fea…
aahel May 25, 2026
fae1603
minor fmt fix
aahel May 25, 2026
fcd6904
Merge branch 'main' into feat/catalogs-v2-configs
aahel Jun 1, 2026
112ced0
Merge branch 'main' into feat/catalogs-v2-configs
sd-db Jun 11, 2026
c6e5841
fix: guard Capability.CatalogsV2 for older dbt-adapters compat
aahel Jun 11, 2026
ddcb08b
fix: ruff E501 line-too-long in _unity.py and test_catalogs_v2.py
aahel Jun 11, 2026
f08e49c
fix: only validate use_uniform/file_format when use_uniform is explic…
aahel Jun 11, 2026
d7fe175
fix: use dict instead of deprecated typing.Dict (ruff UP035/UP006)
aahel Jun 11, 2026
57cca13
fix: ruff import ordering in test_catalogs_v2.py
aahel Jun 11, 2026
04b9ac2
warn when use_uniform is set in catalog config
aahel Jun 11, 2026
3980054
move CatalogsV2 capability guard to top of module-level code
aahel Jun 11, 2026
faf9f1e
move catalogs.yml v2 changelog entry to 1.12.2
aahel Jun 11, 2026
b3f183d
Merge remote-tracking branch 'origin/main' into feat/catalogs-v2-configs
aahel Jun 11, 2026
27bb79d
chore: colocate CatalogsV2 capability registration and add changelog …
sd-db Jun 11, 2026
6840ca7
remove hive_metastore file_format validation to avoid v1 regression
aahel Jun 11, 2026
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
## dbt-databricks 1.12.2 (TBD)

### Features

- Add catalogs.yml v2 support (requires `use_catalogs_v2: true` in dbt-core) ([1440](https://github.com/databricks/dbt-databricks/pull/1440))

### Under the Hood

- Raise the `dbt-adapters` upper bound to `<1.25.0` ([#1507](https://github.com/databricks/dbt-databricks/pull/1507))
Expand Down
15 changes: 14 additions & 1 deletion dbt/adapters/databricks/catalogs/_unity.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

from dbt.adapters.catalogs import CatalogIntegration, CatalogIntegrationConfig
from dbt.adapters.contracts.relation import RelationConfig
from dbt_common.exceptions import DbtValidationError

from dbt.adapters.databricks import constants, parse_model
from dbt.adapters.databricks.catalogs._relation import DatabricksCatalogRelation
from dbt.adapters.databricks.logging import logger


class UnityCatalogIntegration(CatalogIntegration):
Expand All @@ -13,9 +15,20 @@ class UnityCatalogIntegration(CatalogIntegration):

def __init__(self, config: CatalogIntegrationConfig) -> None:
super().__init__(config)
if location_root := config.adapter_properties.get("location_root"):
location_root = config.adapter_properties.get("location_root")
if location_root is not None:
if not str(location_root).strip():
raise DbtValidationError(
f"Catalog '{config.name}' unity/databricks location_root cannot be blank"
)
self.external_volume: Optional[str] = location_root
self.file_format: Optional[str] = config.file_format
if config.adapter_properties.get("use_uniform") is not None:
logger.warning(
f"Catalog '{config.name}': use_uniform is not yet supported by the adapter "
"and has no effect. Use the use_managed_iceberg behavior flag to control "
"Iceberg table creation. Support for use_uniform will be added in a future release."
)

@property
def location_root(self) -> Optional[str]:
Expand Down
25 changes: 19 additions & 6 deletions dbt/adapters/databricks/impl.py
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,17 @@ def get_identifier_list_string(table_names: set[str]) -> str:
return _identifier


def _adapter_capabilities() -> CapabilityDict:
capabilities: dict[Capability, CapabilitySupport] = {
Capability.TableLastModifiedMetadata: CapabilitySupport(support=Support.Full),
Capability.SchemaMetadataByRelations: CapabilitySupport(support=Support.Full),
}
catalogs_v2 = getattr(Capability, "CatalogsV2", None)
if catalogs_v2 is not None:
capabilities[catalogs_v2] = CapabilitySupport(support=Support.Full)
return CapabilityDict(capabilities)


class DatabricksAdapter(SparkAdapter):
INFORMATION_COMMENT_REGEX = re.compile(r"Comment: (.*)\n[A-Z][A-Za-z ]+:", re.DOTALL)

Expand All @@ -248,17 +259,16 @@ class DatabricksAdapter(SparkAdapter):

AdapterSpecificConfigs = DatabricksConfig # type: ignore[assignment]

_capabilities = CapabilityDict(
{
Capability.TableLastModifiedMetadata: CapabilitySupport(support=Support.Full),
Capability.SchemaMetadataByRelations: CapabilitySupport(support=Support.Full),
}
)
_capabilities = _adapter_capabilities()

CATALOG_INTEGRATIONS = [
HiveMetastoreCatalogIntegration,
UnityCatalogIntegration,
]
_V2_TO_V1_TYPE: ClassVar[dict[str, str]] = {
"unity": constants.UNITY_CATALOG_TYPE,
"hive_metastore": constants.HIVE_METASTORE_CATALOG_TYPE,
}
CONSTRAINT_SUPPORT = constraints.CONSTRAINT_SUPPORT

get_column_behavior: GetColumnsBehavior
Expand Down Expand Up @@ -297,6 +307,9 @@ def _has_dbr_capability_parse(self, capability_name: str) -> bool:
return False
return DBRCapabilities(is_sql_warehouse=True).has_capability(capability)

def _v2_to_v1_type(self, catalog_type: str) -> str:
return self._V2_TO_V1_TYPE.get(catalog_type, catalog_type)

@property
def _behavior_flags(self) -> list[BehaviorFlag]:
return [
Expand Down
75 changes: 75 additions & 0 deletions tests/unit/test_catalogs_v2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,75 @@
from dataclasses import dataclass, field
from typing import Any, Optional

import pytest
from dbt.adapters.capability import Capability, Support
from dbt_common.exceptions import DbtValidationError

from dbt.adapters.databricks.catalogs import UnityCatalogIntegration
from dbt.adapters.databricks.impl import DatabricksAdapter


@dataclass
class _Config:
"""Minimal CatalogIntegrationConfig stub for testing __init__ validation."""

name: str = "test_cat"
catalog_type: str = "unity"
catalog_name: Optional[str] = None
table_format: Optional[str] = "iceberg"
external_volume: Optional[str] = None
file_format: Optional[str] = None
adapter_properties: dict[str, Any] = field(default_factory=dict)


# ===== Adapter-level =====


def test_catalogs_v2_capability_declared():
catalogs_v2 = getattr(Capability, "CatalogsV2", None)
if catalogs_v2 is None:
pytest.skip("CatalogsV2 not available in this dbt-adapters version")
cap = DatabricksAdapter._capabilities[catalogs_v2]
assert cap.support == Support.Full


def test_v2_to_v1_type_unity():
adapter = object.__new__(DatabricksAdapter)
assert adapter._v2_to_v1_type("unity") == "unity"


def test_v2_to_v1_type_hive_metastore():
adapter = object.__new__(DatabricksAdapter)
assert adapter._v2_to_v1_type("hive_metastore") == "hive_metastore"


def test_v2_to_v1_type_unknown_passthrough():
adapter = object.__new__(DatabricksAdapter)
assert adapter._v2_to_v1_type("custom_type") == "custom_type"


# ===== UnityCatalogIntegration =====


def test_unity_parquet_without_uniform():
cfg = _Config(file_format="parquet")
integration = UnityCatalogIntegration(cfg)
assert integration.file_format == "parquet"


def test_unity_with_location_root():
cfg = _Config(file_format="parquet", adapter_properties={"location_root": "/mnt/data"})
integration = UnityCatalogIntegration(cfg)
assert integration.external_volume == "/mnt/data"


def test_unity_blank_location_root_raises():
cfg = _Config(file_format="parquet", adapter_properties={"location_root": " "})
with pytest.raises(DbtValidationError, match="location_root cannot be blank"):
UnityCatalogIntegration(cfg)


def test_unity_empty_location_root_raises():
cfg = _Config(file_format="parquet", adapter_properties={"location_root": ""})
with pytest.raises(DbtValidationError, match="location_root cannot be blank"):
UnityCatalogIntegration(cfg)
Loading