dbt-labs/dbt-core · error
should treat qualified vs unqualified __dbt_tmp in MERGE USI
Error message
should treat qualified vs unqualified __dbt_tmp in MERGE USING as equivalent
What it means
Test panic from .expect at crates/dbt-adapter/src/sql/diff.rs:4512: compare_sql(merge_actual, merge_expected, AdapterType::Databricks) returned Err because the USING clause referenced the __dbt_tmp temp table with a three-part qualified name in one SQL and a bare identifier in the other. The differ should canonicalize relation qualification so these compare as equal for Databricks MERGE statements.
Source
Thrown at crates/dbt-adapter/src/sql/diff.rs:4512
merge
into
`dbt`.`dbt_dbt_audit`.`seed_executions` as DBT_INTERNAL_DEST
using
`seed_executions__dbt_tmp` as DBT_INTERNAL_SOURCE
on
FALSE
when matched
then update set
*
when not matched
then insert
*
"#;
compare_sql(merge_actual, merge_expected, AdapterType::Databricks)
.expect("should treat qualified vs unqualified __dbt_tmp in MERGE USING as equivalent");
}
#[test]
fn test_compare_sql_query_tag_payload_ignored() {
let actual = r#" alter session set query_tag = '{""model_name"":""stg_base_orders"",""env"":""PRD"",""job"":{""run_id"":"""",""execution_date"":"""",""start_date"":""""}}'"#;
let expected = r#" alter session set query_tag = '{""env"": ""PRD"", ""job"": {""execution_date"": """", ""run_id"": """", ""start_date"": """"}, ""model_name"": ""stg_base_orders""}'"#;
let result = compare_sql(actual, expected, AdapterType::Snowflake);
assert!(
result.is_ok(),
"Query tag payload differences should be ignored"
);
}
#[test]
fn test_compare_sql_uuid_literals_ignored() {
let actual = r#"
INSERT INTO
PROD_SSAP_AUDIT.ABAC.ABAC_JOB_RUNView on GitHub (pinned to 0267ce9170)
Solutions
- Inspect the Err to confirm the only divergence is relation qualification depth in USING
- Normalize relation names in the canonicalizer: qualify/strip to a common form (e.g. compare by trailing identifier when one side is a temp __dbt_tmp relation)
- Ensure this normalization is enabled for AdapterType::Databricks and shared with the view-DDL path (diff.rs:4464)
- If qualification differences are semantically meaningful (different relations), fix the SQL generator instead
Example fix
// before
compare_sql(merge_actual, merge_expected, AdapterType::Databricks)
.expect("should treat qualified vs unqualified __dbt_tmp in MERGE USING as equivalent");
// after (library-side: unify relation qualification before compare)
let norm = |s: &str| unify_relation_qualification(canonicalize(s, AdapterType::Databricks));
assert_eq!(norm(merge_actual), norm(merge_expected)); Defensive patterns
Strategy: validation
Validate before calling
// check qualification depth of the USING relation before diff
let depth_actual = relation_parts(merge_actual).len();
let depth_expected = relation_parts(merge_expected).len();
if depth_actual != depth_expected && relation_name(merge_actual) == relation_name(merge_expected) {
// pure qualification drift — normalize before comparing
} Try / catch
compare_sql(merge_actual, merge_expected, AdapterType::Databricks)
.unwrap_or_else(|e| eprintln!("MERGE USING relation drift: {e}")); Prevention
- Canonicalize relation qualification (2-part vs 3-part names) before diffing
- Share the qualification normalization between view DDL and MERGE paths
- Fixture-test MERGE USING with both qualified and bare __dbt_tmp references
- Avoid emitting fully qualified temp-table names in generated MERGE statements when the target convention is bare identifiers
When it happens
Trigger: cargo test -p dbt-adapter with the MERGE half of the test at diff.rs:4512: merge_actual uses `catalog.schema.__dbt_tmp` (three-part) in the MERGE USING clause while merge_expected uses just `__dbt_tmp`, and compare_sql under AdapterType::Databricks reports a mismatch, panicking the expect.
Common situations: Fusion qualifies temp relations fully while Mantle emits bare identifiers (or vice versa) in MERGE USING; adapter relation-rendering changes alter qualification depth; MERGE-style incremental models replayed against recorded SQL fail only on the USING relation name.
Related errors
- should treat persisted view vs temp view as equivalent
- bare vs wrapped CREATE VIEW body should compare as equal (or
- STRUCT field order drift should be ignored
- projection order drift should be ignored
- projection order drift should be ignored even with apostroph
AI-assisted analysis of dbt-labs/dbt-core@0267ce9170 (2026-09-07).
Data as JSON: /api/errors/2b505d5fcdfa19b6.
Report an issue: GitHub.