]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
include parsed col length field as integer from mysql index reflection
authorMike Bayer <mike_mp@zzzcomputing.com>
Wed, 4 Jan 2023 14:23:07 +0000 (09:23 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Wed, 4 Jan 2023 17:29:49 +0000 (12:29 -0500)
Added support to MySQL index reflection to correctly reflect the
``mysql_length`` dictionary, which previously was being ignored.

Fixes: #9047
Change-Id: I0a5e27123be68741e12af4464a0fa305052ec36e

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

diff --git a/doc/build/changelog/unreleased_14/9047.rst b/doc/build/changelog/unreleased_14/9047.rst
new file mode 100644 (file)
index 0000000..7411089
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: usecase, mysql
+    :tickets: 9047
+    :versions: 2.0.0
+
+    Added support to MySQL index reflection to correctly reflect the
+    ``mysql_length`` dictionary, which previously was being ignored.
index fbd20a0ba89ca57f962070f362f401838ec6e6a2..e89ebb09de7ec9c5c7642c5b49ad1683e34920ea 100644 (file)
@@ -3075,14 +3075,22 @@ class MySQLDialect(default.DefaultDialect):
                 ]
 
             index_d = {}
-            if dialect_options:
-                index_d["dialect_options"] = dialect_options
 
             index_d["name"] = spec["name"]
             index_d["column_names"] = [s[0] for s in spec["columns"]]
+            mysql_length = {
+                s[0]: s[1] for s in spec["columns"] if s[1] is not None
+            }
+            if mysql_length:
+                dialect_options["%s_length" % self.name] = mysql_length
+
             index_d["unique"] = unique
             if flavor:
                 index_d["type"] = flavor
+
+            if dialect_options:
+                index_d["dialect_options"] = dialect_options
+
             indexes.append(index_d)
         indexes.sort(key=lambda d: d["name"] or "~")  # sort None as last
         return indexes if indexes else ReflectionDefaults.indexes()
index fe92c733a4966fd27a7cf412931837bc9c6e9a95..ec3f82a6008c753d15ccc3b3174c243509fdaef7 100644 (file)
@@ -382,7 +382,12 @@ class MySQLTableDefinitionParser:
     def _parse_keyexprs(self, identifiers):
         """Unpack '"col"(2),"col" ASC'-ish strings into components."""
 
-        return self._re_keyexprs.findall(identifiers)
+        return [
+            (colname, int(length) if length else None, modifiers)
+            for colname, length, modifiers in self._re_keyexprs.findall(
+                identifiers
+            )
+        ]
 
     def _prep_regexes(self):
         """Pre-compile regular expressions."""
index 5e582a492380f15e523cea9368b42588e8934279..f9975a97380f1572666e38e101504e076324bb69 100644 (file)
@@ -920,6 +920,93 @@ class ReflectionTest(fixtures.TestBase, AssertsCompiledSQL):
             "CREATE FULLTEXT INDEX textdata_ix ON mytable (textdata)",
         )
 
+    def test_reflect_index_col_length(self, metadata, connection):
+        """test for #9047"""
+
+        tt = Table(
+            "test_table",
+            metadata,
+            Column("signal_type", Integer(), nullable=False),
+            Column("signal_data", String(200), nullable=False),
+            Column("signal_data_2", String(200), nullable=False),
+            Index(
+                "ix_1",
+                "signal_type",
+                "signal_data",
+                mysql_length={"signal_data": 25},
+                mariadb_length={"signal_data": 25},
+            ),
+        )
+        Index(
+            "ix_2",
+            tt.c.signal_type,
+            tt.c.signal_data,
+            tt.c.signal_data_2,
+            mysql_length={"signal_data": 25, "signal_data_2": 10},
+            mariadb_length={"signal_data": 25, "signal_data_2": 10},
+        )
+
+        mysql_length = (
+            "mysql_length"
+            if not connection.dialect.is_mariadb
+            else "mariadb_length"
+        )
+        eq_(
+            {idx.name: idx.kwargs[mysql_length] for idx in tt.indexes},
+            {
+                "ix_1": {"signal_data": 25},
+                "ix_2": {"signal_data": 25, "signal_data_2": 10},
+            },
+        )
+
+        metadata.create_all(connection)
+
+        eq_(
+            sorted(
+                inspect(connection).get_indexes("test_table"),
+                key=lambda rec: rec["name"],
+            ),
+            [
+                {
+                    "name": "ix_1",
+                    "column_names": ["signal_type", "signal_data"],
+                    "unique": False,
+                    "dialect_options": {mysql_length: {"signal_data": 25}},
+                },
+                {
+                    "name": "ix_2",
+                    "column_names": [
+                        "signal_type",
+                        "signal_data",
+                        "signal_data_2",
+                    ],
+                    "unique": False,
+                    "dialect_options": {
+                        mysql_length: {
+                            "signal_data": 25,
+                            "signal_data_2": 10,
+                        }
+                    },
+                },
+            ],
+        )
+
+        new_metadata = MetaData()
+        reflected_table = Table(
+            "test_table", new_metadata, autoload_with=connection
+        )
+
+        eq_(
+            {
+                idx.name: idx.kwargs[mysql_length]
+                for idx in reflected_table.indexes
+            },
+            {
+                "ix_1": {"signal_data": 25},
+                "ix_2": {"signal_data": 25, "signal_data_2": 10},
+            },
+        )
+
     @testing.requires.mysql_ngram_fulltext
     def test_reflect_fulltext_comment(
         self,