From: RamonWill Date: Wed, 16 Sep 2020 21:47:21 +0000 (-0400) Subject: Support indexing on expressions and functions for the MySQL dialect X-Git-Tag: rel_1_4_0b1~36 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=1cda8e18bf4e9b36d07b9d54c04e1fe035977064;p=thirdparty%2Fsqlalchemy%2Fsqlalchemy.git Support indexing on expressions and functions for the MySQL dialect 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 --- diff --git a/doc/build/changelog/unreleased_13/5462.rst b/doc/build/changelog/unreleased_13/5462.rst new file mode 100644 index 0000000000..2832284ebf --- /dev/null +++ b/doc/build/changelog/unreleased_13/5462.rst @@ -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. diff --git a/lib/sqlalchemy/dialects/mysql/base.py b/lib/sqlalchemy/dialects/mysql/base.py index 8fb4c3b4b4..3e6c676aba 100644 --- a/lib/sqlalchemy/dialects/mysql/base.py +++ b/lib/sqlalchemy/dialects/mysql/base.py @@ -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 ] diff --git a/test/dialect/mysql/test_compiler.py b/test/dialect/mysql/test_compiler.py index b222431ebd..7bddebd176 100644 --- a/test/dialect/mysql/test_compiler.py +++ b/test/dialect/mysql/test_compiler.py @@ -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):