Reduces the number of subqueries when searching with many custom fields set as searchable (#15781).
git-svn-id: http://svn.redmine.org/redmine/trunk@12481 e93f8b46-1217-0410-a6f0-8f06a7374b81
This commit is contained in:
parent
7087dbb5b4
commit
77ac3b7891
|
@ -173,17 +173,18 @@ class CustomField < ActiveRecord::Base
|
||||||
format.join_for_order_statement(self)
|
format.join_for_order_statement(self)
|
||||||
end
|
end
|
||||||
|
|
||||||
def visibility_by_project_condition(project_key=nil, user=User.current)
|
def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
|
||||||
if visible? || user.admin?
|
if visible? || user.admin?
|
||||||
"1=1"
|
"1=1"
|
||||||
elsif user.anonymous?
|
elsif user.anonymous?
|
||||||
"1=0"
|
"1=0"
|
||||||
else
|
else
|
||||||
project_key ||= "#{self.class.customized_class.table_name}.project_id"
|
project_key ||= "#{self.class.customized_class.table_name}.project_id"
|
||||||
|
id_column ||= id
|
||||||
"#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
|
"#{project_key} IN (SELECT DISTINCT m.project_id FROM #{Member.table_name} m" +
|
||||||
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
|
" INNER JOIN #{MemberRole.table_name} mr ON mr.member_id = m.id" +
|
||||||
" INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
|
" INNER JOIN #{table_name_prefix}custom_fields_roles#{table_name_suffix} cfr ON cfr.role_id = mr.role_id" +
|
||||||
" WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id})"
|
" WHERE m.user_id = #{user.id} AND cfr.custom_field_id = #{id_column})"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -28,13 +28,14 @@ class IssueCustomField < CustomField
|
||||||
super || (roles & user.roles_for_project(project)).present?
|
super || (roles & user.roles_for_project(project)).present?
|
||||||
end
|
end
|
||||||
|
|
||||||
def visibility_by_project_condition(*args)
|
def visibility_by_project_condition(project_key=nil, user=User.current, id_column=nil)
|
||||||
sql = super
|
sql = super
|
||||||
additional_sql = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id})"
|
id_column ||= id
|
||||||
unless is_for_all?
|
tracker_condition = "#{Issue.table_name}.tracker_id IN (SELECT tracker_id FROM #{table_name_prefix}custom_fields_trackers#{table_name_suffix} WHERE custom_field_id = #{id_column})"
|
||||||
additional_sql << " AND #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id})"
|
project_condition = "EXISTS (SELECT 1 FROM #{CustomField.table_name} ifa WHERE ifa.is_for_all = #{connection.quoted_true} AND ifa.id = #{id_column})" +
|
||||||
end
|
" OR #{Issue.table_name}.project_id IN (SELECT project_id FROM #{table_name_prefix}custom_fields_projects#{table_name_suffix} WHERE custom_field_id = #{id_column})"
|
||||||
"((#{sql}) AND (#{additional_sql}))"
|
|
||||||
|
"((#{sql}) AND (#{tracker_condition}) AND (#{project_condition}))"
|
||||||
end
|
end
|
||||||
|
|
||||||
def validate_custom_field
|
def validate_custom_field
|
||||||
|
|
|
@ -82,11 +82,16 @@ module Redmine
|
||||||
|
|
||||||
if !options[:titles_only] && searchable_options[:search_custom_fields]
|
if !options[:titles_only] && searchable_options[:search_custom_fields]
|
||||||
searchable_custom_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true)
|
searchable_custom_fields = CustomField.where(:type => "#{self.name}CustomField", :searchable => true)
|
||||||
searchable_custom_fields.each do |field|
|
fields_by_visibility = searchable_custom_fields.group_by {|field|
|
||||||
sql = "#{table_name}.id IN (SELECT customized_id FROM #{CustomValue.table_name}" +
|
field.visibility_by_project_condition(searchable_options[:project_key], user, "cfs.custom_field_id")
|
||||||
" WHERE customized_type='#{self.name}' AND customized_id=#{table_name}.id AND LOWER(value) LIKE ?" +
|
}
|
||||||
" AND #{CustomValue.table_name}.custom_field_id = #{field.id})" +
|
# only 1 subquery for all custom fields with the same visibility statement
|
||||||
" AND #{field.visibility_by_project_condition(searchable_options[:project_key], user)}"
|
fields_by_visibility.each do |visibility, fields|
|
||||||
|
ids = fields.map(&:id).join(',')
|
||||||
|
sql = "#{table_name}.id IN (SELECT cfs.customized_id FROM #{CustomValue.table_name} cfs" +
|
||||||
|
" WHERE cfs.customized_type='#{self.name}' AND cfs.customized_id=#{table_name}.id AND LOWER(cfs.value) LIKE ?" +
|
||||||
|
" AND cfs.custom_field_id IN (#{ids})" +
|
||||||
|
" AND #{visibility})"
|
||||||
token_clauses << sql
|
token_clauses << sql
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue