Schema Validations: Identify foreign keys that do not match schema
Overview
Schema Validations is a framework that compares production DB and db/structure.sql
to find inconsistencies between the two.
See bundle exec rake gitlab:db:schema_checker:run
See the issues generated using Schema Validations, tagged with database-inconsistency-report label
What does this MR do and why?
Adds foreign key support to Gitlab::Database::SchemaValidation
framework
It adds the three new validators:
-
DifferentDefinitionForeignKeys
: Checks for diffs between fks there are present in thedb
and in thestructure.sql
file; -
ExtraForeignKeys
: Checks if fks are present in thedb
, but not in thestructure.sql
file; -
MissingForeignKeys
: Checks if fks are present in thestructure.sql
file, but not in thedb
;
See: !113317 (comment 1304807919)
How to set up and validate locally
1. Testing DifferentDefinitionForeignKeys (Diffs between db and db/structure.sql)
- Change some existent table definition in db/structure.sql, like
ALTER TABLE ONLY user_follow_users ADD CONSTRAINT user_follow_users_follower_id_fkey ... ON UPDATE CASCADE ON DELETE CASCADE
- Check if the
public.user_follow_users_follower_id_fkey
fk is present inDifferentDefinitionForeignKeys
output:
structure_sql = Gitlab::Database::SchemaValidation::StructureSql.new(Rails.root.join('db/structure.sql'), 'public')
database = Gitlab::Database::SchemaValidation::Database.new(ActiveRecord::Base.connection)
Gitlab::Database::SchemaValidation::Validators::DifferentDefinitionForeignKeys.new(structure_sql, database).execute
Check the output
The public.user_follow_users_follower_id_fkey foreign key has a different statement between structure.sql and database
Diff:
-FOREIGN KEY (follower_id) REFERENCES users(id) ON UPDATE CASCADE ON DELETE CASCADE
+FOREIGN KEY (follower_id) REFERENCES users(id) ON DELETE CASCADE)
2. Testing ExtraForeignKeys (that are present in the Database and not in the structure.sql)
- Remove some fks from structure.sql, like
ALTER TABLE ONLY user_follow_users ADD CONSTRAINT user_follow_users_follower_id_fkey ...
- Check if the
user_follow_users_follower_id_fkey
fk is present inExtraForeignKeys
output:
structure_sql = Gitlab::Database::SchemaValidation::StructureSql.new(Rails.root.join('db/structure.sql'), 'public')
database = Gitlab::Database::SchemaValidation::Database.new(ActiveRecord::Base.connection)
Gitlab::Database::SchemaValidation::Validators::ExtraForeignKeys.new(structure_sql, database).execute
Check the output
The foreign key public.user_follow_users_follower_id_fkey is present in the database, but not in the structure.sql file
Diff:
+FOREIGN KEY (follower_id) REFERENCES users(id) ON DELETE CASCADE
3. Testing MissingForeignKeys (that are present in the structure.sql and not in the Database)
- Drop any FK from the database, like:
ALTER TABLE timelogs DROP CONSTRAINT fk_timelogs_note_id;
- Check if the
fk_timelogs_note_id
fk is present inMissingForeignKeys
output:
structure_sql = Gitlab::Database::SchemaValidation::StructureSql.new(Rails.root.join('db/structure.sql'), 'public')
database = Gitlab::Database::SchemaValidation::Database.new(ActiveRecord::Base.connection)
Gitlab::Database::SchemaValidation::Validators::MissingForeignKeys.new(structure_sql, database).execute
Check the output
The foreign key public.fk_timelogs_note_id is missing from the database
Diff:
-FOREIGN KEY (note_id) REFERENCES notes(id) ON DELETE SET NULL
MR acceptance checklist
This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.
-
I have evaluated the MR acceptance checklist for this MR.
Related to #388016 (closed)
Edited by Leonardo da Rosa