Fixed #18116 -- Raised minimum MySQL version officially suported to 5.0.3.

Thanks Carl, Claude and Anssi for discussion and patch review.

git-svn-id: http://code.djangoproject.com/svn/django/trunk@17921 bcc190cf-cafb-0310-a4f2-bffc1f526a37
This commit is contained in:
Ramiro Morales 2012-04-21 03:04:10 +00:00
parent 53fb45c6d8
commit 4536359887
4 changed files with 33 additions and 72 deletions

View File

@ -15,11 +15,13 @@ except ImportError, e:
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
from django.utils.functional import cached_property
# We want version (1, 2, 1, 'final', 2) or later. We can't just use
# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
# inadvertently passes the version test.
version = Database.version_info
if (version < (1,2,1) or (version[:3] == (1, 2, 1) and
if (version < (1, 2, 1) or (version[:3] == (1, 2, 1) and
(len(version) < 5 or version[3] != 'final' or version[4] < 2))):
from django.core.exceptions import ImproperlyConfigured
raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
@ -163,6 +165,7 @@ class DatabaseFeatures(BaseDatabaseFeatures):
supports_timezones = False
requires_explicit_null_ordering_when_grouping = True
allows_primary_key_0 = False
uses_savepoints = True
def __init__(self, connection):
super(DatabaseFeatures, self).__init__(connection)
@ -387,8 +390,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
self.connection = Database.connect(**kwargs)
self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
self.connection.encoders[SafeString] = self.connection.encoders[str]
self.features.uses_savepoints = \
self.get_server_version() >= (5, 0, 3)
connection_created.send(sender=self.__class__, connection=self)
cursor = self.connection.cursor()
if new_connection:
@ -405,10 +406,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
except Database.NotSupportedError:
pass
def get_server_version(self):
@cached_property
def mysql_version(self):
if not self.server_version:
if not self._valid_connection():
self.cursor()
self.cursor().close()
m = server_version_re.match(self.connection.get_server_info())
if not m:
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())

View File

@ -65,27 +65,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
key columns in given table.
"""
key_columns = []
try:
cursor.execute("""
SELECT column_name, referenced_table_name, referenced_column_name
FROM information_schema.key_column_usage
WHERE table_name = %s
AND table_schema = DATABASE()
AND referenced_table_name IS NOT NULL
AND referenced_column_name IS NOT NULL""", [table_name])
key_columns.extend(cursor.fetchall())
except (ProgrammingError, OperationalError):
# Fall back to "SHOW CREATE TABLE", for previous MySQL versions.
# Go through all constraints and save the equal matches.
cursor.execute("SHOW CREATE TABLE %s" % self.connection.ops.quote_name(table_name))
for row in cursor.fetchall():
pos = 0
while True:
match = foreign_key_re.search(row[1], pos)
if match == None:
break
pos = match.end()
key_columns.append(match.groups())
cursor.execute("""
SELECT column_name, referenced_table_name, referenced_column_name
FROM information_schema.key_column_usage
WHERE table_name = %s
AND table_schema = DATABASE()
AND referenced_table_name IS NOT NULL
AND referenced_column_name IS NOT NULL""", [table_name])
key_columns.extend(cursor.fetchall())
return key_columns
def get_primary_key_column(self, cursor, table_name):

View File

@ -3,30 +3,13 @@ from django.db.backends import BaseDatabaseValidation
class DatabaseValidation(BaseDatabaseValidation):
def validate_field(self, errors, opts, f):
"""
There are some field length restrictions for MySQL:
- Prior to version 5.0.3, character fields could not exceed 255
characters in length.
- No character (varchar) fields can have a length exceeding 255
characters if they have a unique index on them.
MySQL has the following field length restriction:
No character (varchar) fields can have a length exceeding 255
characters if they have a unique index on them.
"""
from django.db import models
from MySQLdb import OperationalError
try:
db_version = self.connection.get_server_version()
text_version = '.'.join([str(n) for n in db_version[:3]])
except OperationalError:
db_version = None
text_version = ''
varchar_fields = (models.CharField, models.CommaSeparatedIntegerField,
models.SlugField)
if isinstance(f, varchar_fields) and f.max_length > 255:
if db_version and db_version < (5, 0, 3):
msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when you are using a version of MySQL prior to 5.0.3 (you are using %(version)s).'
elif f.unique == True:
msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".'
else:
msg = None
if msg:
errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__, 'version': text_version})
if isinstance(f, varchar_fields) and f.max_length > 255 and f.unique:
msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".'
errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__})

View File

@ -122,30 +122,23 @@ lookups that use the ``LIKE`` operator in their SQL, as is done with the
MySQL notes
===========
Django expects the database to support transactions, referential integrity, and
Unicode (UTF-8 encoding). Fortunately, MySQL_ has all these features as
available as far back as 3.23. While it may be possible to use 3.23 or 4.0,
you'll probably have less trouble if you use 4.1 or 5.0.
Version support
---------------
MySQL 4.1
---------
`MySQL 4.1`_ has greatly improved support for character sets. It is possible to
set different default character sets on the database, table, and column.
Previous versions have only a server-wide character set setting. It's also the
first version where the character set can be changed on the fly. 4.1 also has
support for views, but Django currently doesn't use views.
MySQL 5.0
---------
Django supports MySQL 5.0.3 and higher.
`MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed
data on all database schema. Django's ``inspectdb`` feature uses this
``information_schema`` if it's available. 5.0 also has support for stored
procedures, but Django currently doesn't use stored procedures.
data on all database schema. Django's ``inspectdb`` feature uses this feature.
.. versionchanged:: 1.5
The minimum version requirement of MySQL 5.0.3 was set in Django 1.5.
Django expects the database to support Unicode (UTF-8 encoding) and delegates to
it the task of enforcing transactions and referential integrity. It is important
to be aware of the fact that the two latter ones aren't actually enforced by
MySQL when using the MyISAM storage engine, see the next section.
.. _MySQL: http://www.mysql.com/
.. _MySQL 4.1: http://dev.mysql.com/doc/refman/4.1/en/index.html
.. _MySQL 5.0: http://dev.mysql.com/doc/refman/5.0/en/index.html
Storage engines
@ -381,10 +374,6 @@ for the field. This affects :class:`~django.db.models.CharField`,
:class:`~django.db.models.SlugField` and
:class:`~django.db.models.CommaSeparatedIntegerField`.
Furthermore, if you are using a version of MySQL prior to 5.0.3, all of those
column types have a maximum length restriction of 255 characters, regardless
of whether ``unique=True`` is specified or not.
DateTime fields
~~~~~~~~~~~~~~~