Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/lib/gitlab/database/migration_helpers_spec.rb')
-rw-r--r--spec/lib/gitlab/database/migration_helpers_spec.rb110
1 files changed, 102 insertions, 8 deletions
diff --git a/spec/lib/gitlab/database/migration_helpers_spec.rb b/spec/lib/gitlab/database/migration_helpers_spec.rb
index 9df23776be8..3f6528558b1 100644
--- a/spec/lib/gitlab/database/migration_helpers_spec.rb
+++ b/spec/lib/gitlab/database/migration_helpers_spec.rb
@@ -2,7 +2,7 @@
require 'spec_helper'
-RSpec.describe Gitlab::Database::MigrationHelpers do
+RSpec.describe Gitlab::Database::MigrationHelpers, feature_category: :database do
include Database::TableSchemaHelpers
include Database::TriggerHelpers
@@ -928,13 +928,13 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
it 'references the custom target columns when provided', :aggregate_failures do
expect(model).to receive(:with_lock_retries).and_yield
expect(model).to receive(:execute).with(
- "ALTER TABLE projects\n" \
- "ADD CONSTRAINT fk_multiple_columns\n" \
- "FOREIGN KEY \(partition_number, user_id\)\n" \
- "REFERENCES users \(partition_number, id\)\n" \
- "ON UPDATE CASCADE\n" \
- "ON DELETE CASCADE\n" \
- "NOT VALID;\n"
+ "ALTER TABLE projects " \
+ "ADD CONSTRAINT fk_multiple_columns " \
+ "FOREIGN KEY \(partition_number, user_id\) " \
+ "REFERENCES users \(partition_number, id\) " \
+ "ON UPDATE CASCADE " \
+ "ON DELETE CASCADE " \
+ "NOT VALID;"
)
model.add_concurrent_foreign_key(
@@ -979,6 +979,80 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
end
end
end
+
+ context 'when creating foreign key on a partitioned table' do
+ let(:source) { :_test_source_partitioned_table }
+ let(:dest) { :_test_dest_partitioned_table }
+ let(:args) { [source, dest] }
+ let(:options) { { column: [:partition_id, :owner_id], target_column: [:partition_id, :id] } }
+
+ before do
+ model.execute(<<~SQL)
+ CREATE TABLE public.#{source} (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ owner_id bigint NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ ) PARTITION BY LIST(partition_id);
+
+ CREATE TABLE #{source}_1
+ PARTITION OF public.#{source}
+ FOR VALUES IN (1);
+
+ CREATE TABLE public.#{dest} (
+ id serial NOT NULL,
+ partition_id serial NOT NULL,
+ PRIMARY KEY (id, partition_id)
+ );
+ SQL
+ end
+
+ it 'creates the FK without using NOT VALID', :aggregate_failures do
+ allow(model).to receive(:execute).and_call_original
+
+ expect(model).to receive(:with_lock_retries).and_yield
+
+ expect(model).to receive(:execute).with(
+ "ALTER TABLE #{source} " \
+ "ADD CONSTRAINT fk_multiple_columns " \
+ "FOREIGN KEY \(partition_id, owner_id\) " \
+ "REFERENCES #{dest} \(partition_id, id\) " \
+ "ON UPDATE CASCADE ON DELETE CASCADE ;"
+ )
+
+ model.add_concurrent_foreign_key(
+ *args,
+ name: :fk_multiple_columns,
+ on_update: :cascade,
+ allow_partitioned: true,
+ **options
+ )
+ end
+
+ it 'raises an error if allow_partitioned is not set' do
+ expect(model).not_to receive(:with_lock_retries).and_yield
+ expect(model).not_to receive(:execute).with(/FOREIGN KEY/)
+
+ expect { model.add_concurrent_foreign_key(*args, **options) }
+ .to raise_error ArgumentError, /use add_concurrent_partitioned_foreign_key/
+ end
+
+ context 'when the reverse_lock_order flag is set' do
+ it 'explicitly locks the tables in target-source order', :aggregate_failures do
+ expect(model).to receive(:with_lock_retries).and_call_original
+ expect(model).to receive(:disable_statement_timeout).and_call_original
+ expect(model).to receive(:statement_timeout_disabled?).and_return(false)
+ expect(model).to receive(:execute).with(/SET statement_timeout TO/)
+ expect(model).to receive(:execute).ordered.with(/VALIDATE CONSTRAINT/)
+ expect(model).to receive(:execute).ordered.with(/RESET statement_timeout/)
+
+ expect(model).to receive(:execute).with("LOCK TABLE #{dest}, #{source} IN ACCESS EXCLUSIVE MODE")
+ expect(model).to receive(:execute).with(/REFERENCES #{dest} \(partition_id, id\)/)
+
+ model.add_concurrent_foreign_key(*args, reverse_lock_order: true, allow_partitioned: true, **options)
+ end
+ end
+ end
end
end
@@ -1049,6 +1123,8 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
describe '#foreign_key_exists?' do
let(:referenced_table_name) { '_test_gitlab_main_referenced' }
let(:referencing_table_name) { '_test_gitlab_main_referencing' }
+ let(:schema) { 'public' }
+ let(:identifier) { "#{schema}.#{referencing_table_name}" }
before do
model.connection.execute(<<~SQL)
@@ -1085,6 +1161,10 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
expect(model.foreign_key_exists?(referencing_table_name, target_table)).to be_truthy
end
+ it 'finds existing foreign_keys by identifier' do
+ expect(model.foreign_key_exists?(identifier, target_table)).to be_truthy
+ end
+
it 'compares by column name if given' do
expect(model.foreign_key_exists?(referencing_table_name, target_table, column: :user_id)).to be_falsey
end
@@ -2890,4 +2970,18 @@ RSpec.describe Gitlab::Database::MigrationHelpers do
it { is_expected.to be_falsey }
end
end
+
+ describe "#table_partitioned?" do
+ subject { model.table_partitioned?(table_name) }
+
+ let(:table_name) { 'p_ci_builds_metadata' }
+
+ it { is_expected.to be_truthy }
+
+ context 'with a non-partitioned table' do
+ let(:table_name) { 'users' }
+
+ it { is_expected.to be_falsey }
+ end
+ end
end