From 9dc93a4519d9d5d7be48ff274127136236a3adb3 Mon Sep 17 00:00:00 2001 From: GitLab Bot Date: Tue, 20 Apr 2021 23:50:22 +0000 Subject: Add latest changes from gitlab-org/gitlab@13-11-stable-ee --- lib/gitlab/object_hierarchy.rb | 46 ++++++++++++++++++++++++++++++++++-------- 1 file changed, 38 insertions(+), 8 deletions(-) (limited to 'lib/gitlab/object_hierarchy.rb') diff --git a/lib/gitlab/object_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index b1a1045a1f0..9a74266693b 100644 --- a/lib/gitlab/object_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -68,13 +68,22 @@ module Gitlab expose_depth = hierarchy_order.present? hierarchy_order ||= :asc - recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct - # if hierarchy_order is given, the calculated `depth` should be present in SELECT if expose_depth + recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all).distinct read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: hierarchy_order)) else - read_only(remove_depth_and_maintain_order(recursive_query, hierarchy_order: hierarchy_order)) + recursive_query = base_and_ancestors_cte(upto).apply_to(model.all) + + if skip_ordering? + recursive_query = recursive_query.distinct + else + recursive_query = recursive_query.reselect(*recursive_query.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct + recursive_query = model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)) + recursive_query = remove_depth_and_maintain_order(recursive_query, hierarchy_order: hierarchy_order) + end + + read_only(recursive_query) end else recursive_query = base_and_ancestors_cte(upto, hierarchy_order).apply_to(model.all) @@ -93,12 +102,21 @@ module Gitlab def base_and_descendants(with_depth: false) if use_distinct? # Always calculate `depth`, remove it later if with_depth is false - base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct - if with_depth - read_only(model.from(Arel::Nodes::As.new(recursive_query.arel, objects_table)).order(depth: :asc)) + base_cte = base_and_descendants_cte(with_depth: true).apply_to(model.all).distinct + read_only(model.from(Arel::Nodes::As.new(base_cte.arel, objects_table)).order(depth: :asc)) else - read_only(remove_depth_and_maintain_order(base_cte, hierarchy_order: :asc)) + base_cte = base_and_descendants_cte.apply_to(model.all) + + if skip_ordering? + base_cte = base_cte.distinct + else + base_cte = base_cte.reselect(*base_cte.arel.projections, 'ROW_NUMBER() OVER () as depth').distinct + base_cte = model.from(Arel::Nodes::As.new(base_cte.arel, objects_table)) + base_cte = remove_depth_and_maintain_order(base_cte, hierarchy_order: :asc) + end + + read_only(base_cte) end else read_only(base_and_descendants_cte(with_depth: with_depth).apply_to(model.all)) @@ -161,7 +179,19 @@ module Gitlab # Use distinct on the Namespace queries to avoid bad planner behavior in PG11. def use_distinct? - (model <= Namespace) && options[:use_distinct] + return unless model <= Namespace + # Global use_distinct_for_all_object_hierarchy takes precedence over use_distinct_in_object_hierarchy + return true if Feature.enabled?(:use_distinct_for_all_object_hierarchy) + return options[:use_distinct] if options.key?(:use_distinct) + + false + end + + # Skips the extra ordering when using distinct on the namespace queries + def skip_ordering? + return options[:skip_ordering] if options.key?(:skip_ordering) + + false end # Remove the extra `depth` field using an INNER JOIN to avoid breaking UNION queries -- cgit v1.2.3