]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
Support indexing on expressions and functions for the MySQL dialect
authorRamonWill <ramonwilliams@hotmail.co.uk>
Wed, 16 Sep 2020 21:47:21 +0000 (17:47 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 12 Oct 2020 21:38:34 +0000 (17:38 -0400)
A user noticed that creating an index where the "key part" was an expression
or function would raise an error for MySQL because the key part was not
parenthesized. The proposed change will check whether a key part is not a
Column or Unary Expression  and parenthesize if the case is False.

This fix also contains a minor fix to a test case that was previously incorrect
(`def test_create_index_expr():`).

**Have a nice day!**
Fixes: #5462
Closes: #5587
Pull-request: https://github.com/sqlalchemy/sqlalchemy/pull/5587
Pull-request-sha: 7515e50cd7435744fc79c210b2f3aa4c0546ba28

Change-Id: Id1b3b3026983c0e05808baa243e354f82b78180c

doc/build/changelog/unreleased_13/5462.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/mysql/base.py
test/dialect/mysql/test_compiler.py

diff --git a/doc/build/changelog/unreleased_13/5462.rst b/doc/build/changelog/unreleased_13/5462.rst
new file mode 100644 (file)
index 0000000..2832284
--- /dev/null
@@ -0,0 +1,7 @@
+.. change::
+    :tags: mysql, usecase
+    :tickets: 5462
+
+    Adjusted the :meth:`MySQLDDLCompiler.visit_create_index` to implement
+    indexing with expressions and functions on the MySQL dialect as accepted by
+    MySQL 8. Pull request courtesy Ramon Williams.
index 8fb4c3b4b43d5ee3c00684f096b33f3c37e9e385..3e6c676ababffcf121ec9e7179946d462cf80f8a 100644 (file)
@@ -952,6 +952,7 @@ from ...engine import reflection
 from ...sql import coercions
 from ...sql import compiler
 from ...sql import elements
+from ...sql import operators
 from ...sql import roles
 from ...sql import util as sql_util
 from ...sql.sqltypes import Unicode
@@ -1975,9 +1976,21 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
         self._verify_index_table(index)
         preparer = self.preparer
         table = preparer.format_table(index.table)
+
         columns = [
             self.sql_compiler.process(
-                expr, include_table=False, literal_binds=True
+                elements.Grouping(expr)
+                if (
+                    not isinstance(expr, elements.ColumnClause)
+                    and (
+                        not isinstance(expr, elements.UnaryExpression)
+                        or expr.modifier
+                        not in (operators.desc_op, operators.asc_op)
+                    )
+                )
+                else expr,
+                include_table=False,
+                literal_binds=True,
             )
             for expr in index.expressions
         ]
index b222431ebde558361ede8c630d9e2445b5d83065..7bddebd176d847f8b447bd62227c0a448514fea2 100644 (file)
@@ -286,7 +286,50 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
         t1 = Table("foo", m, Column("x", Integer))
         self.assert_compile(
             schema.CreateIndex(Index("bar", t1.c.x > 5)),
-            "CREATE INDEX bar ON foo (x > 5)",
+            "CREATE INDEX bar ON foo ((x > 5))",
+        )
+
+    def test_create_index_expr_two(self):
+        m = MetaData()
+        tbl = Table("testtbl", m, Column("x", Integer), Column("y", Integer))
+        idx1 = Index("test_idx1", tbl.c.x + tbl.c.y)
+        idx2 = Index(
+            "test_idx2", tbl.c.x, tbl.c.x + tbl.c.y, tbl.c.y - tbl.c.x
+        )
+        idx3 = Index("test_idx3", tbl.c.x.desc())
+
+        self.assert_compile(
+            schema.CreateIndex(idx1),
+            "CREATE INDEX test_idx1 ON testtbl ((x + y))",
+        )
+        self.assert_compile(
+            schema.CreateIndex(idx2),
+            "CREATE INDEX test_idx2 ON testtbl (x, (x + y), (y - x))",
+        )
+
+        self.assert_compile(
+            schema.CreateIndex(idx3),
+            "CREATE INDEX test_idx3 ON testtbl (x DESC)",
+        )
+
+    def test_create_index_expr_func(self):
+        m = MetaData()
+        tbl = Table("testtbl", m, Column("data", Integer))
+        idx1 = Index("test_idx1", func.radians(tbl.c.data))
+
+        self.assert_compile(
+            schema.CreateIndex(idx1),
+            "CREATE INDEX test_idx1 ON testtbl ((radians(data)))",
+        )
+
+    def test_create_index_expr_func_unary(self):
+        m = MetaData()
+        tbl = Table("testtbl", m, Column("data", Integer))
+        idx1 = Index("test_idx1", -tbl.c.data)
+
+        self.assert_compile(
+            schema.CreateIndex(idx1),
+            "CREATE INDEX test_idx1 ON testtbl ((-data))",
         )
 
     def test_deferrable_initially_kw_not_ignored(self):