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
6 changes: 6 additions & 0 deletions internal/diff/diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ const (
DiffTypeTableComment
DiffTypeTableColumnComment
DiffTypeTableIndexComment
DiffTypeTablePersistence
DiffTypeView
DiffTypeViewTrigger
DiffTypeViewComment
Expand Down Expand Up @@ -66,6 +67,8 @@ func (d DiffType) String() string {
return "table.column.comment"
case DiffTypeTableIndexComment:
return "table.index.comment"
case DiffTypeTablePersistence:
return "table.persistence"
case DiffTypeView:
return "view"
case DiffTypeViewTrigger:
Expand Down Expand Up @@ -138,6 +141,8 @@ func (d *DiffType) UnmarshalJSON(data []byte) error {
*d = DiffTypeTableColumnComment
case "table.index.comment":
*d = DiffTypeTableIndexComment
case "table.persistence":
*d = DiffTypeTablePersistence
case "view":
*d = DiffTypeView
case "view.trigger":
Expand Down Expand Up @@ -386,6 +391,7 @@ type tableDiff struct {
CommentChanged bool
OldComment string
NewComment string
PersistenceChanged bool
}

// ColumnDiff represents changes to a column
Expand Down
34 changes: 32 additions & 2 deletions internal/diff/table.go
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,11 @@ func diffTables(oldTable, newTable *ir.Table, targetSchema string) *tableDiff {
diff.NewComment = newTable.Comment
}

// Check for persistence (UNLOGGED/LOGGED) changes
if oldTable.Unlogged != newTable.Unlogged {
diff.PersistenceChanged = true
}

// Return nil if no changes
if len(diff.AddedColumns) == 0 && len(diff.DroppedColumns) == 0 &&
len(diff.ModifiedColumns) == 0 && len(diff.AddedConstraints) == 0 &&
Expand All @@ -337,7 +342,7 @@ func diffTables(oldTable, newTable *ir.Table, targetSchema string) *tableDiff {
len(diff.DroppedTriggers) == 0 && len(diff.ModifiedTriggers) == 0 &&
len(diff.AddedPolicies) == 0 && len(diff.DroppedPolicies) == 0 &&
len(diff.ModifiedPolicies) == 0 && len(diff.RLSChanges) == 0 &&
!diff.CommentChanged {
!diff.CommentChanged && !diff.PersistenceChanged {
return nil
}

Expand Down Expand Up @@ -583,7 +588,11 @@ func generateTableSQL(table *ir.Table, targetSchema string, createdTables map[st
tableName := ir.QualifyEntityNameWithQuotes(table.Schema, table.Name, targetSchema)

var parts []string
parts = append(parts, fmt.Sprintf("CREATE TABLE IF NOT EXISTS %s (", tableName))
createPrefix := "CREATE TABLE IF NOT EXISTS"
if table.Unlogged {
createPrefix = "CREATE UNLOGGED TABLE IF NOT EXISTS"
}
parts = append(parts, fmt.Sprintf("%s %s (", createPrefix, tableName))

// Add columns
var columnParts []string
Expand Down Expand Up @@ -688,6 +697,27 @@ func constraintDroppedWithColumns(constraint *ir.Constraint, droppedColumnSet ma
// droppedColumnSet contains column names being dropped from this table; constraints that
// depend on those columns are skipped because DROP COLUMN already removes them. (#384)
func (td *tableDiff) generateAlterTableStatements(targetSchema string, collector *diffCollector, droppedTableSet map[string]bool, droppedColumnSet map[string]bool) {
// Persistence change (UNLOGGED to LOGGED or vice versa) should emit first
// because PostgreSQL rewrites the heap so doing it before column/constraint
Comment thread
ivgiuliani marked this conversation as resolved.
// changes reduces data movement on subsequent steps
if td.PersistenceChanged {
tableName := getTableNameWithSchema(td.Table.Schema, td.Table.Name, targetSchema)
clause := "SET LOGGED"
if td.Table.Unlogged {
clause = "SET UNLOGGED"
}
sql := fmt.Sprintf("ALTER TABLE %s %s;", tableName, clause)

context := &diffContext{
Type: DiffTypeTablePersistence,
Operation: DiffOperationAlter,
Path: fmt.Sprintf("%s.%s", td.Table.Schema, td.Table.Name),
Source: td.Table,
CanRunInTransaction: true,
}
collector.collect(context, sql)
}

// Drop constraints first (before dropping columns) - already sorted by the Diff operation
for _, constraint := range td.DroppedConstraints {
// Skip constraints already removed by a dropped column. (#384)
Expand Down
1 change: 1 addition & 0 deletions ir/inspector.go
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,7 @@ func (i *Inspector) buildTables(ctx context.Context, schema *IR, targetSchema st
Name: tableName,
Type: tType,
Comment: comment,
Unlogged: table.Relpersistence.Valid && table.Relpersistence.String == "u",
Columns: []*Column{},
Constraints: make(map[string]*Constraint),
Indexes: make(map[string]*Index),
Expand Down
1 change: 1 addition & 0 deletions ir/ir.go
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ type Table struct {
PartitionStrategy string `json:"partition_strategy,omitempty"` // RANGE, LIST, HASH
PartitionKey string `json:"partition_key,omitempty"` // Column(s) used for partitioning
LikeClauses []LikeClause `json:"like_clauses,omitempty"` // LIKE clauses in CREATE TABLE
Unlogged bool `json:"unlogged,omitempty"` // True for UNLOGGED tables
}

// Column represents a table column
Expand Down
8 changes: 5 additions & 3 deletions ir/queries/queries.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,12 @@ WHERE

-- GetTables retrieves all tables in the database with metadata
-- name: GetTables :many
SELECT
SELECT
t.table_schema,
t.table_name,
t.table_type,
COALESCE(d.description, '') AS table_comment
COALESCE(d.description, '') AS table_comment,
c.relpersistence::text AS relpersistence
FROM information_schema.tables t
LEFT JOIN pg_namespace n ON n.nspname = t.table_schema
LEFT JOIN pg_class c ON c.relname = t.table_name AND c.relnamespace = n.oid
Expand All @@ -44,7 +45,8 @@ SELECT
t.table_schema,
t.table_name,
t.table_type,
COALESCE(d.description, '') AS table_comment
COALESCE(d.description, '') AS table_comment,
c.relpersistence::text AS relpersistence
FROM information_schema.tables t
LEFT JOIN pg_namespace n ON n.nspname = t.table_schema
LEFT JOIN pg_class c ON c.relname = t.table_name AND c.relnamespace = n.oid
Expand Down
28 changes: 17 additions & 11 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: 1 addition & 1 deletion ir/queries/sqlc.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,4 @@ sql:
emit_json_tags: true
database:
managed: false
uri: "postgres://postgres:testpwd1@localhost:5432/sakila"
uri: "postgres://postgres:testpwd1@localhost:5432/sakila"
5 changes: 5 additions & 0 deletions testdata/diff/create_table/add_table_unlogged/diff.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE UNLOGGED TABLE IF NOT EXISTS events (
id integer,
payload text NOT NULL,
CONSTRAINT events_pkey PRIMARY KEY (id)
);
4 changes: 4 additions & 0 deletions testdata/diff/create_table/add_table_unlogged/new.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE UNLOGGED TABLE public.events (
id integer PRIMARY KEY,
payload text NOT NULL
);
1 change: 1 addition & 0 deletions testdata/diff/create_table/add_table_unlogged/old.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
-- Empty schema (no tables)
20 changes: 20 additions & 0 deletions testdata/diff/create_table/add_table_unlogged/plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": "1.0.0",
"pgschema_version": "1.9.0",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "965b1131737c955e24c7f827c55bd78e4cb49a75adfd04229e0ba297376f5085"
},
"groups": [
{
"steps": [
{
"sql": "CREATE UNLOGGED TABLE IF NOT EXISTS events (\n id integer,\n payload text NOT NULL,\n CONSTRAINT events_pkey PRIMARY KEY (id)\n);",
"type": "table",
"operation": "create",
"path": "public.events"
}
]
}
]
}
5 changes: 5 additions & 0 deletions testdata/diff/create_table/add_table_unlogged/plan.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
CREATE UNLOGGED TABLE IF NOT EXISTS events (
id integer,
payload text NOT NULL,
CONSTRAINT events_pkey PRIMARY KEY (id)
);
16 changes: 16 additions & 0 deletions testdata/diff/create_table/add_table_unlogged/plan.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Plan: 1 to add.

Summary by type:
tables: 1 to add

Tables:
+ events

DDL to be executed:
--------------------------------------------------

CREATE UNLOGGED TABLE IF NOT EXISTS events (
id integer,
payload text NOT NULL,
CONSTRAINT events_pkey PRIMARY KEY (id)
);
1 change: 1 addition & 0 deletions testdata/diff/create_table/set_logged/diff.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE events SET LOGGED;
4 changes: 4 additions & 0 deletions testdata/diff/create_table/set_logged/new.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE public.events (
id integer PRIMARY KEY,
payload text NOT NULL
);
4 changes: 4 additions & 0 deletions testdata/diff/create_table/set_logged/old.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE UNLOGGED TABLE public.events (
id integer PRIMARY KEY,
payload text NOT NULL
);
20 changes: 20 additions & 0 deletions testdata/diff/create_table/set_logged/plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": "1.0.0",
"pgschema_version": "1.9.0",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "b465915d72f5be87a29cb98e6808e1cb91db1525bbb7e17775df4774cd0737da"
},
"groups": [
{
"steps": [
{
"sql": "ALTER TABLE events SET LOGGED;",
"type": "table.persistence",
"operation": "alter",
"path": "public.events"
}
]
}
]
}
1 change: 1 addition & 0 deletions testdata/diff/create_table/set_logged/plan.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE events SET LOGGED;
13 changes: 13 additions & 0 deletions testdata/diff/create_table/set_logged/plan.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Plan: 1 to modify.

Summary by type:
tables: 1 to modify

Tables:
~ events
~ events (persistence)

DDL to be executed:
--------------------------------------------------

ALTER TABLE events SET LOGGED;
1 change: 1 addition & 0 deletions testdata/diff/create_table/set_unlogged/diff.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE events SET UNLOGGED;
4 changes: 4 additions & 0 deletions testdata/diff/create_table/set_unlogged/new.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE UNLOGGED TABLE public.events (
id integer PRIMARY KEY,
payload text NOT NULL
);
4 changes: 4 additions & 0 deletions testdata/diff/create_table/set_unlogged/old.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
CREATE TABLE public.events (
id integer PRIMARY KEY,
payload text NOT NULL
);
20 changes: 20 additions & 0 deletions testdata/diff/create_table/set_unlogged/plan.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{
"version": "1.0.0",
"pgschema_version": "1.9.0",
"created_at": "1970-01-01T00:00:00Z",
"source_fingerprint": {
"hash": "cb84b30ef73ee96caeeef3901be4354d9f8aecf303f0fcb9ae70618c1d106761"
},
"groups": [
{
"steps": [
{
"sql": "ALTER TABLE events SET UNLOGGED;",
"type": "table.persistence",
"operation": "alter",
"path": "public.events"
}
]
}
]
}
1 change: 1 addition & 0 deletions testdata/diff/create_table/set_unlogged/plan.sql
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ALTER TABLE events SET UNLOGGED;
13 changes: 13 additions & 0 deletions testdata/diff/create_table/set_unlogged/plan.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
Plan: 1 to modify.

Summary by type:
tables: 1 to modify

Tables:
~ events
~ events (persistence)

DDL to be executed:
--------------------------------------------------

ALTER TABLE events SET UNLOGGED;