Skip to content

Commit

Permalink
Convert DROP CONSTRAINT SQL into OpDropMultiColumnConstraint operatio…
Browse files Browse the repository at this point in the history
…ns (#536)

Convert `DROP CONSTRAINT SQL` into an `OpDropMultiColumnConstraint`.
Because we are unable to infer the columns involved, placeholder
migrations are used.

SQL statements like the following are supported:

```sql
ALTER TABLE foo DROP CONSTRAINT constraint_foo
ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo
ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo RESTRICT
```

`CASCADE` is currently not supported and will fall back to raw SQL

Part of #504
  • Loading branch information
ryanslade authored Dec 16, 2024
1 parent 694d935 commit f4c17ff
Show file tree
Hide file tree
Showing 4 changed files with 80 additions and 2 deletions.
4 changes: 2 additions & 2 deletions pkg/migrations/rename.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ import (
)

// RenameDuplicatedColumn
// * renames a duplicated column to its original name
// * renames any foreign keys on the duplicated column to their original name.
// * Renames a duplicated column to its original name
// * Renames any foreign keys on the duplicated column to their original name.
// * Validates and renames any temporary `CHECK` constraints on the duplicated column.
func RenameDuplicatedColumn(ctx context.Context, conn db.DB, table *schema.Table, column *schema.Column) error {
const (
Expand Down
38 changes: 38 additions & 0 deletions pkg/sql2pgroll/alter_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ func convertAlterTableStmt(stmt *pgq.AlterTableStmt) (migrations.Operations, err
op, err = convertAlterTableDropColumn(stmt, alterTableCmd)
case pgq.AlterTableType_AT_ColumnDefault:
op, err = convertAlterTableSetColumnDefault(stmt, alterTableCmd)
case pgq.AlterTableType_AT_DropConstraint:
op, err = convertAlterTableDropConstraint(stmt, alterTableCmd)
}

if err != nil {
Expand Down Expand Up @@ -293,6 +295,42 @@ func convertAlterTableSetColumnDefault(stmt *pgq.AlterTableStmt, cmd *pgq.AlterT
return nil, nil
}

// convertAlterTableDropConstraint convert DROP CONSTRAINT SQL into an OpDropMultiColumnConstraint.
// Because we are unable to infer the columns involved, placeholder migrations are used.
//
// SQL statements like the following are supported:
//
// `ALTER TABLE foo DROP CONSTRAINT constraint_foo`
// `ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo`
// `ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo RESTRICT`
//
// CASCADE is currently not supported and will fall back to raw SQL
func convertAlterTableDropConstraint(stmt *pgq.AlterTableStmt, cmd *pgq.AlterTableCmd) (migrations.Operation, error) {
if !canConvertDropConstraint(cmd) {
return nil, nil
}

tableName := stmt.GetRelation().GetRelname()
if stmt.GetRelation().GetSchemaname() != "" {
tableName = stmt.GetRelation().GetSchemaname() + "." + tableName
}

return &migrations.OpDropMultiColumnConstraint{
Up: migrations.MultiColumnUpSQL{
"placeholder": PlaceHolderSQL,
},
Down: migrations.MultiColumnDownSQL{
"placeholder": PlaceHolderSQL,
},
Table: tableName,
Name: cmd.GetName(),
}, nil
}

func canConvertDropConstraint(cmd *pgq.AlterTableCmd) bool {
return cmd.Behavior != pgq.DropBehavior_DROP_CASCADE
}

func convertAlterTableDropColumn(stmt *pgq.AlterTableStmt, cmd *pgq.AlterTableCmd) (migrations.Operation, error) {
if !canConvertDropColumn(cmd) {
return nil, nil
Expand Down
19 changes: 19 additions & 0 deletions pkg/sql2pgroll/alter_table_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,22 @@ func TestConvertAlterTableStatements(t *testing.T) {
sql: "ALTER TABLE schema_a.foo ADD CONSTRAINT fk_bar_c FOREIGN KEY (a) REFERENCES schema_a.bar (c);",
expectedOp: expect.AddForeignKeyOp3,
},
{
sql: "ALTER TABLE foo DROP CONSTRAINT constraint_foo",
expectedOp: expect.OpDropConstraintWithTable("foo"),
},
{
sql: "ALTER TABLE schema.foo DROP CONSTRAINT constraint_foo",
expectedOp: expect.OpDropConstraintWithTable("schema.foo"),
},
{
sql: "ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo",
expectedOp: expect.OpDropConstraintWithTable("foo"),
},
{
sql: "ALTER TABLE foo DROP CONSTRAINT IF EXISTS constraint_foo RESTRICT",
expectedOp: expect.OpDropConstraintWithTable("foo"),
},
}

for _, tc := range tests {
Expand Down Expand Up @@ -162,6 +178,9 @@ func TestUnconvertableAlterTableStatements(t *testing.T) {
"ALTER TABLE foo ADD CONSTRAINT fk_bar_cd FOREIGN KEY (a, b) REFERENCES bar (c, d) MATCH FULL;",
// MATCH PARTIAL is not implemented in the actual parser yet
//"ALTER TABLE foo ADD CONSTRAINT fk_bar_cd FOREIGN KEY (a, b) REFERENCES bar (c, d) MATCH PARTIAL;",

// Drop constraint with CASCADE
"ALTER TABLE foo DROP CONSTRAINT bar CASCADE",
}

for _, sql := range tests {
Expand Down
21 changes: 21 additions & 0 deletions pkg/sql2pgroll/expect/drop_constraint.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// SPDX-License-Identifier: Apache-2.0

package expect

import (
"github.com/xataio/pgroll/pkg/migrations"
"github.com/xataio/pgroll/pkg/sql2pgroll"
)

func OpDropConstraintWithTable(table string) *migrations.OpDropMultiColumnConstraint {
return &migrations.OpDropMultiColumnConstraint{
Up: migrations.MultiColumnUpSQL{
"placeholder": sql2pgroll.PlaceHolderSQL,
},
Down: migrations.MultiColumnDownSQL{
"placeholder": sql2pgroll.PlaceHolderSQL,
},
Table: table,
Name: "constraint_foo",
}
}

0 comments on commit f4c17ff

Please sign in to comment.