]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Reflect ASC/DESC in MySQL index columns
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 28 Jun 2018 18:33:14 +0000 (14:33 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 28 Jun 2018 20:40:46 +0000 (16:40 -0400)
Fixed bug in index reflection where on MySQL 8.0 an index that includes
ASC or DESC in an indexed column specfication would not be correctly
reflected, as MySQL 8.0 introduces support for returning this information
in a table definition string.

Change-Id: I21f64984ade690aac8c87dbe3aad0c1ee8e9727f
Fixes: #4293
(cherry picked from commit 9d2dc7911b7767b97814479d228072b6f566a864)

doc/build/changelog/unreleased_12/4293.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/reflection.py
test/dialect/mysql/test_reflection.py

diff --git a/doc/build/changelog/unreleased_12/4293.rst b/doc/build/changelog/unreleased_12/4293.rst
new file mode 100644 (file)
index 0000000..51fac20
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, mysql
+    :tickets: 4293
+
+    Fixed bug in index reflection where on MySQL 8.0 an index that includes
+    ASC or DESC in an indexed column specfication would not be correctly
+    reflected, as MySQL 8.0 introduces support for returning this information
+    in a table definition string.
index f9b8c8d3b3f04729d539437084f5aeccb4d44297..3e7affef28164e87d6bc80f9277af411d8f9a974 100644 (file)
@@ -76,6 +76,8 @@ class MySQLTableDefinitionParser(object):
         if m:
             spec = m.groupdict()
             # convert columns into name, length pairs
+            # NOTE: we may want to consider SHOW INDEX as the
+            # format of indexes in MySQL becomes more complex
             spec['columns'] = self._parse_keyexprs(spec['columns'])
             return 'key', spec
 
@@ -310,11 +312,10 @@ class MySQLTableDefinitionParser(object):
 
         # `col`,`col2`(32),`col3`(15) DESC
         #
-        # Note: ASC and DESC aren't reflected, so we'll punt...
         self._re_keyexprs = _re_compile(
             r'(?:'
             r'(?:%(iq)s((?:%(esc_fq)s|[^%(fq)s])+)%(fq)s)'
-            r'(?:\((\d+)\))?(?=\,|$))+' % quotes)
+            r'(?:\((\d+)\))?(?: +(ASC|DESC))?(?=\,|$))+' % quotes)
 
         # 'foo' or 'foo','bar' or 'fo,o','ba''a''r'
         self._re_csv_str = _re_compile(r'\x27(?:\x27\x27|[^\x27])*\x27')
index 86db65db8969a5b839befc3d1f84e8b5503be2e2..6b126ca0a1702c370a070c8419f4658261f8c8b9 100644 (file)
@@ -4,7 +4,7 @@ from sqlalchemy.testing import eq_, is_
 from sqlalchemy import Column, Table, DDL, MetaData, TIMESTAMP, \
     DefaultClause, String, Integer, Text, UnicodeText, SmallInteger,\
     NCHAR, LargeBinary, DateTime, select, UniqueConstraint, Unicode,\
-    BigInteger
+    BigInteger, Index
 from sqlalchemy import event
 from sqlalchemy import sql
 from sqlalchemy import exc
@@ -582,6 +582,20 @@ class ReflectionTest(fixtures.TestBase, AssertsExecutionResults):
         self.assert_(indexes['uc_a'].unique)
         self.assert_('uc_a' not in constraints)
 
+    @testing.provide_metadata
+    def test_non_column_index(self):
+        m1 = self.metadata
+        t1 = Table(
+            'add_ix', m1, Column('x', String(50)), mysql_engine='InnoDB')
+        Index('foo_idx', t1.c.x.desc())
+        m1.create_all()
+
+        insp = inspect(testing.db)
+        eq_(
+            insp.get_indexes("add_ix"),
+            [{'name': 'foo_idx', 'column_names': ['x'], 'unique': False}]
+        )
+
 
 class RawReflectionTest(fixtures.TestBase):
     __backend__ = True
@@ -621,6 +635,55 @@ class RawReflectionTest(fixtures.TestBase):
         assert regex.match(
             "  KEY (`id`) USING BTREE COMMENT 'prefix''text''suffix'")
 
+    def test_key_reflection_columns(self):
+        regex = self.parser._re_key
+        exprs = self.parser._re_keyexprs
+        m = regex.match(
+            "  KEY (`id`) USING BTREE COMMENT '''comment'")
+        eq_(m.group("columns"), '`id`')
+
+        m = regex.match(
+            "  KEY (`x`, `y`) USING BTREE")
+        eq_(m.group("columns"), '`x`, `y`')
+
+        eq_(
+            exprs.findall(m.group("columns")),
+            [("x", "", ""), ("y", "", "")]
+        )
+
+        m = regex.match(
+            "  KEY (`x`(25), `y`(15)) USING BTREE")
+        eq_(m.group("columns"), '`x`(25), `y`(15)')
+        eq_(
+            exprs.findall(m.group("columns")),
+            [("x", "25", ""), ("y", "15", "")]
+        )
+
+        m = regex.match(
+            "  KEY (`x`(25) DESC, `y`(15) ASC) USING BTREE")
+        eq_(m.group("columns"), '`x`(25) DESC, `y`(15) ASC')
+        eq_(
+            exprs.findall(m.group("columns")),
+            [("x", "25", "DESC"), ("y", "15", "ASC")]
+        )
+
+        m = regex.match(
+            "  KEY `foo_idx` (`x` DESC)")
+        eq_(m.group("columns"), '`x` DESC')
+        eq_(
+            exprs.findall(m.group("columns")),
+            [("x", "", "DESC")]
+        )
+
+        eq_(
+            exprs.findall(m.group("columns")),
+            [("x", "", "DESC")]
+        )
+
+        m = regex.match(
+            "  KEY `foo_idx` (`x` DESC, `y` ASC)")
+        eq_(m.group("columns"), '`x` DESC, `y` ASC')
+
     def test_fk_reflection(self):
         regex = self.parser._re_fk_constraint