{"record":{"id":"96b87b4f7c871738","repo":"dbt-labs/dbt-core","slug":"struct-field-order-drift-should-be-ignored","errorCode":null,"errorMessage":"STRUCT field order drift should be ignored","messagePattern":"STRUCT field order drift should be ignored","errorType":"panic","errorClass":null,"httpStatus":null,"severity":"error","filePath":"crates/dbt-adapter/src/sql/diff.rs","lineNumber":3501,"sourceCode":"\"#;\n\n        let sql_fusion = r#\"\ncreate or replace table `db`.`sch`.`opportunity_product_entity_stream_base` as (\n  with hashed_rows as (\n    select\n      to_hex(md5(to_json_string(\n        struct( -- noqa: PRS\n          a , b , c\n        )\n      ))) as row_hash_id\n    from `db`.`sch`.`t`\n  )\n  select * from hashed_rows\n);\n\"#;\n\n        compare_sql(sql_fusion, sql_recorded, AdapterType::Snowflake)\n            .expect(\"STRUCT field order drift should be ignored\");\n    }\n\n    #[test]\n    fn test_bigquery_struct_projection_order_drift_should_be_ignorable() {\n        // Same as the Snowplow ordering drift case, but without comments.\n        let expected_alias_order = [\n            \"service_configuration_context\",\n            \"modal_entity\",\n            \"experiment_entity\",\n            \"kafka_connector_entity\",\n            \"selected_item_context\",\n            \"service_integration_context\",\n            \"workflow_entity\",\n            \"video_entity\",\n            \"value_calculator_context\",\n            \"kafka_plan_finder_context\",\n            \"feature_flag_context\",\n            \"posthog_session_context\",","sourceCodeStart":3483,"sourceCodeEnd":3519,"githubUrl":"https://github.com/dbt-labs/dbt-core/blob/0267ce9170576975b76b64ce856b2e5848e96617/crates/dbt-adapter/src/sql/diff.rs#L3483-L3519","documentation":"Test panic from .expect in crates/dbt-adapter/src/sql/diff.rs:3501: compare_sql between two Snowflake CTE queries whose only difference is the field ordering inside a STRUCT projection returned Err, so the differ treated reordered STRUCT fields as a semantic difference. The differ is supposed to make projection/STRUCT field order independent so recorded SQL and Fusion-generated SQL compare equal.","triggerScenarios":"cargo test -p dbt-adapter with test at diff.rs:3501: two otherwise identical Snowflake queries (Snowplow-style `hashed_rows` CTE ending in `select * from hashed_rows`) differ only in the order of STRUCT fields in the projection, and compare_sql(sql_fusion, sql_recorded, AdapterType::Snowflake) reports a mismatch.","commonSituations":"Replaying recorded warehouse SQL against newly generated SQL after a compiler change reordered SELECT items; canonicalizer changes that removed order-insensitive matching for struct literals/projections; a regression in alias-aware projection matching inside CTEs.","solutions":["Inspect the Err output of compare_sql to find which STRUCT field pair failed to match after canonicalization","Extend the projection-order canonicalization so STRUCT fields are compared as unordered name->expression maps (matched by alias) for Snowflake","Check whether a recent change to alias/projection extraction regressed handling of nested STRUCT expressions in CTEs","If field order is actually semantically meaningful in the new SQL, fix the generator, not the differ"],"exampleFix":"// before\ncompare_sql(sql_fusion, sql_recorded, AdapterType::Snowflake)\n    .expect(\"STRUCT field order drift should be ignored\");\n// after (library-side: compare struct fields by alias, unordered)\nlet norm = |s: &str| sort_struct_fields_by_alias(canonicalize(s, AdapterType::Snowflake));\nassert_eq!(norm(sql_fusion), norm(sql_recorded));","handlingStrategy":"validation","validationCode":"// verify only projection order differs before invoking the diff\nfn projections_equal_ignoring_order(a: &str, b: &str) -> bool {\n    let mut pa: Vec<_> = extract_projections(a); let mut pb: Vec<_> = extract_projections(b);\n    pa.sort(); pb.sort(); pa == pb\n}","typeGuard":null,"tryCatchPattern":"if let Err(e) = compare_sql(sql_fusion, sql_recorded, AdapterType::Snowflake) {\n    eprintln!(\"STRUCT projection diff: {e}\"); // inspect canonical forms, don't panic\n}","preventionTips":["Treat SELECT projections as alias-keyed maps, not ordered lists, in comparisons","Test STRUCT-heavy queries in both argument orders","Keep generated column order stable, or normalize before diffing","Cover CTE pipelines (with final `select * from cte`) in canonicalizer tests"],"tags":["rust","sql-diff","test-panic","snowflake","struct-projection"],"backgroundTag":"sql-diff-mismatch","analyzedSha":"0267ce9170576975b76b64ce856b2e5848e96617","analyzedAt":"2026-09-07T21:53:39.732Z","contentChangedAt":"2026-09-07T21:53:39.732Z","schemaVersion":2},"datasetVersion":"2026-09-14T16:17:12.679Z"}