Ticket #16961: ticket_16961.2.diff
File ticket_16961.2.diff, 15.3 KB (added by , 13 years ago) |
---|
-
django/db/backends/mysql/base.py
diff --git a/django/db/backends/mysql/base.py b/django/db/backends/mysql/base.py index faaefca..bacd998 100644
a b except ImportError, e: 15 15 from django.core.exceptions import ImproperlyConfigured 16 16 raise ImproperlyConfigured("Error loading MySQLdb module: %s" % e) 17 17 18 from django.utils.functional import cached_property 19 18 20 # We want version (1, 2, 1, 'final', 2) or later. We can't just use 19 21 # lexicographic ordering in this check because then (1, 2, 1, 'gamma') 20 22 # inadvertently passes the version test. 21 23 version = Database.version_info 22 if (version < (1, 2,1) or (version[:3] == (1, 2, 1) and24 if (version < (1, 2, 1) or (version[:3] == (1, 2, 1) and 23 25 (len(version) < 5 or version[3] != 'final' or version[4] < 2))): 24 26 from django.core.exceptions import ImproperlyConfigured 25 27 raise ImproperlyConfigured("MySQLdb-1.2.1p2 or newer is required; you have %s" % Database.__version__) … … class DatabaseFeatures(BaseDatabaseFeatures): 163 165 supports_timezones = False 164 166 requires_explicit_null_ordering_when_grouping = True 165 167 allows_primary_key_0 = False 168 uses_savepoints = True 166 169 167 170 def __init__(self, connection): 168 171 super(DatabaseFeatures, self).__init__(connection) … … class DatabaseOperations(BaseDatabaseOperations): 258 261 sql.append('%s %s;' % (style.SQL_KEYWORD('TRUNCATE'), style.SQL_FIELD(self.quote_name(table)))) 259 262 sql.append('SET FOREIGN_KEY_CHECKS = 1;') 260 263 261 # 'ALTER TABLE table AUTO_INCREMENT = 1;'... style SQL statements 262 # to reset sequence indices 263 sql.extend(["%s %s %s %s %s;" % \ 264 (style.SQL_KEYWORD('ALTER'), 265 style.SQL_KEYWORD('TABLE'), 266 style.SQL_TABLE(self.quote_name(sequence['table'])), 267 style.SQL_KEYWORD('AUTO_INCREMENT'), 268 style.SQL_FIELD('= 1'), 269 ) for sequence in sequences]) 264 # Truncate already resets the AUTO_INCREMENT field from 265 # MySQL version 5.0.13 onwards. Refs #16961. 266 if self.connection.mysql_version < (5,0,13): 267 sql.extend( 268 ["%s %s %s %s %s;" % \ 269 (style.SQL_KEYWORD('ALTER'), 270 style.SQL_KEYWORD('TABLE'), 271 style.SQL_TABLE(self.quote_name(sequence['table'])), 272 style.SQL_KEYWORD('AUTO_INCREMENT'), 273 style.SQL_FIELD('= 1'), 274 ) for sequence in sequences]) 270 275 return sql 271 276 else: 272 277 return [] … … class DatabaseWrapper(BaseDatabaseWrapper): 387 392 self.connection = Database.connect(**kwargs) 388 393 self.connection.encoders[SafeUnicode] = self.connection.encoders[unicode] 389 394 self.connection.encoders[SafeString] = self.connection.encoders[str] 390 self.features.uses_savepoints = \391 self.get_server_version() >= (5, 0, 3)392 395 connection_created.send(sender=self.__class__, connection=self) 393 396 cursor = self.connection.cursor() 394 397 if new_connection: … … class DatabaseWrapper(BaseDatabaseWrapper): 405 408 except Database.NotSupportedError: 406 409 pass 407 410 408 def get_server_version(self): 411 @cached_property 412 def mysql_version(self): 409 413 if not self.server_version: 410 414 if not self._valid_connection(): 411 self.cursor() 415 self.cursor().close() 412 416 m = server_version_re.match(self.connection.get_server_info()) 413 417 if not m: 414 418 raise Exception('Unable to determine MySQL version from version string %r' % self.connection.get_server_info()) -
django/db/backends/mysql/introspection.py
diff --git a/django/db/backends/mysql/introspection.py b/django/db/backends/mysql/introspection.py index ab4eebe..bb56ae3 100644
a b class DatabaseIntrospection(BaseDatabaseIntrospection): 65 65 key columns in given table. 66 66 """ 67 67 key_columns = [] 68 try: 69 cursor.execute(""" 70 SELECT column_name, referenced_table_name, referenced_column_name 71 FROM information_schema.key_column_usage 72 WHERE table_name = %s 73 AND table_schema = DATABASE() 74 AND referenced_table_name IS NOT NULL 75 AND referenced_column_name IS NOT NULL""", [table_name]) 76 key_columns.extend(cursor.fetchall()) 77 except (ProgrammingError, OperationalError): 78 # Fall back to "SHOW CREATE TABLE", for previous MySQL versions. 79 # Go through all constraints and save the equal matches. 80 cursor.execute("SHOW CREATE TABLE %s" % self.connection.ops.quote_name(table_name)) 81 for row in cursor.fetchall(): 82 pos = 0 83 while True: 84 match = foreign_key_re.search(row[1], pos) 85 if match == None: 86 break 87 pos = match.end() 88 key_columns.append(match.groups()) 68 cursor.execute(""" 69 SELECT column_name, referenced_table_name, referenced_column_name 70 FROM information_schema.key_column_usage 71 WHERE table_name = %s 72 AND table_schema = DATABASE() 73 AND referenced_table_name IS NOT NULL 74 AND referenced_column_name IS NOT NULL""", [table_name]) 75 key_columns.extend(cursor.fetchall()) 89 76 return key_columns 90 77 91 78 def get_primary_key_column(self, cursor, table_name): -
django/db/backends/mysql/validation.py
diff --git a/django/db/backends/mysql/validation.py b/django/db/backends/mysql/validation.py index 663cc7d..de7474d 100644
a b from django.db.backends import BaseDatabaseValidation 3 3 class DatabaseValidation(BaseDatabaseValidation): 4 4 def validate_field(self, errors, opts, f): 5 5 """ 6 There are some field length restrictions for MySQL: 7 8 - Prior to version 5.0.3, character fields could not exceed 255 9 characters in length. 10 - No character (varchar) fields can have a length exceeding 255 11 characters if they have a unique index on them. 6 MySQL has the following field length restriction: 7 No character (varchar) fields can have a length exceeding 255 8 characters if they have a unique index on them. 12 9 """ 13 10 from django.db import models 14 from MySQLdb import OperationalError15 try:16 db_version = self.connection.get_server_version()17 text_version = '.'.join([str(n) for n in db_version[:3]])18 except OperationalError:19 db_version = None20 text_version = ''21 11 varchar_fields = (models.CharField, models.CommaSeparatedIntegerField, 22 12 models.SlugField) 23 if isinstance(f, varchar_fields) and f.max_length > 255: 24 if db_version and db_version < (5, 0, 3): 25 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).' 26 elif f.unique == True: 27 msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".' 28 else: 29 msg = None 30 31 if msg: 32 errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__, 'version': text_version}) 13 if isinstance(f, varchar_fields) and f.max_length > 255 and f.unique: 14 msg = '"%(name)s": %(cls)s cannot have a "max_length" greater than 255 when using "unique=True".' 15 errors.add(opts, msg % {'name': f.name, 'cls': f.__class__.__name__}) -
docs/intro/install.txt
diff --git a/docs/intro/install.txt b/docs/intro/install.txt index ef04eba..95f7b27 100644
a b you should see something like:: 39 39 Set up a database 40 40 ----------------- 41 41 42 If you installed Python 2.6 or later, you can skip this step for now. 43 44 If not, or if you'd like to work with a "large" database engine like PostgreSQL, 45 MySQL, or Oracle, consult the :ref:`database installation information 46 <database-installation>`. 42 This step is only necessary if you'd like to work with a "large" database engine 43 like PostgreSQL, MySQL, or Oracle. To install such a database, consult the 44 :ref:`database installation information <database-installation>`. 47 45 48 46 Remove any old versions of Django 49 47 --------------------------------- -
docs/ref/databases.txt
diff --git a/docs/ref/databases.txt b/docs/ref/databases.txt index 59a0c36..c271946 100644
a b lookups that use the ``LIKE`` operator in their SQL, as is done with the 122 122 MySQL notes 123 123 =========== 124 124 125 Django expects the database to support transactions, referential integrity, and 126 Unicode (UTF-8 encoding). Fortunately, MySQL_ has all these features as 127 available as far back as 3.23. While it may be possible to use 3.23 or 4.0, 128 you'll probably have less trouble if you use 4.1 or 5.0. 125 Version support 126 --------------- 129 127 130 MySQL 4.1 131 --------- 128 Django supports MySQL 5.0.3 and higher. 132 129 133 `MySQL 4.1`_ has greatly improved support for character sets. It is possible to 134 set different default character sets on the database, table, and column. 135 Previous versions have only a server-wide character set setting. It's also the 136 first version where the character set can be changed on the fly. 4.1 also has 137 support for views, but Django currently doesn't use views. 130 `MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed 131 data on all database schema. Django's ``inspectdb`` feature uses this feature. 138 132 139 MySQL 5.0 140 --------- 133 .. versionchanged:: 1.5 134 The minimum version requirement of MySQL 5.0.3 was set in Django 1.5. 141 135 142 `MySQL 5.0`_ adds the ``information_schema`` database, which contains detailed 143 data on all database schema. Django's ``inspectdb`` feature uses this 144 ``information_schema`` if it's available. 5.0 also has support for stored 145 procedures, but Django currently doesn't use stored procedures.136 Django expects the database to support Unicode (UTF-8 encoding) and delegates to 137 it the task of enforcing transactions and referential integrity. It is important 138 to be aware of the fact that the two latter ones aren't actually enforced by 139 MySQL when using the MyISAM storage engine, see the next section. 146 140 147 141 .. _MySQL: http://www.mysql.com/ 148 .. _MySQL 4.1: http://dev.mysql.com/doc/refman/4.1/en/index.html149 142 .. _MySQL 5.0: http://dev.mysql.com/doc/refman/5.0/en/index.html 150 143 151 144 Storage engines … … for the field. This affects :class:`~django.db.models.CharField`, 381 374 :class:`~django.db.models.SlugField` and 382 375 :class:`~django.db.models.CommaSeparatedIntegerField`. 383 376 384 Furthermore, if you are using a version of MySQL prior to 5.0.3, all of those385 column types have a maximum length restriction of 255 characters, regardless386 of whether ``unique=True`` is specified or not.387 388 377 DateTime fields 389 378 ~~~~~~~~~~~~~~~ 390 379 -
tests/regressiontests/backends/tests.py
diff --git a/tests/regressiontests/backends/tests.py b/tests/regressiontests/backends/tests.py index d5b1ea8..f87b9c4 100644
a b class OracleChecks(unittest.TestCase): 61 61 def test_client_encoding(self): 62 62 # If the backend is Oracle, test that the client encoding is set 63 63 # correctly. This was broken under Cygwin prior to r14781. 64 c = connection.cursor() # Ensure the connection is initialized.64 connection.cursor() # Ensure the connection is initialized. 65 65 self.assertEqual(connection.connection.encoding, "UTF-8") 66 66 self.assertEqual(connection.connection.nencoding, "UTF-8") 67 67 68 class MySQLTests(TestCase): 69 @unittest.skipUnless(connection.vendor == 'mysql', 70 "Test valid only for MySQL") 71 def test_autoincrement(self): 72 """ 73 Check that auto_increment fields are reset correctly by sql_flush(). 74 Before MySQL version 5.0.13 TRUNCATE did not do auto_increment reset. 75 Refs #16961. 76 """ 77 statements = connection.ops.sql_flush(no_style(), 78 tables=['test'], 79 sequences=[{ 80 'table': 'test', 81 'col': 'somecol', 82 }]) 83 found_reset = False 84 for sql in statements: 85 found_reset = found_reset or 'ALTER TABLE' in sql 86 if connection.mysql_version < (5,0,13): 87 self.assertTrue(found_reset) 88 else: 89 self.assertFalse(found_reset) 90 91 68 92 class DateQuotingTest(TestCase): 69 93 70 94 def test_django_date_trunc(self): -
tests/regressiontests/test_runner/models.py
diff --git a/tests/regressiontests/test_runner/models.py b/tests/regressiontests/test_runner/models.py index e69de29..9a072e6 100644
a b 1 from django.db import models 2 3 class Person(models.Model): 4 first_name = models.CharField(max_length=20) 5 last_name = models.CharField(max_length=20) -
tests/regressiontests/test_runner/tests.py
diff --git a/tests/regressiontests/test_runner/tests.py b/tests/regressiontests/test_runner/tests.py index ccb65b4..3fc8d7f 100644
a b from optparse import make_option 8 8 from django.core.exceptions import ImproperlyConfigured 9 9 from django.core.management import call_command 10 10 from django import db 11 from django.test import simple 11 from django.db import connection 12 from django.test import simple, TransactionTestCase 12 13 from django.test.simple import DjangoTestSuiteRunner, get_tests 13 14 from django.test.testcases import connections_support_transactions 14 15 from django.utils import unittest 15 16 from django.utils.importlib import import_module 16 17 17 18 from ..admin_scripts.tests import AdminScriptTestCase 19 from .models import Person 18 20 19 21 20 22 TEST_APP_OK = 'regressiontests.test_runner.valid_app.models' … … class Sqlite3InMemoryTestDbs(unittest.TestCase): 262 264 self.assertTrue(connections_support_transactions(), msg) 263 265 finally: 264 266 db.connections = old_db_connections 267 268 269 class AutoIncrementResetTest(TransactionTestCase): 270 """ 271 Here we test creating the same model two times in different test methods, 272 and check that both times they get "1" as their PK value. That is, we test 273 that AutoField values start from 1 for each transactional test case. 274 """ 275 @unittest.skipIf(connection.vendor == 'oracle', 276 "Oracle's auto-increment fields are not reset between " 277 "tests") 278 def test_autoincrement_reset1(self): 279 p = Person.objects.create(first_name='Jack', last_name='Smith') 280 self.assertEquals(p.pk, 1) 281 282 @unittest.skipIf(connection.vendor == 'oracle', 283 "Oracle's auto-increment fields are not reset between " 284 "tests") 285 def test_autoincrement_reset2(self): 286 p = Person.objects.create(first_name='Jack', last_name='Smith') 287 self.assertEquals(p.pk, 1)