Commit cff8d9ac authored by Robert Speicher's avatar Robert Speicher

Merge branch 'fix-share-with-group-lock-update' into 'master'

Fix setting share_with_group_lock

Closes #37916

See merge request gitlab-org/gitlab-ce!14300
parents 6ecb3b01 ac702af8
...@@ -231,6 +231,13 @@ class Namespace < ActiveRecord::Base ...@@ -231,6 +231,13 @@ class Namespace < ActiveRecord::Base
end end
def force_share_with_group_lock_on_descendants def force_share_with_group_lock_on_descendants
descendants.update_all(share_with_group_lock: true) return unless Group.supports_nested_groups?
# We can't use `descendants.update_all` since Rails will throw away the WITH
# RECURSIVE statement. We also can't use WHERE EXISTS since we can't use
# different table aliases, hence we're just using WHERE IN. Since we have a
# maximum of 20 nested groups this should be fine.
Namespace.where(id: descendants.select(:id))
.update_all(share_with_group_lock: true)
end end
end end
module Gitlab
module Database
# Module that can be injected into a ActiveRecord::Relation to make it
# read-only.
module ReadOnlyRelation
[:delete, :delete_all, :update, :update_all].each do |method|
define_method(method) do |*args|
raise(
ActiveRecord::ReadOnlyRecord,
"This relation is marked as read-only"
)
end
end
end
end
end
...@@ -22,7 +22,7 @@ module Gitlab ...@@ -22,7 +22,7 @@ module Gitlab
def base_and_ancestors def base_and_ancestors
return ancestors_base unless Group.supports_nested_groups? return ancestors_base unless Group.supports_nested_groups?
base_and_ancestors_cte.apply_to(model.all) read_only(base_and_ancestors_cte.apply_to(model.all))
end end
# Returns a relation that includes the descendants_base set of groups # Returns a relation that includes the descendants_base set of groups
...@@ -30,7 +30,7 @@ module Gitlab ...@@ -30,7 +30,7 @@ module Gitlab
def base_and_descendants def base_and_descendants
return descendants_base unless Group.supports_nested_groups? return descendants_base unless Group.supports_nested_groups?
base_and_descendants_cte.apply_to(model.all) read_only(base_and_descendants_cte.apply_to(model.all))
end end
# Returns a relation that includes the base groups, their ancestors, # Returns a relation that includes the base groups, their ancestors,
...@@ -67,11 +67,13 @@ module Gitlab ...@@ -67,11 +67,13 @@ module Gitlab
union = SQL::Union.new([model.unscoped.from(ancestors_table), union = SQL::Union.new([model.unscoped.from(ancestors_table),
model.unscoped.from(descendants_table)]) model.unscoped.from(descendants_table)])
model relation = model
.unscoped .unscoped
.with .with
.recursive(ancestors.to_arel, descendants.to_arel) .recursive(ancestors.to_arel, descendants.to_arel)
.from("(#{union.to_sql}) #{model.table_name}") .from("(#{union.to_sql}) #{model.table_name}")
read_only(relation)
end end
private private
...@@ -107,5 +109,12 @@ module Gitlab ...@@ -107,5 +109,12 @@ module Gitlab
def groups_table def groups_table
model.arel_table model.arel_table
end end
def read_only(relation)
# relations using a CTE are not safe to use with update_all as it will
# throw away the CTE, hence we mark them as read-only.
relation.extend(Gitlab::Database::ReadOnlyRelation)
relation
end
end end
end end
...@@ -23,6 +23,11 @@ describe Gitlab::GroupHierarchy, :postgresql do ...@@ -23,6 +23,11 @@ describe Gitlab::GroupHierarchy, :postgresql do
expect(relation).to include(parent, child1, child2) expect(relation).to include(parent, child1, child2)
end end
it 'does not allow the use of #update_all' do
expect { relation.update_all(share_with_group_lock: false) }
.to raise_error(ActiveRecord::ReadOnlyRecord)
end
end end
describe '#base_and_descendants' do describe '#base_and_descendants' do
...@@ -43,6 +48,11 @@ describe Gitlab::GroupHierarchy, :postgresql do ...@@ -43,6 +48,11 @@ describe Gitlab::GroupHierarchy, :postgresql do
expect(relation).to include(parent, child1, child2) expect(relation).to include(parent, child1, child2)
end end
it 'does not allow the use of #update_all' do
expect { relation.update_all(share_with_group_lock: false) }
.to raise_error(ActiveRecord::ReadOnlyRecord)
end
end end
describe '#all_groups' do describe '#all_groups' do
...@@ -73,5 +83,10 @@ describe Gitlab::GroupHierarchy, :postgresql do ...@@ -73,5 +83,10 @@ describe Gitlab::GroupHierarchy, :postgresql do
expect(relation).to include(child2) expect(relation).to include(child2)
end end
it 'does not allow the use of #update_all' do
expect { relation.update_all(share_with_group_lock: false) }
.to raise_error(ActiveRecord::ReadOnlyRecord)
end
end end
end end
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment