diff options
-rw-r--r-- | lib/gitlab/database/migration_helpers.rb | 39 | ||||
-rw-r--r-- | spec/lib/gitlab/database/migration_helpers_spec.rb | 29 |
2 files changed, 64 insertions, 4 deletions
diff --git a/lib/gitlab/database/migration_helpers.rb b/lib/gitlab/database/migration_helpers.rb index 44ca434056f..1634fe4e9cb 100644 --- a/lib/gitlab/database/migration_helpers.rb +++ b/lib/gitlab/database/migration_helpers.rb @@ -900,11 +900,42 @@ into similar problems in the future (e.g. when new tables are created). end end - # Rails' index_exists? doesn't work when you only give it a table and index - # name. As such we have to use some extra code to check if an index exists for - # a given name. + # Fetches indexes on a column by name for postgres. + # + # This will include indexes using an expression on the column, for example: + # `CREATE INDEX CONCURRENTLY index_name ON table (LOWER(column));` + # + # For mysql, it falls back to the default ActiveRecord implementation that + # will not find custom indexes. But it will select by name without passing + # a column. + # + # We can remove this when upgrading to Rails 5 with an updated `index_exists?`: + # - https://github.com/rails/rails/commit/edc2b7718725016e988089b5fb6d6fb9d6e16882 + # + # Or this can be removed when we no longer support postgres < 9.5, so we + # can use `CREATE INDEX IF NOT EXISTS`. def index_exists_by_name?(table, index) - indexes(table).map(&:name).include?(index) + # We can't fall back to the normal `index_exists?` method because that + # does not find indexes without passing a column name. + if indexes(table).map(&:name).include?(index.to_s) + true + elsif Gitlab::Database.postgresql? + postgres_exists_by_name?(table, index) + else + false + end + end + + def postgres_exists_by_name?(table, name) + index_sql = <<~SQL + SELECT COUNT(*) + FROM pg_index + JOIN pg_class i ON (indexrelid=i.oid) + JOIN pg_class t ON (indrelid=t.oid) + WHERE i.relname = '#{name}' AND t.relname = '#{table}' + SQL + + connection.select_value(index_sql).to_i > 0 end end end diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb index a41b7f4e104..280f799f2ab 100644 --- a/spec/lib/gitlab/database/migration_helpers_spec.rb +++ b/spec/lib/gitlab/database/migration_helpers_spec.rb @@ -1211,4 +1211,33 @@ describe Gitlab::Database::MigrationHelpers do expect(model.perform_background_migration_inline?).to eq(false) end end + + describe '#index_exists_by_name?' do + it 'returns true if an index exists' do + expect(model.index_exists_by_name?(:projects, 'index_projects_on_path')) + .to be_truthy + end + + it 'returns false if the index does not exist' do + expect(model.index_exists_by_name?(:projects, 'this_does_not_exist')) + .to be_falsy + end + + context 'when an index with a function exists', :postgresql do + before do + ActiveRecord::Base.connection.execute( + 'CREATE INDEX test_index ON projects (LOWER(path));' + ) + end + + after do + 'DROP INDEX IF EXISTS test_index;' + end + + it 'returns true if an index exists' do + expect(model.index_exists_by_name?(:projects, 'test_index')) + .to be_truthy + end + end + end end |