-
Notifications
You must be signed in to change notification settings - Fork 102
Add unique column without exclusive lock #679
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add unique column without exclusive lock #679
Conversation
@@ -42,6 +42,12 @@ func (o *OpAddColumn) Start(ctx context.Context, conn db.DB, latestSchema string | |||
} | |||
} | |||
|
|||
if o.Column.Unique { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In addColumn
we already add UNIQUE
to the generated SQL. You also need to change that function, so pgroll
does not add unique constraint directly to the column. Similarly to what we do for check constraints.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be specific, what we need is something like this:
diff --git a/pkg/migrations/op_add_column.go b/pkg/migrations/op_add_column.go
index 89c97753..a4125e27 100644
--- a/pkg/migrations/op_add_column.go
+++ b/pkg/migrations/op_add_column.go
@@ -252,6 +252,14 @@ func addColumn(ctx context.Context, conn db.DB, o OpAddColumn, t *schema.Table,
// This is to avoid unnecessary exclusive table locks.
o.Column.Check = nil
+ // Don't add a column with a UNIQUE constraint directly.
+ // They are handled by:
+ // - adding the column without the UNIQUE modifier
+ // - creating a UNIQUE index concurrently
+ // - adding a UNIQUE constraint USING the index on migration completion
+ // This is to avoid unnecessary exclusive table locks.
+ o.Column.Unique = false
+
o.Column.Name = TemporaryName(o.Column.Name)
columnWriter := ColumnSQLWriter{WithPK: true, Transformer: tr}
colSQL, err := columnWriter.Write(o.Column)
This ensures that the column is added without the UNIQUE
modifier.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Great start! I added a single note. Thank you for your contribution! 🎉
Thanks for the contribution! Just tested it with
after adding
Looks like now we have double unique constraint for each unique column, one with the actual column name, and one with the temporary one. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for doing this @mcadariu 👍
Left some comments, I think it's pretty close.
@@ -42,6 +42,12 @@ func (o *OpAddColumn) Start(ctx context.Context, conn db.DB, latestSchema string | |||
} | |||
} | |||
|
|||
if o.Column.Unique { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To be specific, what we need is something like this:
diff --git a/pkg/migrations/op_add_column.go b/pkg/migrations/op_add_column.go
index 89c97753..a4125e27 100644
--- a/pkg/migrations/op_add_column.go
+++ b/pkg/migrations/op_add_column.go
@@ -252,6 +252,14 @@ func addColumn(ctx context.Context, conn db.DB, o OpAddColumn, t *schema.Table,
// This is to avoid unnecessary exclusive table locks.
o.Column.Check = nil
+ // Don't add a column with a UNIQUE constraint directly.
+ // They are handled by:
+ // - adding the column without the UNIQUE modifier
+ // - creating a UNIQUE index concurrently
+ // - adding a UNIQUE constraint USING the index on migration completion
+ // This is to avoid unnecessary exclusive table locks.
+ o.Column.Unique = false
+
o.Column.Name = TemporaryName(o.Column.Name)
columnWriter := ColumnSQLWriter{WithPK: true, Transformer: tr}
colSQL, err := columnWriter.Write(o.Column)
This ensures that the column is added without the UNIQUE
modifier.
I think this is a result of #679 (comment) and I'd expect it to be resolved when we make that change. |
… convention Co-authored-by: Andrew Farries <andyrb@gmail.com>
…th the two-step approach that avoids the exclusive locks
Thanks all! 🙏 To check the latest version I first ran Ahmet's scenario in the comment above. In {
"name": "03_add_column_to_products",
"operations": [
{
"add_column": {
"table": "products",
"up": "UPPER(name)",
"column": {
"name": "description",
"type": "varchar(255)",
"nullable": true,
"unique": true
}
}
},
{
"add_column": {
"table": "products",
"column": {
"name": "stock",
"type": "int",
"nullable": false,
"default": "100",
"unique": true
}
}
},
{
"add_column": {
"table": "products",
"up": "name || '-category'",
"column": {
"name": "category",
"type": "varchar(255)",
"nullable": false,
"unique": true
}
}
}
]
} The result looks OK to me now:
The Next I ran the scenario from the issue description (#644). After step 2, I ran this:
Then ran step 3. I saw only |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for the contribution and for making pgroll better! 😄
Hello @mcadariu, thank you for your contribution to pgroll 🎉 I got so happy to see a familiar face in our project! Have a nice week ahead. |
Hi @gulcin! |
Hi,
Awesome project! 👍
This PR is an attempt at fixing #644.
Looking forward to your feedback!