Skip to content

fix(indexes): ensure CCI created on final relation, not __dbt_tmp (#578)#751

Open
mopthe wants to merge 5 commits into
dbt-msft:masterfrom
mopthe:feat/index-refactor
Open

fix(indexes): ensure CCI created on final relation, not __dbt_tmp (#578)#751
mopthe wants to merge 5 commits into
dbt-msft:masterfrom
mopthe:feat/index-refactor

Conversation

@mopthe

@mopthe mopthe commented Jul 20, 2026

Copy link
Copy Markdown

Fixes #578 - Creating nonclustered indexes in a SQL Server materialized table was resulting in an orphaned clustered columnstore index.

The key fix: index names are now derived from the final relation name (with __dbt_tmp / __dbt_backup suffixes stripped). This ensures:

  • A second run produces an identical index name (idempotent)
  • CCIs are not orphaned after intermediate relations are renamed
  • No conflicts when drop_all_indexes_on_table runs

Add comprehensive integration and unit tests covering incremental runs, INCLUDE columns, quoted identifiers, and idempotence.

Copilot AI review requested due to automatic review settings July 20, 2026 10:30

Copilot AI left a comment

Copy link
Copy Markdown

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 fixes SQL Server index-macro behavior to prevent “orphaned” clustered columnstore index (CCI) naming during materializations that involve intermediate __dbt_tmp / __dbt_backup relations, by deriving index names from the final relation name and improving identifier quoting. It also adds unit + integration coverage around determinism/idempotence, INCLUDE columns, and quoted identifiers.

Changes:

  • Refactors index macros to use deterministic index naming derived from the final relation identifier (suffix-stripped) and improved quoting.
  • Updates the CCI creation macro to avoid __dbt_tmp / __dbt_backup leaking into the index name.
  • Adds comprehensive unit tests for macro rendering plus live SQL Server integration tests validating idempotence, INCLUDE semantics, quoted identifiers, and the orphaned-CCI regression.

Reviewed changes

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

File Description
dbt/include/sqlserver/macros/adapters/indexes.sql Adds quoting/qualification helpers and refactors index/CCI macros to produce deterministic names and safer SQL.
dbt/include/sqlserver/macros/relations/table/create.sql Updates the inline comment to document the new “final relation name” index naming behavior.
tests/unit/adapters/mssql/test_indexes.py Adds Jinja-rendered unit tests for quoting, suffix-stripping, deterministic names, and emitted SQL shapes.
tests/functional/adapter/mssql/test_index_macros.py Adds integration tests against live SQL Server for incremental stability, INCLUDE columns, quoted identifiers, and orphaned-CCI regression.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread tests/unit/adapters/mssql/test_indexes.py Outdated
Comment thread tests/functional/adapter/mssql/test_index_macros.py
Comment thread dbt/include/sqlserver/macros/adapters/indexes.sql Outdated
@mopthe

mopthe commented Jul 20, 2026

Copy link
Copy Markdown
Author

Migration Note: Orphaned Indexes

This release prevents orphaned CCI indexes from being created on intermediate __dbt_tmp tables across all materializations.

  • table materialization: No action required. The table is fully recreated on each run, so any pre-existing orphaned indexes are dropped automatically.
  • incremental materialization: Orphaned indexes created by prior versions persist and must be cleaned up manually (see below).

Cleaning up orphaned indexes

-- Identify orphaned CCI indexes
SELECT
    name AS index_name,
    OBJECT_SCHEMA_NAME(object_id) AS schema_name,
    OBJECT_NAME(object_id) AS table_name
FROM sys.indexes
WHERE name LIKE '%__dbt_tmp%cci';

-- Drop each one
DROP INDEX [index_name] ON [schema_name].[table_name];

@Benjamin-Knight

Copy link
Copy Markdown
Collaborator

I think you have converted the file endings because the file is showing a huge number of changes and I don't think there are any there, it makes the pull request difficult to parse.

@mopthe
mopthe force-pushed the feat/index-refactor branch 2 times, most recently from 6497d0e to 8a2916f Compare July 20, 2026 12:52
@mopthe

mopthe commented Jul 20, 2026

Copy link
Copy Markdown
Author

@Benjamin-Knight Thanks! Should be readable now.

@axellpadilla axellpadilla left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

mssql__ is not used anywhere on the repo, also I think a quoting macro already exists, adapter.quote, quotename, escape_single_quotes, can you check please for standarization and re-use where possible

@axellpadilla axellpadilla added this to the v1.10.1 milestone Jul 22, 2026
@axellpadilla
axellpadilla force-pushed the feat/index-refactor branch from c845896 to f6f601b Compare July 23, 2026 02:02
@axellpadilla
axellpadilla enabled auto-merge (squash) July 23, 2026 02:50
@axellpadilla

Copy link
Copy Markdown
Collaborator

After a careful analysis, this is a bug with how Commvault works, we deliberatelly chose to make a swap and avoid building this heavy index while the table is being read, this approach doesnt fix the issue because commvault just uses names to check object ownership, can you warrant it indeed fixes it @mopthe ?

@axellpadilla axellpadilla removed this from the v1.10.1 milestone Jul 23, 2026
@mopthe

mopthe commented Jul 23, 2026

Copy link
Copy Markdown
Author

Thanks for the Commvault context. Just to clarify, this PR only changes the CCI name by removing the __dbt_tmp suffix. It doesn't change when the index is created. The CCI is still built on the __dbt_tmp table before the swap.

If Commvault tracks ownership by index name, consistent naming should improve compatibility, not break it. Could you share more detail about the specific interaction you're seeing?

image

mopthe and others added 5 commits July 23, 2026 08:39
…t-msft#578)

Add helper macros for index creation: mssql__quote_ident, mssql__qualified_relation, mssql__strip_dbt_suffix, mssql__index_name, and sqlserver__index_exists.

The key fix: index names are now derived from the *final* relation name (with __dbt_tmp / __dbt_backup suffixes stripped). This ensures:
  * A second run produces an identical index name (idempotent)
  * CCIs are not orphaned after intermediate relations are renamed
  * No conflicts when `drop_all_indexes_on_table` runs

Update create_clustered_index and create_nonclustered_index to accept a `relation` parameter and use bracket-quoted, ]]-escaped column names.

Add comprehensive integration and unit tests covering incremental runs,INCLUDE columns, quoted identifiers, and idempotence.
- Escape and quote CCI index name to prevent SQL injection
- Use get_use_database_sql() helper for consistency
- Limit Jinja2 macro patch fixture to module scope
- Remove misleading multi-threaded bullet from comment
auto-merge was automatically disabled July 23, 2026 06:39

Head branch was pushed to by a user without write access

@mopthe
mopthe force-pushed the feat/index-refactor branch from f6f601b to ac9c3e7 Compare July 23, 2026 06:39
@Benjamin-Knight

Copy link
Copy Markdown
Collaborator

The index work I did also means that a certain prefix is required for DBT to consider indexes part of its managed set for that code, and that it could drop codes if you enable the flag that DBT does not think its managing.

I believe CCIs are exempt from this but best to check how your changes interact with that code.

@mopthe

mopthe commented Jul 23, 2026

Copy link
Copy Markdown
Author

@Benjamin-Knight You are right that CCI is exempt by type, not name. Reconciliation checks type == 'clustered columnstore' directly from sys.indexes, renaming it has no effect on whether it's protected from drops.

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.

[Bug] Creating nonclustered indexes in a SQL Server materialized table is resulting in an orphaned clustered columnstore index

4 participants