mirror of
https://github.com/django/django.git
synced 2025-06-05 11:39:13 +00:00
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:
parent
53fb45c6d8
commit
4536359887
@ -15,11 +15,13 @@ except ImportError, e:
|
|||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e)
|
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
|
# 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')
|
# lexicographic ordering in this check because then (1, 2, 1, 'gamma')
|
||||||
# inadvertently passes the version test.
|
# inadvertently passes the version test.
|
||||||
version = Database.version_info
|
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))):
|
(len(version) < 5 or version[3] != 'final' or version[4] < 2))):
|
||||||
from django.core.exceptions import ImproperlyConfigured
|
from django.core.exceptions import ImproperlyConfigured
|
||||||
raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__)
|
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
|
supports_timezones = False
|
||||||
requires_explicit_null_ordering_when_grouping = True
|
requires_explicit_null_ordering_when_grouping = True
|
||||||
allows_primary_key_0 = False
|
allows_primary_key_0 = False
|
||||||
|
uses_savepoints = True
|
||||||
|
|
||||||
def __init__(self, connection):
|
def __init__(self, connection):
|
||||||
super(DatabaseFeatures, self).__init__(connection)
|
super(DatabaseFeatures, self).__init__(connection)
|
||||||
@ -387,8 +390,6 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
self.connection = Database.connect(**kwargs)
|
self.connection = Database.connect(**kwargs)
|
||||||
self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
|
self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode]
|
||||||
self.connection.encoders[SafeString] = self.connection.encoders[str]
|
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)
|
connection_created.send(sender=self.__class__, connection=self)
|
||||||
cursor = self.connection.cursor()
|
cursor = self.connection.cursor()
|
||||||
if new_connection:
|
if new_connection:
|
||||||
@ -405,10 +406,11 @@ class DatabaseWrapper(BaseDatabaseWrapper):
|
|||||||
except Database.NotSupportedError:
|
except Database.NotSupportedError:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
def get_server_version(self):
|
@cached_property
|
||||||
|
def mysql_version(self):
|
||||||
if not self.server_version:
|
if not self.server_version:
|
||||||
if not self._valid_connection():
|
if not self._valid_connection():
|
||||||
self.cursor()
|
self.cursor().close()
|
||||||
m = server_version_re.match(self.connection.get_server_info())
|
m = server_version_re.match(self.connection.get_server_info())
|
||||||
if not m:
|
if not m:
|
||||||
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
|
raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info())
|
||||||
|
@ -65,27 +65,14 @@ class DatabaseIntrospection(BaseDatabaseIntrospection):
|
|||||||
key columns in given table.
|
key columns in given table.
|
||||||
"""
|
"""
|
||||||
key_columns = []
|
key_columns = []
|
||||||
try:
|
cursor.execute("""
|
||||||
cursor.execute("""
|
SELECT column_name, referenced_table_name, referenced_column_name
|
||||||
SELECT column_name, referenced_table_name, referenced_column_name
|
FROM information_schema.key_column_usage
|
||||||
FROM information_schema.key_column_usage
|
WHERE table_name = %s
|
||||||
WHERE table_name = %s
|
AND table_schema = DATABASE()
|
||||||
AND table_schema = DATABASE()
|
AND referenced_table_name IS NOT NULL
|
||||||
AND referenced_table_name IS NOT NULL
|
AND referenced_column_name IS NOT NULL""", [table_name])
|
||||||
AND referenced_column_name IS NOT NULL""", [table_name])
|
key_columns.extend(cursor.fetchall())
|
||||||
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())
|
|
||||||
return key_columns
|
return key_columns
|
||||||
|
|
||||||
def get_primary_key_column(self, cursor, table_name):
|
def get_primary_key_column(self, cursor, table_name):
|
||||||
|
@ -3,30 +3,13 @@ from django.db.backends import BaseDatabaseValidation
|
|||||||
class DatabaseValidation(BaseDatabaseValidation):
|
class DatabaseValidation(BaseDatabaseValidation):
|
||||||
def validate_field(self, errors, opts, f):
|
def validate_field(self, errors, opts, f):
|
||||||
"""
|
"""
|
||||||
There are some field length restrictions for MySQL:
|
MySQL has the following field length restriction:
|
||||||
|
No character (varchar) fields can have a length exceeding 255
|
||||||
- Prior to version 5.0.3, character fields could not exceed 255
|
characters if they have a unique index on them.
|
||||||
characters in length.
|
|
||||||
- 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 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,
|
varchar_fields = (models.CharField, models.CommaSeparatedIntegerField,
|
||||||
models.SlugField)
|
models.SlugField)
|
||||||
if isinstance(f, varchar_fields) and f.max_length > 255:
|
if isinstance(f, varchar_fields) and f.max_length > 255 and f.unique:
|
||||||
if db_version and db_version < (5, 0, 3):
|
msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".'
|
||||||
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).'
|
errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__})
|
||||||
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})
|
|
||||||
|
@ -122,30 +122,23 @@ lookups that use the ``LIKE`` operator in their SQL, as is done with the
|
|||||||
MySQL notes
|
MySQL notes
|
||||||
===========
|
===========
|
||||||
|
|
||||||
Django expects the database to support transactions, referential integrity, and
|
Version support
|
||||||
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.
|
|
||||||
|
|
||||||
MySQL 4.1
|
Django supports MySQL 5.0.3 and higher.
|
||||||
---------
|
|
||||||
|
|
||||||
`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
|
|
||||||
---------
|
|
||||||
|
|
||||||
`MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed
|
`MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed
|
||||||
data on all database schema. Django's ``inspectdb`` feature uses this
|
data on all database schema. Django's ``inspectdb`` feature uses this feature.
|
||||||
``information_schema`` if it's available. 5.0 also has support for stored
|
|
||||||
procedures, but Django currently doesn't use stored procedures.
|
.. 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: 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
|
.. _MySQL 5.0: http://dev.mysql.com/doc/refman/5.0/en/index.html
|
||||||
|
|
||||||
Storage engines
|
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.SlugField` and
|
||||||
:class:`~django.db.models.CommaSeparatedIntegerField`.
|
: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
|
DateTime fields
|
||||||
~~~~~~~~~~~~~~~
|
~~~~~~~~~~~~~~~
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user