summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHeinrich Lee Yu <heinrich@gitlab.com>2019-03-27 22:21:32 +0800
committerHeinrich Lee Yu <heinrich@gitlab.com>2019-04-05 07:56:21 +0800
commit392908ccadf81e366dea456631291c2a0532fdd8 (patch)
tree38db16b9ecca56ffd85e23c5d7760e3699496986
parentb752b579e9c84382002fe47c08282338fc3299d4 (diff)
downloadgitlab-ce-ce-10546-fix-epic-depth-validation.tar.gz
Prevent infinite loops in ObjectHierarchyce-10546-fix-epic-depth-validation
-rw-r--r--lib/gitlab/object_hierarchy.rb27
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