I ran into a strange problem using MySQL. It seems like UNIQUE in MySQL
is case insensitive, so you cannot create "foo" if you have "FOO" in
your database.
You can test this yourself using the following SQL-statements:
---------8<------------------------------------------------------
CREATE TEMPORARY TABLE tempfoobar (
name varchar(100) UNIQUE
) TYPE=HEAP;
INSERT INTO tempfoobar VALUES("name");
SELECT * FROM tempfoobar WHERE name="NAME";
INSERT INTO tempfoobar VALUES("NAME");
DROP TABLE tempfoobar;
------------------------------------------------------>8---------
So, why does this in any way affect Django? (Skip this if you know #7789)
Django provides a simple way to create objects, if they don't exist yet,
called get_or_create(). This method used get() to test if the object is
there (which is case sensitive) and then tries to save a new object
(which is case insensitive). To work around race conditions the method
catches IntegrityError's and tries to fetch the object again.
Now with MySQL fetching the object does not work, but INSERT does not
work either as UNIQUE is case insensitive. Now get_or_create() raises a
DoesNotExist exception, which took me a while to figure out why.
About the impact of this issue: I use django-tagging
(http://code.google.com/p/django-tagging/) in my projects. After
switching to mysql on my development machine tagging objects became
nearly impossible. You always had to type in tags exacple the same way
they where in the database, otherwise saving the object was not
possible. This this issue might break working applications.
So, what to do about this? This issue should at least be documented, it
seems that it came up on this list before and there even is a bug-report
(#7789).
But I would prefer to fix it, which is actually pretty easy:
---------8<------------------------------------------------------
CREATE TEMPORARY TABLE tempfoobar (
name varchar(100) BINARY UNIQUE
) TYPE=HEAP;
INSERT INTO tempfoobar VALUES("name");
SELECT * FROM tempfoobar WHERE name="NAME";
INSERT INTO tempfoobar VALUES("NAME");
DROP TABLE tempfoobar;
------------------------------------------------------>8---------
(note the "BINARY")
I have attached a patch
(http://code.djangoproject.com/attachment/ticket/7789/django-mysql-case-sensitive-unique.patch)
for current trunk to #7789, perhaps this should go into Django before 1.0?
Greetings, David Danier
Hi devs,
I ran into a strange problem using MySQL. It seems like UNIQUE in MySQL
is case insensitive, so you cannot create "foo" if you have "FOO" in
your database.
[...snip details...]
So, what to do about this? This issue should at least be documented, it
seems that it came up on this list before and there even is a bug-report
(#7789).
But I would prefer to fix it, which is actually pretty easy:
---------8<------------------------------------------------------
CREATE TEMPORARY TABLE tempfoobar (
name varchar(100) BINARY UNIQUE
) TYPE=HEAP;
INSERT INTO tempfoobar VALUES("name");
SELECT * FROM tempfoobar WHERE name="NAME";
INSERT INTO tempfoobar VALUES("NAME");
DROP TABLE tempfoobar;
------------------------------------------------------>8---------
(note the "BINARY")
I have attached a patch
(http://code.djangoproject.com/attachment/ticket/7789/django-mysql-case-sensitive-unique.patch)
for current trunk to #7789, perhaps this should go into Django before 1.0?
With a little research today I discovered that it is possible to do a
case insensitive match on a binary column by using COLLATE.
I still have some concerns with Django specifying a binary column type on table creation: