CHECK constraints
Use CHECK constraints to enforce data integrity rules beyond NOT NULL requirements.
For NOT NULL constraints specifically, see NOT NULL constraints.
Add a CHECK constraint to a new column with a default value
When you add a new column with a CHECK constraint and a default value that satisfies
the constraint, you can skip constraint validation in the initial migration.
Validate the constraint in a post-deployment migration instead.
This approach avoids a full table scan on large tables because:
- Existing rows resolve to the default value through the PostgreSQL fast defaults mechanism, so the constraint is already satisfied.
- A
NOT VALIDconstraint is still enforced on new inserts and updates, so future rows cannot violate it.
This pattern only applies when the default value expression itself satisfies the
constraint. For example, a literal string value like 'active' is safe, but a function
call or expression that could produce invalid values should not use this pattern.
Add the column with constraint and default value
Create a regular migration that adds the column and the CHECK constraint with validate: false:
class AddStatusCheckToProjects < Gitlab::Database::Migration[2.1]
def change
add_column :projects, :status, :string, default: 'active'
add_check_constraint :projects, "status IN ('active', 'inactive')", name: 'check_status_valid', validate: false
end
endValidate the constraint
After you have added the column, in a post-deployment migration in the same release, validate the constraint. See the migration style guide for more information on post-deployment migrations:
class ValidateProjectsStatusCheckConstraint < Gitlab::Database::Migration[2.1]
disable_ddl_transaction!
def up
validate_check_constraint :projects, name: 'check_status_valid'
end
def down
# no-op
end
end