Skip to content

Commit f429ee2

Browse files
authored
sql2pgroll: Support set and drop column defaults (#526)
Support translating the following alter table statements into pgroll operations: ```sql ALTER TABLE foo COLUMN bar SET DEFAULT 'foo' ALTER TABLE foo COLUMN bar SET DEFAULT 123 ALTER TABLE foo COLUMN bar SET DEFAULT 123.456 ALTER TABLE foo COLUMN bar SET DEFAULT true ALTER TABLE foo COLUMN bar SET DEFAULT B'0101' ALTER TABLE foo COLUMN bar SET DEFAULT null ALTER TABLE foo COLUMN bar DROP DEFAULT ``` For cases where the default is set to something other than a simple literal, we fall back to raw SQL.
1 parent ac222a4 commit f429ee2

File tree

3 files changed

+143
-3
lines changed

3 files changed

+143
-3
lines changed

pkg/sql2pgroll/alter_table.go

Lines changed: 62 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,9 @@ package sql2pgroll
44

55
import (
66
"fmt"
7+
"strconv"
78

9+
"github.com/oapi-codegen/nullable"
810
pgq "github.com/pganalyze/pg_query_go/v6"
911

1012
"github.com/xataio/pgroll/pkg/migrations"
@@ -38,6 +40,8 @@ func convertAlterTableStmt(stmt *pgq.AlterTableStmt) (migrations.Operations, err
3840
op, err = convertAlterTableAddConstraint(stmt, alterTableCmd)
3941
case pgq.AlterTableType_AT_DropColumn:
4042
op, err = convertAlterTableDropColumn(stmt, alterTableCmd)
43+
case pgq.AlterTableType_AT_ColumnDefault:
44+
op, err = convertAlterTableSetColumnDefault(stmt, alterTableCmd)
4145
}
4246

4347
if err != nil {
@@ -158,11 +162,66 @@ func convertAlterTableAddUniqueConstraint(stmt *pgq.AlterTableStmt, constraint *
158162
}, nil
159163
}
160164

161-
// convertAlterTableDropColumn converts SQL statements like:
165+
// convertAlterTableSetColumnDefault converts SQL statements like:
162166
//
163-
// `ALTER TABLE foo DROP COLUMN bar
167+
// `ALTER TABLE foo COLUMN bar SET DEFAULT 'foo'`
168+
// `ALTER TABLE foo COLUMN bar SET DEFAULT 123`
169+
// `ALTER TABLE foo COLUMN bar SET DEFAULT 123.456`
170+
// `ALTER TABLE foo COLUMN bar SET DEFAULT true`
171+
// `ALTER TABLE foo COLUMN bar SET DEFAULT B'0101'`
172+
// `ALTER TABLE foo COLUMN bar SET DEFAULT null`
173+
// `ALTER TABLE foo COLUMN bar DROP DEFAULT`
164174
//
165-
// to an OpDropColumn operation.
175+
// to an OpAlterColumn operation.
176+
func convertAlterTableSetColumnDefault(stmt *pgq.AlterTableStmt, cmd *pgq.AlterTableCmd) (migrations.Operation, error) {
177+
operation := &migrations.OpAlterColumn{
178+
Table: stmt.GetRelation().GetRelname(),
179+
Column: cmd.GetName(),
180+
Down: PlaceHolderSQL,
181+
Up: PlaceHolderSQL,
182+
}
183+
184+
if c := cmd.GetDef().GetAConst(); c != nil {
185+
if c.GetIsnull() {
186+
// The default can be set to null
187+
operation.Default = nullable.NewNullNullable[string]()
188+
return operation, nil
189+
}
190+
191+
// We have a constant
192+
switch v := c.GetVal().(type) {
193+
case *pgq.A_Const_Sval:
194+
operation.Default = nullable.NewNullableWithValue(v.Sval.GetSval())
195+
case *pgq.A_Const_Ival:
196+
operation.Default = nullable.NewNullableWithValue(strconv.FormatInt(int64(v.Ival.Ival), 10))
197+
case *pgq.A_Const_Fval:
198+
operation.Default = nullable.NewNullableWithValue(v.Fval.Fval)
199+
case *pgq.A_Const_Boolval:
200+
operation.Default = nullable.NewNullableWithValue(strconv.FormatBool(v.Boolval.Boolval))
201+
case *pgq.A_Const_Bsval:
202+
operation.Default = nullable.NewNullableWithValue(v.Bsval.Bsval)
203+
default:
204+
return nil, fmt.Errorf("unknown constant type: %T", c.GetVal())
205+
}
206+
207+
return operation, nil
208+
}
209+
210+
if cmd.GetDef() != nil {
211+
// We're setting it to something other than a constant
212+
return nil, nil
213+
}
214+
215+
// We're not setting it to anything, which is the case when we are dropping it
216+
if cmd.GetBehavior() == pgq.DropBehavior_DROP_RESTRICT {
217+
operation.Default = nullable.NewNullNullable[string]()
218+
return operation, nil
219+
}
220+
221+
// Unknown case, fall back to raw SQL
222+
return nil, nil
223+
}
224+
166225
func convertAlterTableDropColumn(stmt *pgq.AlterTableStmt, cmd *pgq.AlterTableCmd) (migrations.Operation, error) {
167226
if !canConvertDropColumn(cmd) {
168227
return nil, nil

pkg/sql2pgroll/alter_table_test.go

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,34 @@ func TestConvertAlterTableStatements(t *testing.T) {
3636
sql: "ALTER TABLE foo ALTER COLUMN a TYPE text",
3737
expectedOp: expect.AlterColumnOp3,
3838
},
39+
{
40+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT 'baz'",
41+
expectedOp: expect.AlterColumnOp5,
42+
},
43+
{
44+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT 123",
45+
expectedOp: expect.AlterColumnOp6,
46+
},
47+
{
48+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT true",
49+
expectedOp: expect.AlterColumnOp9,
50+
},
51+
{
52+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT B'0101'",
53+
expectedOp: expect.AlterColumnOp10,
54+
},
55+
{
56+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT 123.456",
57+
expectedOp: expect.AlterColumnOp8,
58+
},
59+
{
60+
sql: "ALTER TABLE foo ALTER COLUMN bar DROP DEFAULT",
61+
expectedOp: expect.AlterColumnOp7,
62+
},
63+
{
64+
sql: "ALTER TABLE foo ALTER COLUMN bar SET DEFAULT null",
65+
expectedOp: expect.AlterColumnOp7,
66+
},
3967
{
4068
sql: "ALTER TABLE foo ADD CONSTRAINT bar UNIQUE (a)",
4169
expectedOp: expect.CreateConstraintOp1,
@@ -85,6 +113,9 @@ func TestUnconvertableAlterTableStatements(t *testing.T) {
85113
// CASCADE and IF EXISTS clauses are not represented by OpDropColumn
86114
"ALTER TABLE foo DROP COLUMN bar CASCADE",
87115
"ALTER TABLE foo DROP COLUMN IF EXISTS bar",
116+
117+
// Non literal default values
118+
"ALTER TABLE foo ALTER COLUMN bar SET DEFAULT now()",
88119
}
89120

90121
for _, sql := range tests {

pkg/sql2pgroll/expect/alter_column.go

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
package expect
44

55
import (
6+
"github.com/oapi-codegen/nullable"
7+
68
"github.com/xataio/pgroll/pkg/migrations"
79
"github.com/xataio/pgroll/pkg/sql2pgroll"
810
)
@@ -37,6 +39,54 @@ var AlterColumnOp4 = &migrations.OpAlterColumn{
3739
Name: ptr("b"),
3840
}
3941

42+
var AlterColumnOp5 = &migrations.OpAlterColumn{
43+
Table: "foo",
44+
Column: "bar",
45+
Default: nullable.NewNullableWithValue("baz"),
46+
Up: sql2pgroll.PlaceHolderSQL,
47+
Down: sql2pgroll.PlaceHolderSQL,
48+
}
49+
50+
var AlterColumnOp6 = &migrations.OpAlterColumn{
51+
Table: "foo",
52+
Column: "bar",
53+
Default: nullable.NewNullableWithValue("123"),
54+
Up: sql2pgroll.PlaceHolderSQL,
55+
Down: sql2pgroll.PlaceHolderSQL,
56+
}
57+
58+
var AlterColumnOp7 = &migrations.OpAlterColumn{
59+
Table: "foo",
60+
Column: "bar",
61+
Default: nullable.NewNullNullable[string](),
62+
Up: sql2pgroll.PlaceHolderSQL,
63+
Down: sql2pgroll.PlaceHolderSQL,
64+
}
65+
66+
var AlterColumnOp8 = &migrations.OpAlterColumn{
67+
Table: "foo",
68+
Column: "bar",
69+
Default: nullable.NewNullableWithValue("123.456"),
70+
Up: sql2pgroll.PlaceHolderSQL,
71+
Down: sql2pgroll.PlaceHolderSQL,
72+
}
73+
74+
var AlterColumnOp9 = &migrations.OpAlterColumn{
75+
Table: "foo",
76+
Column: "bar",
77+
Default: nullable.NewNullableWithValue("true"),
78+
Up: sql2pgroll.PlaceHolderSQL,
79+
Down: sql2pgroll.PlaceHolderSQL,
80+
}
81+
82+
var AlterColumnOp10 = &migrations.OpAlterColumn{
83+
Table: "foo",
84+
Column: "bar",
85+
Default: nullable.NewNullableWithValue("b0101"),
86+
Up: sql2pgroll.PlaceHolderSQL,
87+
Down: sql2pgroll.PlaceHolderSQL,
88+
}
89+
4090
func ptr[T any](v T) *T {
4191
return &v
4292
}

0 commit comments

Comments
 (0)