diff options
author | Heinrich Lee Yu <heinrich@gitlab.com> | 2019-03-27 22:21:32 +0800 |
---|---|---|
committer | Heinrich Lee Yu <heinrich@gitlab.com> | 2019-04-05 07:56:21 +0800 |
commit | 392908ccadf81e366dea456631291c2a0532fdd8 (patch) | |
tree | 38db16b9ecca56ffd85e23c5d7760e3699496986 /lib/gitlab/object_hierarchy.rb | |
parent | b752b579e9c84382002fe47c08282338fc3299d4 (diff) | |
download | gitlab-ce-392908ccadf81e366dea456631291c2a0532fdd8.tar.gz |
Prevent infinite loops in ObjectHierarchyce-10546-fix-epic-depth-validation
Diffstat (limited to 'lib/gitlab/object_hierarchy.rb')
-rw-r--r-- | lib/gitlab/object_hierarchy.rb | 27 |
1 files changed, 23 insertions, 4 deletions
diff --git a/lib/gitlab/object_hierarchy.rb b/lib/gitlab/object_hierarchy.rb index 65bcf5e6ec4..38b32770e90 100644 --- a/lib/gitlab/object_hierarchy.rb +++ b/lib/gitlab/object_hierarchy.rb @@ -144,7 +144,7 @@ module Gitlab cte = SQL::RecursiveCTE.new(:base_and_ancestors) base_query = ancestors_base.except(:order) - base_query = base_query.select("1 as #{DEPTH_COLUMN}", objects_table[Arel.star]) if hierarchy_order + base_query = base_query.select("1 as #{DEPTH_COLUMN}", "ARRAY[id] AS tree_path", "false AS tree_cycle", objects_table[Arel.star]) if hierarchy_order cte << base_query @@ -154,7 +154,17 @@ module Gitlab .where(objects_table[:id].eq(cte.table[:parent_id])) .except(:order) - parent_query = parent_query.select(cte.table[DEPTH_COLUMN] + 1, objects_table[Arel.star]) if hierarchy_order + if hierarchy_order + quoted_objects_table_name = model.connection.quote_table_name(objects_table.name) + + parent_query = parent_query.select( + cte.table[DEPTH_COLUMN] + 1, + "tree_path || #{quoted_objects_table_name}.id", + "#{quoted_objects_table_name}.id = ANY(tree_path)", + objects_table[Arel.star] + ).where(cte.table[:tree_cycle].eq(false)) + end + parent_query = parent_query.where(cte.table[:parent_id].not_eq(stop_id)) if stop_id cte << parent_query @@ -167,7 +177,7 @@ module Gitlab cte = SQL::RecursiveCTE.new(:base_and_descendants) base_query = descendants_base.except(:order) - base_query = base_query.select("1 as #{DEPTH_COLUMN}", objects_table[Arel.star]) if with_depth + base_query = base_query.select("1 AS #{DEPTH_COLUMN}", "ARRAY[id] AS tree_path", "false AS tree_cycle", objects_table[Arel.star]) if with_depth cte << base_query @@ -177,7 +187,16 @@ module Gitlab .where(objects_table[:parent_id].eq(cte.table[:id])) .except(:order) - descendants_query = descendants_query.select(cte.table[DEPTH_COLUMN] + 1, objects_table[Arel.star]) if with_depth + if with_depth + quoted_objects_table_name = model.connection.quote_table_name(objects_table.name) + + descendants_query = descendants_query.select( + cte.table[DEPTH_COLUMN] + 1, + "tree_path || #{quoted_objects_table_name}.id", + "#{quoted_objects_table_name}.id = ANY(tree_path)", + objects_table[Arel.star] + ).where(cte.table[:tree_cycle].eq(false)) + end cte << descendants_query cte |