]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
implement eager_grouping for expression clauselists
authorMike Bayer <mike_mp@zzzcomputing.com>
Mon, 16 Oct 2023 17:01:42 +0000 (13:01 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Mon, 16 Oct 2023 17:01:42 +0000 (13:01 -0400)
the expression clauselist feature added in #7744 failed to accommodate
this parameter that is used only by the PostgreSQL JSON
operators.

Fixed 2.0 regression caused by :ticket:`7744` where chains of expressions
involving PostgreSQL JSON operators combined with other operators such as
string concatenation would lose correct parenthesization, due to an
implementation detail specific to the PostgreSQL dialect.

Fixes: #10479
Change-Id: Ic168bf6afd8bf1cfa648f2bad22fdd7254feaa34

doc/build/changelog/unreleased_20/10479.rst [new file with mode: 0644]
lib/sqlalchemy/sql/compiler.py
test/dialect/postgresql/test_compiler.py
test/sql/test_operators.py

diff --git a/doc/build/changelog/unreleased_20/10479.rst b/doc/build/changelog/unreleased_20/10479.rst
new file mode 100644 (file)
index 0000000..2c9adfe
--- /dev/null
@@ -0,0 +1,8 @@
+.. change::
+    :tags: bug, postgresql
+    :tickets: 10479
+
+    Fixed 2.0 regression caused by :ticket:`7744` where chains of expressions
+    involving PostgreSQL JSON operators combined with other operators such as
+    string concatenation would lose correct parenthesization, due to an
+    implementation detail specific to the PostgreSQL dialect.
index 171dd1f1bd00d265334bec4bbb07d07e8dc5f787..58d249e8dd7bcd2c4d87cb25d37d08f4e840a151 100644 (file)
@@ -2742,6 +2742,7 @@ class SQLCompiler(Compiled):
         except KeyError as err:
             raise exc.UnsupportedCompilationError(self, operator_) from err
         else:
+            kw["_in_operator_expression"] = True
             return self._generate_delimited_list(
                 clauselist.clauses, opstring, **kw
             )
@@ -3370,9 +3371,9 @@ class SQLCompiler(Compiled):
     def _generate_generic_binary(
         self, binary, opstring, eager_grouping=False, **kw
     ):
-        _in_binary = kw.get("_in_binary", False)
+        _in_operator_expression = kw.get("_in_operator_expression", False)
 
-        kw["_in_binary"] = True
+        kw["_in_operator_expression"] = True
         kw["_binary_op"] = binary.operator
         text = (
             binary.left._compiler_dispatch(
@@ -3384,7 +3385,7 @@ class SQLCompiler(Compiled):
             )
         )
 
-        if _in_binary and eager_grouping:
+        if _in_operator_expression and eager_grouping:
             text = "(%s)" % text
         return text
 
index 6e2907039cad8d2dac7da6d16bcc830353ff78bb..5851a86e6d647fd5eb02399d0da03bc4ff8308a6 100644 (file)
@@ -43,6 +43,7 @@ from sqlalchemy.dialects.postgresql import array_agg as pg_array_agg
 from sqlalchemy.dialects.postgresql import DOMAIN
 from sqlalchemy.dialects.postgresql import ExcludeConstraint
 from sqlalchemy.dialects.postgresql import insert
+from sqlalchemy.dialects.postgresql import JSON
 from sqlalchemy.dialects.postgresql import JSONB
 from sqlalchemy.dialects.postgresql import JSONPATH
 from sqlalchemy.dialects.postgresql import Range
@@ -2556,6 +2557,23 @@ class CompileTest(fixtures.TestBase, AssertsCompiledSQL):
             "AS jsonb_path_exists_1 FROM data",
         )
 
+    @testing.combinations(
+        (lambda col: col["foo"] + " ", "(x -> %(x_1)s) || %(param_1)s"),
+        (
+            lambda col: col["foo"] + " " + col["bar"],
+            "(x -> %(x_1)s) || %(param_1)s || (x -> %(x_2)s)",
+        ),
+        argnames="expr, expected",
+    )
+    @testing.combinations((JSON(),), (JSONB(),), argnames="type_")
+    def test_eager_grouping_flag(self, expr, expected, type_):
+        """test #10479"""
+        col = Column("x", type_)
+
+        expr = testing.resolve_lambda(expr, col=col)
+
+        self.assert_compile(expr, expected)
+
     def test_custom_object_hook(self):
         # See issue #8884
         from datetime import date
index eca45c5d5d30ddceb36c85ffa0fdeb64f930757b..af51010c761a0169db4326ac419d8cc74d24fd33 100644 (file)
@@ -1010,6 +1010,21 @@ class JSONIndexOpTest(fixtures.TestBase, testing.AssertsCompiledSQL):
         is_(col[5]["foo"].type._type_affinity, JSON)
         is_(col[("a", "b", "c")].type._type_affinity, JSON)
 
+    @testing.combinations(
+        (lambda col: col["foo"] + " ", "(x -> :x_1) || :param_1"),
+        (
+            lambda col: col["foo"] + " " + col["bar"],
+            "(x -> :x_1) || :param_1 || (x -> :x_2)",
+        ),
+    )
+    def test_eager_grouping_flag(self, expr, expected):
+        """test #10479"""
+        col = Column("x", self.MyType())
+
+        expr = testing.resolve_lambda(expr, col=col)
+
+        self.assert_compile(expr, expected)
+
     def test_getindex_literal_integer(self):
         col = Column("x", self.MyType())