]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
narrow the check for double-paren exprs in mysql create_index
authorMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Dec 2020 16:16:51 +0000 (11:16 -0500)
committerMike Bayer <mike_mp@zzzcomputing.com>
Sat, 26 Dec 2020 21:00:52 +0000 (16:00 -0500)
Fixed regression from SQLAlchemy 1.3.20 caused by the fix for
:ticket:`5462` which adds double-parenthesis for MySQL functional
expressions in indexes, as is required by the backend, this inadvertently
extended to include arbitrary :func:`_sql.text` expressions as well as
Alembic's internal textual component,  which are required by Alembic for
arbitrary index expressions which don't imply double parenthesis.  The
check has been narrowed to include only binary/ unary/functional
expressions directly.

Fixes: #5800
Change-Id: I40f83c6f9dd04b984d0c86eba632a588570709a1
(cherry picked from commit e81bc1f098ea40cf38ec4e4007c11c7f3ffc9712)

doc/build/changelog/unreleased_13/5800.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/5800.rst b/doc/build/changelog/unreleased_13/5800.rst
new file mode 100644 (file)
index 0000000..11bb730
--- /dev/null
@@ -0,0 +1,12 @@
+.. change::
+    :tags: bug, mysql
+    :tickets: 5800
+
+    Fixed regression from SQLAlchemy 1.3.20 caused by the fix for
+    :ticket:`5462` which adds double-parenthesis for MySQL functional
+    expressions in indexes, as is required by the backend, this inadvertently
+    extended to include arbitrary :func:`_sql.text` expressions as well as
+    Alembic's internal textual component,  which are required by Alembic for
+    arbitrary index expressions which don't imply double parenthesis.  The
+    check has been narrowed to include only binary/ unary/functional
+    expressions directly.
\ No newline at end of file
index e1aef37968c1ee5a99861ef57b1b3691d2d6955c..5962f7faba095a2a008a0eb0dc22941f1af33efa 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 functions
 from ...sql import operators
 from ...sql import util as sql_util
 from ...types import BINARY
@@ -1853,12 +1854,13 @@ class MySQLDDLCompiler(compiler.DDLCompiler):
             self.sql_compiler.process(
                 elements.Grouping(expr)
                 if (
-                    not isinstance(expr, elements.ColumnClause)
-                    and (
-                        not isinstance(expr, elements.UnaryExpression)
-                        or expr.modifier
+                    isinstance(expr, elements.BinaryExpression)
+                    or (
+                        isinstance(expr, elements.UnaryExpression)
+                        and expr.modifier
                         not in (operators.desc_op, operators.asc_op)
                     )
+                    or isinstance(expr, functions.FunctionElement)
                 )
                 else expr,
                 include_table=False,
index 895bf4b55ea40c4a2d256a6d52fff29628a513a9..6a0202b22948325b7d283bcf3778f9d41af0fc52 100644 (file)
@@ -40,6 +40,7 @@ from sqlalchemy import String
 from sqlalchemy import Table
 from sqlalchemy import testing
 from sqlalchemy import TEXT
+from sqlalchemy import text
 from sqlalchemy import TIME
 from sqlalchemy import Time
 from sqlalchemy import TIMESTAMP
@@ -99,6 +100,45 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "CREATE FULLTEXT INDEX test_idx1 " "ON testtbl (data(10))",
         )
 
+    def test_create_index_with_text(self):
+        m = MetaData()
+        tbl = Table("testtbl", m, Column("data", String(255)))
+        idx = Index("test_idx1", text("created_at desc"), _table=tbl)
+
+        self.assert_compile(
+            schema.CreateIndex(idx),
+            "CREATE INDEX test_idx1 ON testtbl (created_at desc)",
+        )
+
+    def test_create_index_with_arbitrary_column_element(self):
+        from sqlalchemy.ext.compiler import compiles
+
+        class _textual_index_element(sql.ColumnElement):
+            """alembic's wrapper"""
+
+            __visit_name__ = "_textual_idx_element"
+
+            def __init__(self, table, text):
+                self.table = table
+                self.text = text
+
+        @compiles(_textual_index_element)
+        def _render_textual_index_column(element, compiler, **kw):
+            return compiler.process(element.text, **kw)
+
+        m = MetaData()
+        tbl = Table("testtbl", m, Column("data", String(255)))
+        idx = Index(
+            "test_idx1",
+            _textual_index_element(tbl, text("created_at desc")),
+            _table=tbl,
+        )
+
+        self.assert_compile(
+            schema.CreateIndex(idx),
+            "CREATE INDEX test_idx1 ON testtbl (created_at desc)",
+        )
+
     def test_create_index_with_parser(self):
         m = MetaData()
         tbl = Table("testtbl", m, Column("data", String(255)))