]> git.ipfire.org Git - thirdparty/sqlalchemy/sqlalchemy.git/commitdiff
add bind casts for BYTEA on asyncpg
authorMike Bayer <mike_mp@zzzcomputing.com>
Thu, 4 May 2023 02:33:28 +0000 (22:33 -0400)
committerMike Bayer <mike_mp@zzzcomputing.com>
Thu, 4 May 2023 12:47:11 +0000 (08:47 -0400)
Fixed another regression due to the "insertmanyvalues" change in 2.0.10 as
part of :ticket:`9618`, in a similar way as regression :ticket:`9701`, where
:class:`.LargeBinary` datatypes also need additional casts on when using the
asyncpg driver specifically in order to work with the new bulk INSERT
format.

Fixes: #9739
Change-Id: I57370d269ea757f263c1f3a16c324ceae76fd4e8

doc/build/changelog/unreleased_20/9739.rst [new file with mode: 0644]
lib/sqlalchemy/dialects/postgresql/asyncpg.py
lib/sqlalchemy/testing/suite/test_insert.py
lib/sqlalchemy/testing/suite/test_types.py

diff --git a/doc/build/changelog/unreleased_20/9739.rst b/doc/build/changelog/unreleased_20/9739.rst
new file mode 100644 (file)
index 0000000..987d69c
--- /dev/null
@@ -0,0 +1,9 @@
+.. change::
+    :tags: bug, postgresql, regression
+    :tickets: 9739
+
+    Fixed another regression due to the "insertmanyvalues" change in 2.0.10 as
+    part of :ticket:`9618`, in a similar way as regression :ticket:`9701`, where
+    :class:`.LargeBinary` datatypes also need additional casts on when using the
+    asyncpg driver specifically in order to work with the new bulk INSERT
+    format.
index c879205e4a18ae70670588a7f40ed699d059adb5..3f33600f91c54fe0103b098e1739e12111736534 100644 (file)
@@ -182,6 +182,7 @@ from .base import PGExecutionContext
 from .base import PGIdentifierPreparer
 from .base import REGCLASS
 from .base import REGCONFIG
+from .types import BYTEA
 from ... import exc
 from ... import pool
 from ... import util
@@ -212,6 +213,10 @@ class AsyncpgTime(sqltypes.Time):
     render_bind_cast = True
 
 
+class AsyncpgByteA(BYTEA):
+    render_bind_cast = True
+
+
 class AsyncpgDate(sqltypes.Date):
     render_bind_cast = True
 
@@ -986,6 +991,7 @@ class PGDialect_asyncpg(PGDialect):
             sqltypes.Numeric: AsyncpgNumeric,
             sqltypes.Float: AsyncpgFloat,
             sqltypes.JSON: AsyncpgJSON,
+            sqltypes.LargeBinary: AsyncpgByteA,
             json.JSONB: AsyncpgJSONB,
             sqltypes.JSON.JSONPathType: AsyncpgJSONPathType,
             sqltypes.JSON.JSONIndexType: AsyncpgJSONIndexType,
index d49eb3284ffecd0e6c3c8ab88de55e200c5893ee..39150342202d742c1706c08513927e23473ba674 100644 (file)
@@ -430,6 +430,8 @@ class ReturningTest(fixtures.TablesTest):
         this tests insertmanyvalues as well as decimal / floating point
         RETURNING types
 
+        TODO: this might be better in suite/test_types?
+
         """
 
         t = Table(
index 72f1e8c10f68866849d8b1056c19352b3131e2ba..ba2dda9efe96caf14715502710c82e2a37d7a654 100644 (file)
@@ -26,6 +26,7 @@ from ... import cast
 from ... import Date
 from ... import DateTime
 from ... import Float
+from ... import Identity
 from ... import Integer
 from ... import JSON
 from ... import literal
@@ -45,6 +46,7 @@ from ... import Unicode
 from ... import UnicodeText
 from ... import UUID
 from ... import Uuid
+from ...dialects.postgresql import BYTEA
 from ...orm import declarative_base
 from ...orm import Session
 from ...sql.sqltypes import LargeBinary
@@ -313,6 +315,68 @@ class BinaryTest(_LiteralRoundTripFixture, fixtures.TablesTest):
         row = connection.execute(select(binary_table.c.pickle_data)).first()
         eq_(row, ({"foo": [1, 2, 3], "bar": "bat"},))
 
+    @testing.combinations(
+        (
+            LargeBinary(),
+            b"this is binary",
+        ),
+        (LargeBinary(), b"7\xe7\x9f"),
+        (BYTEA(), b"7\xe7\x9f", testing.only_on("postgresql")),
+        argnames="type_,value",
+    )
+    @testing.variation("sort_by_parameter_order", [True, False])
+    @testing.variation("multiple_rows", [True, False])
+    @testing.requires.insert_returning
+    def test_imv_returning(
+        self,
+        connection,
+        metadata,
+        sort_by_parameter_order,
+        type_,
+        value,
+        multiple_rows,
+    ):
+        """test #9739 (similar to #9701).
+
+        this tests insertmanyvalues as well as binary
+        RETURNING types
+
+        """
+        t = Table(
+            "t",
+            metadata,
+            Column("id", Integer, Identity(), primary_key=True),
+            Column("value", type_),
+        )
+
+        t.create(connection)
+
+        result = connection.execute(
+            t.insert().returning(
+                t.c.id,
+                t.c.value,
+                sort_by_parameter_order=bool(sort_by_parameter_order),
+            ),
+            [{"value": value} for i in range(10)]
+            if multiple_rows
+            else {"value": value},
+        )
+
+        if multiple_rows:
+            i_range = range(1, 11)
+        else:
+            i_range = range(1, 2)
+
+        eq_(
+            set(result),
+            {(id_, value) for id_ in i_range},
+        )
+
+        eq_(
+            set(connection.scalars(select(t.c.value))),
+            {value},
+        )
+
 
 class TextTest(_LiteralRoundTripFixture, fixtures.TablesTest):
     __requires__ = ("text_type",)