]> 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:28:43 +0000 (17:28 -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
(cherry picked from commit 9dedf37446108196b585ffdcef8dd48c378d1401)

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 c44f2ac21e98d324e9c6205fad5044efb15a8ea3..e7bf7c9b34bfffb1301be5f1a863997802c055c2 100644 (file)
@@ -893,6 +893,7 @@ from ...engine import default
 from ...engine import reflection
 from ...sql import compiler
 from ...sql import elements
+from ...sql import operators
 from ...sql import util as sql_util
 from ...types import BINARY
 from ...types import BLOB
@@ -1842,9 +1843,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 8de027dadb7b0602ab112a0b44a33938fd6b162a..895bf4b55ea40c4a2d256a6d52fff29628a513a9 100644 (file)
@@ -288,7 +288,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):