MySQL NULL gotcha

Thijs van der Vossen, 28 Aug 2006, 11:09 in ruby on rails, last updated 28 Jan 2007, 19:57 (edit).

Never try to find the authenticated user in a Rails app running on MySQL with something like:

@authenticated = Person.find_by_id session[:authenticated_id]

Only use find_by_id if session[:authenticated_id] is not nil:

unless session[:authenticated_id].nil?
  @authenticated = Person.find_by_id session[:authenticated_id]
end

When you do a find_by nil the following query is executed:

SELECT * FROM people WHERE (people.`id` IS NULL) LIMIT 1;

Most of the time this returns an empty set, but if the previous query was an insert into the people table, MySQL will return the row for the last insert. This is because NULL somehow returns the generated id:

mysql> SELECT id FROM people WHERE id IS NULL;
Empty set (0.00 sec)

mysql> INSERT people SET username='bob';
Query OK, 1 row affected (0.08 sec)

mysql> SELECT id FROM people WHERE id IS NULL;
+----+
| id |
+----+
| 11 |
+----+
1 row in set (0.00 sec)

mysql> SELECT id FROM people WHERE id IS NULL;
Empty set (0.00 sec)

It would take some time and determination to exploit this, but it’s certainly not impossible.

Update: This was fixed in Rails just after the release of 1.2.1.

Comments

  1. Mischa Berger about 13 hours later: (delete | show email)

    Hm, interesting didn't know that...

    Will there always be an exception thrown when you do:
    @authenticated = Person.find(nil)

    or is something similar possible??

  2. Thijs van der Vossen about 14 hours later: (delete)

    As far as I can see, AR does not generate a query for Person.find(nil) so you should always get the ActiveRecord::RecordNotFound exception.

  3. Julik about 23 hours later: (delete)

    Nice gotcha, but you are better off checking beforehand. The automatic finders return nil or [] on failed find, find(bla) raises. If you use a method returning an emoty result it's sort of your responsibility to check if it succeeded.

  4. Julik about 23 hours later: (delete)

    Oh right, I see now. Thx for the heads up!

Add your comment

In order to fight spam on this blog, posting comments from a browser without javascript is currently not supported.