summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--app/models/user.rb4
-rw-r--r--db/migrate/20180215181245_users_name_lower_index.rb29
-rw-r--r--db/schema.rb2
-rw-r--r--lib/gitlab/sql/pattern.rb16
-rw-r--r--lib/tasks/migrate/setup_postgresql.rake2
-rw-r--r--spec/lib/gitlab/sql/pattern_spec.rb6
6 files changed, 54 insertions, 5 deletions
diff --git a/app/models/user.rb b/app/models/user.rb
index f5eeba27572..8610ca27b7f 100644
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -327,8 +327,8 @@ class User < ActiveRecord::Base
SQL
where(
- fuzzy_arel_match(:name, query)
- .or(fuzzy_arel_match(:username, query))
+ fuzzy_arel_match(:name, query, lower_exact_match: true)
+ .or(fuzzy_arel_match(:username, query, lower_exact_match: true))
.or(arel_table[:email].eq(query))
).reorder(order % { query: ActiveRecord::Base.connection.quote(query) }, :name)
end
diff --git a/db/migrate/20180215181245_users_name_lower_index.rb b/db/migrate/20180215181245_users_name_lower_index.rb
new file mode 100644
index 00000000000..d3f68cb7d45
--- /dev/null
+++ b/db/migrate/20180215181245_users_name_lower_index.rb
@@ -0,0 +1,29 @@
+# See http://doc.gitlab.com/ce/development/migration_style_guide.html
+# for more information on how to write migrations for GitLab.
+
+class UsersNameLowerIndex < ActiveRecord::Migration
+ include Gitlab::Database::MigrationHelpers
+
+ # Set this constant to true if this migration requires downtime.
+ DOWNTIME = false
+ INDEX_NAME = 'index_on_users_name_lower'
+
+ disable_ddl_transaction!
+
+ def up
+ return unless Gitlab::Database.postgresql?
+
+ # On GitLab.com this produces an index with a size of roughly 60 MB.
+ execute "CREATE INDEX CONCURRENTLY #{INDEX_NAME} ON users (LOWER(name))"
+ end
+
+ def down
+ return unless Gitlab::Database.postgresql?
+
+ if supports_drop_index_concurrently?
+ execute "DROP INDEX CONCURRENTLY IF EXISTS #{INDEX_NAME}"
+ else
+ execute "DROP INDEX IF EXISTS #{INDEX_NAME}"
+ end
+ end
+end
diff --git a/db/schema.rb b/db/schema.rb
index 409d1ac7644..c0ce87302cf 100644
--- a/db/schema.rb
+++ b/db/schema.rb
@@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
-ActiveRecord::Schema.define(version: 20180213131630) do
+ActiveRecord::Schema.define(version: 20180215181245) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
diff --git a/lib/gitlab/sql/pattern.rb b/lib/gitlab/sql/pattern.rb
index 5f0c98cb5a4..0e3a93aa236 100644
--- a/lib/gitlab/sql/pattern.rb
+++ b/lib/gitlab/sql/pattern.rb
@@ -25,7 +25,11 @@ module Gitlab
query.length >= MIN_CHARS_FOR_PARTIAL_MATCHING
end
- def fuzzy_arel_match(column, query)
+ # column - The column name to search in.
+ # query - The text to search for.
+ # lower_exact_match - When set to `true` we'll fall back to using
+ # `LOWER(column) = query` instead of using `ILIKE`.
+ def fuzzy_arel_match(column, query, lower_exact_match: false)
query = query.squish
return nil unless query.present?
@@ -34,9 +38,17 @@ module Gitlab
if words.any?
words.map { |word| arel_table[column].matches(to_pattern(word)) }.reduce(:and)
else
+ sanitized_query = sanitize_sql_like(query)
+
# No words of at least 3 chars, but we can search for an exact
# case insensitive match with the query as a whole
- arel_table[column].matches(sanitize_sql_like(query))
+ if lower_exact_match
+ Arel::Nodes::NamedFunction
+ .new('LOWER', [arel_table[column]])
+ .eq(sanitized_query)
+ else
+ arel_table[column].matches(sanitized_query)
+ end
end
end
diff --git a/lib/tasks/migrate/setup_postgresql.rake b/lib/tasks/migrate/setup_postgresql.rake
index 31cbd651edb..1c7a8a90f5c 100644
--- a/lib/tasks/migrate/setup_postgresql.rake
+++ b/lib/tasks/migrate/setup_postgresql.rake
@@ -8,6 +8,7 @@ task setup_postgresql: :environment do
require Rails.root.join('db/migrate/20170503185032_index_redirect_routes_path_for_like')
require Rails.root.join('db/migrate/20171220191323_add_index_on_namespaces_lower_name.rb')
require Rails.root.join('db/migrate/20180113220114_rework_redirect_routes_indexes.rb')
+ require Rails.root.join('db/migrate/20180215181245_users_name_lower_index.rb')
NamespacesProjectsPathLowerIndexes.new.up
AddUsersLowerUsernameEmailIndexes.new.up
@@ -17,4 +18,5 @@ task setup_postgresql: :environment do
IndexRedirectRoutesPathForLike.new.up
AddIndexOnNamespacesLowerName.new.up
ReworkRedirectRoutesIndexes.new.up
+ UsersNameLowerIndex.new.up
end
diff --git a/spec/lib/gitlab/sql/pattern_spec.rb b/spec/lib/gitlab/sql/pattern_spec.rb
index ef51e3cc8df..5b5052de372 100644
--- a/spec/lib/gitlab/sql/pattern_spec.rb
+++ b/spec/lib/gitlab/sql/pattern_spec.rb
@@ -154,6 +154,12 @@ describe Gitlab::SQL::Pattern do
it 'returns a single equality condition' do
expect(fuzzy_arel_match.to_sql).to match(/title.*I?LIKE 'fo'/)
end
+
+ it 'uses LOWER instead of ILIKE when LOWER is enabled' do
+ rel = Issue.fuzzy_arel_match(:title, query, lower_exact_match: true)
+
+ expect(rel.to_sql).to match(/LOWER\(.*title.*\).*=.*'fo'/)
+ end
end
context 'with two words both equal to 3 chars' do