-
Notifications
You must be signed in to change notification settings - Fork 27
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
Online not null constraints: SET NOT NULL
#83
Conversation
081f29e
to
41e3d6f
Compare
bdb3706
to
61969a5
Compare
61969a5
to
25af9f2
Compare
25af9f2
to
9c0af84
Compare
@@ -45,6 +45,7 @@ $ pg-schema-diff plan --dsn "postgres://postgres:postgres@localhost:5432/postgre | |||
* Online index replacement: If some index is changed, the new version will be built before the old version is dropped, preventing a window where no index is backing queries | |||
* Online check constraint builds: Check constraints are added as `INVALID` before being validated, eliminating the need | |||
for a long access-exclusive lock on the table | |||
* Online `ALTER ... SET NOT NULL` using check constraints to eliminate the need for an access-exclusive lock on the table |
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.
Once this gets merged in, I'll cut a follow-up PR that highlights this behavior via an example, since I think showing rather than telling will work better.
SET NOT NULL
"ALTER TABLE \"public\".\"foobar\" ADD CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\" CHECK(\"foobar\" IS NOT NULL) NOT VALID", | ||
"ALTER TABLE \"public\".\"foobar\" VALIDATE CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\"", | ||
"ALTER TABLE \"public\".\"foobar\" ALTER COLUMN \"foobar\" SET NOT NULL", | ||
"ALTER TABLE \"public\".\"foobar\" DROP CONSTRAINT \"not_null_10111213-1415-4617-9819-1a1b1c1d1e1f\"", |
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.
super cool
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.
Yeah, this format is much better than the manually "schema" defined tests. We should migrate all of those over except for the schemas that are impossible to recreate via DDL, e.g., invalid indexes.
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.
Looks great! Some thoughts but all non-blocking.
"ALTER TABLE \"public\".\"foobar\" ADD CONSTRAINT \"foobar\" CHECK((foobar IS NOT NULL)) NOT VALID", | ||
"ALTER TABLE \"public\".\"foobar\" VALIDATE CONSTRAINT \"foobar\"", | ||
"ALTER TABLE \"public\".\"foobar\" ALTER COLUMN \"foobar\" SET NOT NULL", |
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.
Amazing that this works without adding a system check constraint
pkg/diff/sql_generator.go
Outdated
return schema.CheckConstraint{}, fmt.Errorf("generating uuid: %w", err) | ||
} | ||
return schema.CheckConstraint{ | ||
Name: fmt.Sprintf("not_null_%s", uuid.String()), |
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.
thought: maybe we can fit in pg_schema_diff to the identifier somehow? That'd help with debugging/confusion if one of these are left around, but it's not critical
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 point!
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.
I want to update the temporary indexes to use this pattern, but I'm going to save that for a subsequent PR, since I also am going to switch to the UUID's to base64 encoded to make them smaller.
pkg/diff/sql_generator.go
Outdated
|
||
if isOnPreExistingColumn && isValidNotNullCC(con) { | ||
// If the NOT NULL check constraint is on a pre-existing column, then we should ensure it is added before | ||
// the column. |
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.
Is this correction right?
// the column. | |
// the column alter. |
pkg/diff/sql_generator.go
Outdated
// If it's a not-null check constraint, we can drop the check constraint whenever convenient, e.g., after | ||
// the column has been altered because `NOT NULL` does not depend on the type of the column. | ||
// For all other check constraints, they can rely on the type of the column. Thus, we should drop these | ||
// check constraint before any columns are altered because the new type might not be compatible with the old | ||
// check constraint. |
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.
Is there value to allowing the NN constraints to be dropped whenever? Maybe it'd be best to add the dependency regardless just for consistency among the constraint types?
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.
It's critical we drop this last, which the topographical sort does if an obj has no deps because of the scenario where we're deleting a valid not null constraint AND changing a column to NOT NULL.
I imagine the scenario above is pretty common because it would occur for a half-complete migration, where the valid constraint was added but the SET NOT NULL
never ran
return nil, fmt.Errorf("cycle detected: %+v, %+v", graph, incomingEdgeCountByVertex) | ||
dotSB := strings.Builder{} | ||
if err := EncodeDOT(g, &dotSB, true); err != nil { | ||
dotSB.Reset() |
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.
The dot encoding has been super useful for debugging! @kevinmingtarja
0e15973
to
4953a1b
Compare
4953a1b
to
27a1517
Compare
372c33d
to
7e891de
Compare
7e891de
to
ab005bd
Compare
Description
Use check constraints to make
SET NOT NULL
constraints onlineOne exception: This does not yet work for partitioned tables, since we don't yet support local check constraints
Motivation
#82
Testing
Tested via unit tests