]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
- a CREATE TABLE will put the COLLATE option
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 3 Oct 2011 19:19:07 +0000 (15:19 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 3 Oct 2011 19:19:07 +0000 (15:19 -0400)
    after CHARSET, which appears to be part of
    MySQL's arbitrary rules regarding if it will actually
    work or not.  [ticket:2225]

  - reflecting a MySQL table will ensure that the
    options added to the Table at the table.kwargs
    level have spaces converted to underscores.
    This is a slight behavioral change specifically
    to the "mysql_default_charset" option which
    previously would not be symmetrical.

CHANGES
lib/sqlalchemy/dialects/mysql/base.py
test/dialect/test_mysql.py

diff --git a/CHANGES b/CHANGES
index f4f846ff9ff72c37f9e20dac77b3f84364462012..3377cf383b86ebc902a774b888d464203da9a71b 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -236,6 +236,19 @@ CHANGES
     it was assumed that "current" schema was synonymous
     with the full search_path.  [ticket:2249]
 
+- mysql
+  - a CREATE TABLE will put the COLLATE option 
+    after CHARSET, which appears to be part of 
+    MySQL's arbitrary rules regarding if it will actually
+    work or not.  [ticket:2225]
+
+  - reflecting a MySQL table will ensure that the 
+    options added to the Table at the table.kwargs
+    level have spaces converted to underscores.
+    This is a slight behavioral change specifically
+    to the "mysql_default_charset" option which 
+    previously would not be symmetrical.
+
 - mssql
   - Changes to attempt support of FreeTDS 0.91 with 
     Pyodbc.  This includes that string binds are sent as 
index 77ad90182483f07ed0494875be91baa7dde2f4ee..1d7d8984962ae1873392dc3d64160ba0ce23c015 100644 (file)
@@ -211,7 +211,7 @@ from array import array as _array
 from sqlalchemy.engine import reflection
 from sqlalchemy.engine import base as engine_base, default
 from sqlalchemy import types as sqltypes
-
+from sqlalchemy.util import topological
 from sqlalchemy.types import DATE, DATETIME, BOOLEAN, TIME, \
                                 BLOB, BINARY, VARBINARY
 
@@ -1363,26 +1363,36 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
         """Build table-level CREATE options like ENGINE and COLLATE."""
 
         table_opts = []
-        for k in table.kwargs:
-            if k.startswith('%s_' % self.dialect.name):
-                opt = k[len(self.dialect.name)+1:].upper()
-
-                arg = table.kwargs[k]
-                if opt in _options_of_type_string:
-                    arg = "'%s'" % arg.replace("\\", "\\\\").replace("'", "''")
-
-                if opt in ('DATA_DIRECTORY', 'INDEX_DIRECTORY',
-                           'DEFAULT_CHARACTER_SET', 'CHARACTER_SET', 
-                           'DEFAULT_CHARSET',
-                           'DEFAULT_COLLATE'):
-                    opt = opt.replace('_', ' ')
-
-                joiner = '='
-                if opt in ('TABLESPACE', 'DEFAULT CHARACTER SET',
-                           'CHARACTER SET', 'COLLATE'):
-                    joiner = ' '
-
-                table_opts.append(joiner.join((opt, arg)))
+
+        opts = dict(
+            (
+                k[len(self.dialect.name)+1:].upper(), 
+                v
+            )
+            for k, v in table.kwargs.items()
+            if k.startswith('%s_' % self.dialect.name)
+        )
+
+        for opt in topological.sort([
+            ('DEFAULT_CHARSET', 'COLLATE'),
+            ('DEFAULT_CHARACTER_SET', 'COLLATE')
+        ], opts):
+            arg = opts[opt]
+            if opt in _options_of_type_string:
+                arg = "'%s'" % arg.replace("\\", "\\\\").replace("'", "''")
+
+            if opt in ('DATA_DIRECTORY', 'INDEX_DIRECTORY',
+                       'DEFAULT_CHARACTER_SET', 'CHARACTER_SET', 
+                       'DEFAULT_CHARSET',
+                       'DEFAULT_COLLATE'):
+                opt = opt.replace('_', ' ')
+
+            joiner = '='
+            if opt in ('TABLESPACE', 'DEFAULT CHARACTER SET',
+                       'CHARACTER SET', 'COLLATE'):
+                joiner = ' '
+
+            table_opts.append(joiner.join((opt, arg)))
         return ' '.join(table_opts)
 
     def visit_drop_index(self, drop):
@@ -2252,7 +2262,7 @@ class MySQLTableDefinitionParser(object):
             options.pop(nope, None)
 
         for opt, val in options.items():
-            state.table_options['%s_%s' % (self.dialect.name, opt)] = val
+            state.table_options['%s_%s' % (self.dialect.name, opt.replace(' ', '_'))] = val
 
     def _parse_column(self, line, state):
         """Extract column details.
index fb20f44fddd9577fe1d95962c5f3081672e8f4d7..b8bcd573d4aae5ad70935ae930ab788c3c8a875e 100644 (file)
@@ -331,6 +331,22 @@ class TypesTest(fixtures.TestBase, AssertsExecutionResults, AssertsCompiledSQL):
             raise
         charset_table.drop()
 
+    @testing.exclude('mysql', '<', (5, 0, 5), 'a 5.0+ feature')
+    @testing.provide_metadata
+    def test_charset_collate_table(self):
+        t = Table('foo', self.metadata,
+            Column('id', Integer),
+            mysql_default_charset='utf8',
+            mysql_collate='utf8_unicode_ci'
+        )
+        t.create()
+        m2 = MetaData(testing.db)
+        t2 = Table('foo', m2, autoload=True)
+        eq_(t2.kwargs['mysql_collate'], 'utf8_unicode_ci')
+        # this is also testing that the names coming
+        # back get an underscore _ in them
+        eq_(t2.kwargs['mysql_default_charset'], 'utf8')
+
     @testing.exclude('mysql', '<', (5, 0, 5), 'a 5.0+ feature')
     @testing.fails_on('mysql+oursql', 'some round trips fail, oursql bug ?')
     def test_bit_50(self):
@@ -878,7 +894,7 @@ class ReflectionTest(fixtures.TestBase, AssertsExecutionResults):
 
         assert reflected.kwargs['mysql_engine'] == 'MEMORY'
         assert reflected.kwargs['mysql_comment'] == comment
-        assert reflected.kwargs['mysql_default charset'] == 'utf8'
+        assert reflected.kwargs['mysql_default_charset'] == 'utf8'
         assert reflected.kwargs['mysql_avg_row_length'] == '3'
         assert reflected.kwargs['mysql_connection'] == 'fish'