FIX: Restoring backup could fail due to missing discourse_functions (#29332)

Database dumps sometimes reference functions in the `discourse_functions` schema. It's possible that some of these functions have been dropped in a newer version of Discourse. In that case, restoring an older backup will fail with a `ERROR:  function discourse_functions.something_something() does not exist` error. The restore functionality contains a workaround for that problem, but it didn't work with functions created in plugin migrations.

This commit adds support for temporarily creating missing `discourse_functions` from plugins. And it adds a simple check if the DB migration file even contains the required `DROPPED_TABLES` or `DROPPED_COLUMNS` constant. We don't need to create an instance of the DB migration class unless one of those constants is used. This makes the restore slightly faster and works around a problem with migrations that execute without `up` or `down` methods (e.g. `BackfillChatChannelAndThreadLastMessageIdsPostMigrate`).
This commit is contained in:
Gerhard Schlager 2024-10-22 23:13:01 +09:00 committed by GitHub
parent cf44502cdf
commit 07ff21d045
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 9 additions and 4 deletions

View File

@ -49,9 +49,11 @@ module BackupRestore
ActiveRecord::Base.connection.drop_schema(BACKUP_SCHEMA) if backup_schema_dropable? ActiveRecord::Base.connection.drop_schema(BACKUP_SCHEMA) if backup_schema_dropable?
end end
def self.core_migration_files def self.all_migration_files
Dir[Rails.root.join(Migration::SafeMigrate.post_migration_path, "**/*.rb")] + Dir[Rails.root.join(Migration::SafeMigrate.post_migration_path, "**/*.rb")] +
Dir[Rails.root.join("db/migrate/*.rb")] Dir[Rails.root.join("db/migrate/*.rb")] +
Dir[Rails.root.join("plugins/**", Migration::SafeMigrate.post_migration_path, "**/*.rb")] +
Dir[Rails.root.join("plugins/**", "db/migrate/*.rb")]
end end
protected protected
@ -162,7 +164,10 @@ module BackupRestore
@created_functions_for_table_columns = [] @created_functions_for_table_columns = []
all_readonly_table_columns = [] all_readonly_table_columns = []
DatabaseRestorer.core_migration_files.each do |path| DatabaseRestorer.all_migration_files.each do |path|
file_content = File.read(path)
next if file_content.exclude?("DROPPED_TABLES") && file_content.exclude?("DROPPED_COLUMNS")
require path require path
class_name = File.basename(path, ".rb").sub(/\A\d+_/, "").camelize class_name = File.basename(path, ".rb").sub(/\A\d+_/, "").camelize
migration_class = class_name.constantize migration_class = class_name.constantize

View File

@ -157,7 +157,7 @@ RSpec.describe BackupRestore::DatabaseRestorer do
describe "readonly functions" do describe "readonly functions" do
before do before do
BackupRestore::DatabaseRestorer.stubs(:core_migration_files).returns( BackupRestore::DatabaseRestorer.stubs(:all_migration_files).returns(
Dir[Rails.root.join("spec/fixtures/db/post_migrate/drop_column/**/*.rb")], Dir[Rails.root.join("spec/fixtures/db/post_migrate/drop_column/**/*.rb")],
) )
end end