Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions internal/diff/index.go
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,18 @@ func generateIndexSQLWithName(index *ir.Index, indexName string, targetSchema st
}
builder.WriteString(")")

// INCLUDE columns (non-key columns stored in the index)
if len(index.IncludeColumns) > 0 {
builder.WriteString(" INCLUDE (")
for i, col := range index.IncludeColumns {
if i > 0 {
builder.WriteString(", ")
}
builder.WriteString(col)
}
builder.WriteString(")")
}

// NULLS NOT DISTINCT for unique indexes (PostgreSQL 15+)
if index.NullsNotDistinct && index.Type == ir.IndexTypeUnique {
builder.WriteString(" NULLS NOT DISTINCT")
Expand Down
10 changes: 10 additions & 0 deletions internal/diff/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -1511,6 +1511,16 @@ func indexesStructurallyEqual(oldIndex, newIndex *ir.Index) bool {
}
}

// Compare INCLUDE columns
if len(oldIndex.IncludeColumns) != len(newIndex.IncludeColumns) {
return false
}
for i, oldCol := range oldIndex.IncludeColumns {
if oldCol != newIndex.IncludeColumns[i] {
return false
}
}

return true
}

Expand Down
21 changes: 11 additions & 10 deletions ir/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -746,16 +746,17 @@ func (i *Inspector) buildIndexes(ctx context.Context, schema *IR, targetSchema s
}

index := &Index{
Schema: schemaName,
Table: tableName,
Name: indexName,
Type: indexType,
Method: method,
IsPartial: isPartial,
IsExpression: hasExpressions,
Where: "",
Comment: comment,
Columns: []*IndexColumn{},
Schema: schemaName,
Table: tableName,
Name: indexName,
Type: indexType,
Method: method,
IncludeColumns: indexRow.IncludeColumns,
IsPartial: isPartial,
IsExpression: hasExpressions,
Where: "",
Comment: comment,
Columns: []*IndexColumn{},
}

// Check for NULLS NOT DISTINCT (PostgreSQL 15+)
Expand Down
11 changes: 6 additions & 5 deletions ir/ir.go
Original file line number Diff line number Diff line change
Expand Up @@ -251,11 +251,12 @@ type Index struct {
Type IndexType `json:"type"`
Method string `json:"method"` // btree, hash, gin, gist, etc.
Columns []*IndexColumn `json:"columns"`
IsPartial bool `json:"is_partial"` // has a WHERE clause
IsExpression bool `json:"is_expression"` // functional/expression index
Where string `json:"where,omitempty"` // partial index condition
NullsNotDistinct bool `json:"nulls_not_distinct,omitempty"` // NULLS NOT DISTINCT (PG15+)
Comment string `json:"comment,omitempty"`
IncludeColumns []string `json:"include_columns,omitempty"` // INCLUDE columns (non-key)
IsPartial bool `json:"is_partial"` // has a WHERE clause
IsExpression bool `json:"is_expression"` // functional/expression index
Where string `json:"where,omitempty"` // partial index condition
NullsNotDistinct bool `json:"nulls_not_distinct,omitempty"` // NULLS NOT DISTINCT (PG15+)
Comment string `json:"comment,omitempty"`
}

// IndexColumn represents a column within an index
Expand Down
17 changes: 12 additions & 5 deletions ir/queries/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -436,27 +436,32 @@ WITH index_base AS (
ELSE false
END as has_expressions,
COALESCE(d.description, '') AS index_comment,
idx.indnkeyatts as num_key_columns,
idx.indnatts as num_columns,
ARRAY(
SELECT pg_get_indexdef(idx.indexrelid, k::int, true)
FROM generate_series(1, idx.indnatts) k
FROM generate_series(1, idx.indnkeyatts) k
) as column_definitions,
ARRAY(
SELECT
CASE
WHEN (idx.indoption[k-1] & 1) = 1 THEN 'DESC'
ELSE 'ASC'
END
FROM generate_series(1, idx.indnatts) k
FROM generate_series(1, idx.indnkeyatts) k
) as column_directions,
ARRAY(
SELECT CASE
WHEN opc.opcdefault THEN '' -- Omit default operator classes
ELSE COALESCE(opc.opcname, '')
END
FROM generate_series(1, idx.indnatts) k
FROM generate_series(1, idx.indnkeyatts) k
LEFT JOIN pg_opclass opc ON opc.oid = idx.indclass[k-1]
) as column_opclasses
) as column_opclasses,
ARRAY(
SELECT pg_get_indexdef(idx.indexrelid, k::int, true)
FROM generate_series(idx.indnkeyatts + 1, idx.indnatts) k
) as include_columns
FROM pg_index idx
JOIN pg_class i ON i.oid = idx.indexrelid
JOIN pg_class t ON t.oid = idx.indrelid
Expand Down Expand Up @@ -488,10 +493,12 @@ SELECT
sp.partial_predicate,
ib.has_expressions,
ib.index_comment,
ib.num_key_columns,
ib.num_columns,
ib.column_definitions,
ib.column_directions,
ib.column_opclasses
ib.column_opclasses,
ib.include_columns
FROM index_base ib
CROSS JOIN LATERAL (
SELECT
Expand Down
21 changes: 16 additions & 5 deletions ir/queries/queries.sql.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions testdata/diff/create_index/add_index/diff.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ CREATE TABLE IF NOT EXISTS users (

CREATE INDEX IF NOT EXISTS idx_users_email ON users (email varchar_pattern_ops);

CREATE INDEX IF NOT EXISTS idx_users_email_include ON users (email) INCLUDE (name);

CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email_unique ON users (email) NULLS NOT DISTINCT;

CREATE INDEX IF NOT EXISTS idx_users_id ON users (id);
Expand Down
2 changes: 2 additions & 0 deletions testdata/diff/create_index/add_index/new.sql
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ CREATE INDEX idx_users_id ON public.users (id);
CREATE INDEX "public.idx_users" ON public.users (email, name);
-- Test NULLS NOT DISTINCT (issue #355)
CREATE UNIQUE INDEX idx_users_email_unique ON public.users (email) NULLS NOT DISTINCT;
-- Test INCLUDE columns (issue #385)
CREATE INDEX idx_users_email_include ON public.users (email) INCLUDE (name);
6 changes: 6 additions & 0 deletions testdata/diff/create_index/add_index/plan.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,12 @@
"operation": "create",
"path": "public.users.idx_users_email"
},
{
"sql": "CREATE INDEX IF NOT EXISTS idx_users_email_include ON users (email) INCLUDE (name);",
"type": "table.index",
"operation": "create",
"path": "public.users.idx_users_email_include"
},
{
"sql": "CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email_unique ON users (email) NULLS NOT DISTINCT;",
"type": "table.index",
Expand Down
2 changes: 2 additions & 0 deletions testdata/diff/create_index/add_index/plan.sql
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ CREATE TABLE IF NOT EXISTS users (

CREATE INDEX IF NOT EXISTS idx_users_email ON users (email varchar_pattern_ops);

CREATE INDEX IF NOT EXISTS idx_users_email_include ON users (email) INCLUDE (name);

CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email_unique ON users (email) NULLS NOT DISTINCT;

CREATE INDEX IF NOT EXISTS idx_users_id ON users (id);
Expand Down
3 changes: 3 additions & 0 deletions testdata/diff/create_index/add_index/plan.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ Summary by type:
Tables:
+ users
+ idx_users_email (index)
+ idx_users_email_include (index)
+ idx_users_email_unique (index)
+ idx_users_id (index)
+ idx_users_name (index)
Expand All @@ -23,6 +24,8 @@ CREATE TABLE IF NOT EXISTS users (

CREATE INDEX IF NOT EXISTS idx_users_email ON users (email varchar_pattern_ops);

CREATE INDEX IF NOT EXISTS idx_users_email_include ON users (email) INCLUDE (name);

CREATE UNIQUE INDEX IF NOT EXISTS idx_users_email_unique ON users (email) NULLS NOT DISTINCT;

CREATE INDEX IF NOT EXISTS idx_users_id ON users (id);
Expand Down