fix: preserve INCLUDE columns on CREATE INDEX (#385)#390
Conversation
The index inspector was using indnatts (total columns) for both key and include columns, causing INCLUDE columns to be merged into regular indexed columns. Now uses indnkeyatts to extract only key columns, and separately extracts include columns from positions indnkeyatts+1 through indnatts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Greptile SummaryThis PR fixes a bug where index INCLUDE columns were being merged into the regular key-column list because the inspector iterated up to Confidence Score: 5/5Safe to merge — the fix is correct and well-tested with no blocking issues. All findings are P2 (unused NumKeyColumns field in sqlc-generated code, consistent with the pre-existing unused NumColumns). The core bug fix correctly uses indnkeyatts vs indnatts to separate key and INCLUDE columns, the generated SQL clause ordering is valid PostgreSQL syntax (INCLUDE before NULLS NOT DISTINCT and WHERE), and the structural-equality comparison handles the ordered nature of INCLUDE columns correctly. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A[pg_index row] --> B{indnkeyatts vs indnatts}
B -->|generate_series 1..indnkeyatts| C[column_definitions
column_directions
column_opclasses]
B -->|generate_series indnkeyatts+1..indnatts| D[include_columns]
C --> E[Index.Columns]
D --> F[Index.IncludeColumns]
E --> G[generateIndexSQLWithName]
F --> G
G --> H["CREATE INDEX ... (key_cols)\nINCLUDE (include_cols)\n[NULLS NOT DISTINCT] [WHERE ...];"]
E --> I[indexesStructurallyEqual]
F --> I
I -->|equal| J[no-op]
I -->|differs| K[DROP + CREATE]
Reviews (1): Last reviewed commit: "fix: preserve INCLUDE columns on CREATE ..." | Re-trigger Greptile |
| NumKeyColumns int16 `db:"num_key_columns" json:"num_key_columns"` | ||
| NumColumns int16 `db:"num_columns" json:"num_columns"` |
There was a problem hiding this comment.
NumKeyColumns is scanned from the database but never read anywhere in inspector.go — column counts are already derived implicitly from the lengths of ColumnDefinitions and IncludeColumns. The pre-existing NumColumns field had the same issue before this PR. Both fields could be removed from the query, struct, and scan to reduce noise, but they're harmless as-is.
There was a problem hiding this comment.
Acknowledged — both NumKeyColumns and NumColumns are unused in Go code (column counts come from array lengths). This is a pre-existing pattern; removing them would be unrelated cleanup. Keeping them harmless and consistent with the SQL query structure.
There was a problem hiding this comment.
Pull request overview
Fixes schema inspection and diff/DDL generation so Postgres index INCLUDE columns are preserved (instead of being incorrectly merged into key columns), addressing issue #385.
Changes:
- Update index inspection query to treat
indnkeyattsas the key-column count and separately extract INCLUDE columns fromindnkeyatts+1..indnatts. - Extend the IR index model with
IncludeColumns, and update diff structural equality + SQL generation to emitINCLUDE (...). - Add/update a regression test case under
testdata/diff/create_index/add_index/to cover CREATE INDEX with INCLUDE.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated no comments.
Show a summary per file
| File | Description |
|---|---|
ir/queries/queries.sql |
Fixes index column extraction by separating key vs INCLUDE columns using indnkeyatts / indnatts. |
ir/queries/queries.sql.go |
Regenerates/updates sqlc output to include new query fields and scanning for INCLUDE columns. |
ir/ir.go |
Adds IncludeColumns to the Index IR struct for non-key stored columns. |
ir/inspector.go |
Populates Index.IncludeColumns from query results during inspection. |
internal/diff/index.go |
Emits INCLUDE (...) clause in generated CREATE INDEX SQL when applicable. |
internal/diff/table.go |
Includes IncludeColumns in indexesStructurallyEqual to detect structural changes correctly. |
testdata/diff/create_index/add_index/new.sql |
Adds a desired-state index containing INCLUDE (name) for regression coverage. |
testdata/diff/create_index/add_index/plan.txt |
Updates expected plan summary/DDL to include the INCLUDE index. |
testdata/diff/create_index/add_index/plan.sql |
Updates expected plan SQL output for INCLUDE clause. |
testdata/diff/create_index/add_index/plan.json |
Updates expected plan JSON step for the INCLUDE index. |
testdata/diff/create_index/add_index/diff.sql |
Updates expected diff SQL to include INCLUDE (...). |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Summary
indnatts(total columns) instead ofindnkeyatts(key columns only)IncludeColumnsfield toIndexIR struct and updated the SQL query to separately extract include columns from positionsindnkeyatts+1throughindnattsINCLUDE (...)clause and structural equality comparisonFixes #385
Test plan
testdata/diff/create_index/add_index/PGSCHEMA_TEST_FILTER="create_index/" go test -v ./cmd -run TestPlanAndApply🤖 Generated with Claude Code