Skip to content

fix(ST03): exempt data-modifying CTEs from unused_cte#2676

Open
skyf0l wants to merge 1 commit into
quarylabs:mainfrom
skyf0l:fix/st03-data-modifying-cte
Open

fix(ST03): exempt data-modifying CTEs from unused_cte#2676
skyf0l wants to merge 1 commit into
quarylabs:mainfrom
skyf0l:fix/st03-data-modifying-cte

Conversation

@skyf0l
Copy link
Copy Markdown

@skyf0l skyf0l commented Jun 6, 2026

What

ST03 (structure.unused_cte) reported a violation for any CTE whose name never appears in a TableReference, even when the CTE body is a data-modifying statement (INSERT / UPDATE / DELETE / MERGE). In Postgres a data-modifying CTE is executed for its side effects whether or not the primary query references it, so such a CTE is never "unused".

This is a false positive on a common, idiomatic pattern: running several deletes/inserts as one atomic statement / round-trip.

WITH deleted_a AS (
    DELETE FROM child_a WHERE parent_id = 1
),
deleted_b AS (
    DELETE FROM child_b WHERE parent_id = 1
)
DELETE FROM parent WHERE id = 1

Before this change all three of these CTEs were reported as unused, and there is no inline way to silence it.

Why

SQLFluff (which sqruff tracks for rule behaviour) already exempts these via _is_data_modifying_cte. sqruff simply never ported that exemption. This PR brings sqruff in line.

How

In RuleST03::eval, before pushing a violation for a remaining CTE, inspect its cte_definition_segment with recursive_crawl for InsertStatement / UpdateStatement / DeleteStatement / MergeStatement. If found, skip the CTE.

Tests

Added Postgres fixtures to ST03.yml:

  • test_pass_postgres_data_modifying_delete_cte — single unreferenced DELETE CTE passes.
  • test_pass_postgres_data_modifying_multiple_delete_ctes — several unreferenced DELETE CTEs in one statement pass.
  • test_pass_postgres_data_modifying_insert_cte — unreferenced INSERT CTE passes.
  • test_pass_postgres_data_modifying_update_cte — unreferenced UPDATE CTE passes.
  • test_fail_postgres_unused_select_cte_alongside_data_modifying — a genuinely unused SELECT CTE next to an exempt data-modifying CTE is still flagged, so the exemption does not over-reach.

All existing ST03 cases continue to pass.

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.

1 participant