Skip to content

Rollback to LOWER comparison instead of (I)LIKE because of bug and poor Postgres performance#339

Merged
binarylogic merged 1 commit into
binarylogic:masterfrom
cris:back-to-lower
Dec 7, 2012
Merged

Rollback to LOWER comparison instead of (I)LIKE because of bug and poor Postgres performance#339
binarylogic merged 1 commit into
binarylogic:masterfrom
cris:back-to-lower

Conversation

@cris

@cris cris commented Nov 27, 2012

Copy link
Copy Markdown
Contributor

Hi, Ben.

I suggest to revert changes with LIKE back to LOWER, because this solution doesn't add any benefits and introduce subtle bug.

  1. (I)LIKE is used without any quotiong. This leads to login/email collision. For example, user1 has email: user1@gmail.com and user2 has email: user_@gmail.com. If user1 is registered before user2, user2 isn't able to login. Because query:
SELECT  "users".* FROM "users"  WHERE ("users".email ILIKE 'user_@gmail.com') LIMIT 1;

allways returns user1 record. Take a look on issue 321, they already obtain this email collision: binarylogic/authlogic/issues/#321

  1. For MySQL case-insensitive is usualy default, because Rails creates database with collation "utf8_general_ci", and with such collation search by string fields is case insensitive. So, MySQL doesn't benefit from LIKE, because it doesn't make sense for it to use such option. Plane find_by_#{field} does all in case-insensitive manner.

  2. For Postgres ILIKE only brings new issue instead of solving something.
    First of all, ILIKE can't use indexes. You can clearly see this via EXPLAIN:

EXPLAIN SELECT  "users".* FROM "users"  WHERE ("users".email ILIKE 'user_@gmail.com') LIMIT 1;
                            QUERY PLAN                             
-------------------------------------------------------------------
 Limit  (cost=0.00..846.95 rows=1 width=1903)
   ->  Seq Scan on users  (cost=0.00..32184.19 rows=38 width=1903)
         Filter: ((email)::text ~~* 'user_@gmail.com'::text)
(3 rows)

What is worse, now I can't use Postgres ability to create index on function. For previous version of Authlogic I've created index on expression: LOWER(email) and it provides me with required functionality.

explain SELECT  "users".* FROM "users"  WHERE (LOWER("users".email) = 'user_@gmail.com') LIMIT 1;
                                          QUERY PLAN                                          
----------------------------------------------------------------------------------------------
 Limit  (cost=0.00..8.48 rows=1 width=1903)
   ->  Index Scan using index_users_lower_email on users  (cost=0.00..8.48 rows=1 width=1903)
         Index Cond: (lower((email)::text) = 'user_@gmail.com'::text)

After update to the latest version of AuthLogic I lost such ability.

Please, apply this pull-request to handle all caveats.

@bri3d

bri3d commented Dec 6, 2012

Copy link
Copy Markdown

+1. The ILIKE quoting issue is fairly serious, and switching back to LOWER seems like a good way to both fix it and improve performance on Postgres at the same time.

It looks like the original switch to LIKE was done for "performance" reasons on MySQL, but wasn't thought through completely as it actually degraded performance on all versions of Postgres.

(for reference here's the original LIKE commit)

cris@ca37d8a

@jstin

jstin commented Dec 6, 2012

Copy link
Copy Markdown

+1 this is a much better solution.

binarylogic added a commit that referenced this pull request Dec 7, 2012
Rollback to LOWER comparison instead of (I)LIKE because of bug and poor Postgres performance
@binarylogic binarylogic merged commit d8c61db into binarylogic:master Dec 7, 2012
@maxjustus

Copy link
Copy Markdown

FWIW this change destroys performance on MySQL, since the use of LOWER prevents MySQL from being able to employ indices at all.

pixeltrix added a commit to alphagov/e-petitions that referenced this pull request Apr 28, 2015
As of Rails 4.2 enforcing case-sensitivity for usernames is broken in
Authlogic due to the commit rails/rails@a38e957. The app change was for
security reasons since at the time Authlogic was using LIKE in the
query generation. However this was fixed in binarylogic/authlogic#339.

- binarylogic/authlogic#444
- binarylogic/authlogic#453

We should leave it as case-insensitive as this is better UX
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

8 participants