Skip to content

feat!: add support for on_additive_change#5111

Closed
eakmanrq wants to merge 1 commit intomainfrom
eakmanrq/add_on_additive_change_support
Closed

feat!: add support for on_additive_change#5111
eakmanrq wants to merge 1 commit intomainfrom
eakmanrq/add_on_additive_change_support

Conversation

@eakmanrq
Copy link
Collaborator

@eakmanrq eakmanrq commented Aug 8, 2025

Breaking explanation: This change is breaking if you currently use the dbt adapter and have models using on_schema_change where we used to not correctly mimic the behavior in the SQLMesh runtime. This is non-breaking for SQLMesh native users.

In main, SQLMesh currently just detects destructive changes and allows users 3 different behavior options (ERROR, WARN, ALLOW). The problem is that dbt has schema change options that, in SQLMesh terms, differentiates destructive and additive changes. For example append_new_columns allows additive changes but ignores destructive changes. Furthermore they have an ignore option which means that no schema changes are performed on tables.

Therefore two fundamental changes are made in this PR:

  • on_additive_change incremental property is added that behaves just like on_destructive_change except applies to additive changes
  • ignore is added as an option to on_destructive_change. This should never really be used outside of some workaround edge-cases and documentation properly reflects this. dbt just says it will fail next time you run if you ignore (which is the default behavior)...

The dbt adapter is updated to use these changes. See table below for a mapping of behavior from dbt -> SQLMesh (the docs also contain this):

on_schema_change SQLMesh on_destructive_change SQLMesh on_additive_change
ignore ignore ignore
fail error error
append_new_columns ignore allow
sync_all_columns allow allow

Two follow up PRs are required to reach on_schema_change parity:

  • append_new_columns ignores alters even if the alters are additive. This PR would consider that additive and allow the change through. So need a way for dbt adapter to configure schema differ to consider alters destructive so it can be ignored.
  • on_schema_change only tracks top-level column changes while, on some engines, SQLMesh tracks nested column changes. Therefore there needs to be a way to let dbt adapter to configure SQLMesh so it doesn't do nested changes.

dbt documentation: https://docs.getdbt.com/docs/build/incremental-models#what-if-the-columns-of-my-incremental-model-change

TODO:

  • Manual testing
  • Run docs locally and validate it renders properly

@eakmanrq eakmanrq force-pushed the eakmanrq/add_on_additive_change_support branch from bd67ec2 to 23c4570 Compare August 8, 2025 00:56
@eakmanrq eakmanrq requested a review from Copilot August 8, 2025 00:57
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR adds support for on_additive_change configuration to provide fine-grained control over schema changes in SQLMesh models. It introduces the ability to differentiate between destructive changes (dropping columns) and additive changes (adding columns), allowing users to configure different behaviors for each type of schema modification.

Key changes include:

  • New OnAdditiveChange enum with ERROR, WARN, ALLOW, and IGNORE options
  • Enhanced dbt adapter to properly map on_schema_change values to SQLMesh settings
  • Updated schema diff logic to distinguish additive changes and apply filtering based on IGNORE settings

Reviewed Changes

Copilot reviewed 28 out of 28 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
sqlmesh/core/model/kind.py Adds OnAdditiveChange enum and integrates it into incremental model kinds
sqlmesh/dbt/model.py Updates dbt adapter to map on_schema_change to both destructive and additive change settings
sqlmesh/core/schema_diff.py Implements additive change detection and filtering logic with metadata support
sqlmesh/core/plan/builder.py Adds additive change validation to plan building process
sqlmesh/core/snapshot/evaluator.py Integrates additive change checking into snapshot evaluation
sqlmesh/utils/errors.py Adds AdditiveChangeError and formatting functions for additive changes
Comments suppressed due to low confidence (1)

tests/core/test_schema_diff.py:172

  • [nitpick] The parameter name is_part_of_destructive_change is inconsistent with the attribute name used in the actual implementation. Consider renaming to is_destructive for brevity and consistency.
            dict(support_positional_add=True),

@eakmanrq eakmanrq force-pushed the eakmanrq/add_on_additive_change_support branch 2 times, most recently from 231257e to c12ac90 Compare August 8, 2025 03:21
@eakmanrq eakmanrq marked this pull request as draft August 8, 2025 03:48
@eakmanrq eakmanrq force-pushed the eakmanrq/add_on_additive_change_support branch from c12ac90 to 19e794d Compare August 8, 2025 14:57
)
# Add current type metadata for additive classification
if self.current_type:
alter_column.meta["current_type"] = self.current_type
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we use this anywhere?

column.set("position", self.add_position.column_position_node)
# Set metadata if this ADD operation supports destructive changes
if self.is_part_of_destructive_change:
column.meta["sqlmesh_destructive"] = True
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand why does it matter. There's will be a corresponding drop alteration which will trigger the check. Why complicate this?

Copy link
Collaborator

@izeigerman izeigerman Aug 8, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we just check whether the same column shows up for both drop and add alteration in the generated list? This will make it more explicit.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Conceptually the reason why something like this is needed is because we can't assume ADD commands are additive - if they are ADD commands that are only needed due to a DROP command then we don't want that add either.

Doing it based on column name also works and I agree is cleaner since it wouldn't require creating metadata like this.

@izeigerman
Copy link
Collaborator

I believe we still need an empty migration script to recompute the metadata hash

@eakmanrq
Copy link
Collaborator Author

Deprecated by: #5193

All the feedback from this PR was address in the new PR.

@eakmanrq eakmanrq closed this Aug 20, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants