Skip to content

Commit 667a9ca

Browse files
committed
add bind casts for BYTEA on asyncpg
Fixed another regression due to the "insertmanyvalues" change in 2.0.10 as part of 🎫`9618`, in a similar way as regression 🎫`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
1 parent 228490e commit 667a9ca

4 files changed

Lines changed: 81 additions & 0 deletions

File tree

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
.. change::
2+
:tags: bug, postgresql, regression
3+
:tickets: 9739
4+
5+
Fixed another regression due to the "insertmanyvalues" change in 2.0.10 as
6+
part of :ticket:`9618`, in a similar way as regression :ticket:`9701`, where
7+
:class:`.LargeBinary` datatypes also need additional casts on when using the
8+
asyncpg driver specifically in order to work with the new bulk INSERT
9+
format.

lib/sqlalchemy/dialects/postgresql/asyncpg.py

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -182,6 +182,7 @@
182182
from .base import PGIdentifierPreparer
183183
from .base import REGCLASS
184184
from .base import REGCONFIG
185+
from .types import BYTEA
185186
from ... import exc
186187
from ... import pool
187188
from ... import util
@@ -212,6 +213,10 @@ class AsyncpgTime(sqltypes.Time):
212213
render_bind_cast = True
213214

214215

216+
class AsyncpgByteA(BYTEA):
217+
render_bind_cast = True
218+
219+
215220
class AsyncpgDate(sqltypes.Date):
216221
render_bind_cast = True
217222

@@ -986,6 +991,7 @@ class PGDialect_asyncpg(PGDialect):
986991
sqltypes.Numeric: AsyncpgNumeric,
987992
sqltypes.Float: AsyncpgFloat,
988993
sqltypes.JSON: AsyncpgJSON,
994+
sqltypes.LargeBinary: AsyncpgByteA,
989995
json.JSONB: AsyncpgJSONB,
990996
sqltypes.JSON.JSONPathType: AsyncpgJSONPathType,
991997
sqltypes.JSON.JSONIndexType: AsyncpgJSONIndexType,

lib/sqlalchemy/testing/suite/test_insert.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,8 @@ def test_insert_w_floats(
430430
this tests insertmanyvalues as well as decimal / floating point
431431
RETURNING types
432432
433+
TODO: this might be better in suite/test_types?
434+
433435
"""
434436

435437
t = Table(

lib/sqlalchemy/testing/suite/test_types.py

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from ... import Date
2727
from ... import DateTime
2828
from ... import Float
29+
from ... import Identity
2930
from ... import Integer
3031
from ... import JSON
3132
from ... import literal
@@ -45,6 +46,7 @@
4546
from ... import UnicodeText
4647
from ... import UUID
4748
from ... import Uuid
49+
from ...dialects.postgresql import BYTEA
4850
from ...orm import declarative_base
4951
from ...orm import Session
5052
from ...sql.sqltypes import LargeBinary
@@ -313,6 +315,68 @@ def test_pickle_roundtrip(self, connection):
313315
row = connection.execute(select(binary_table.c.pickle_data)).first()
314316
eq_(row, ({"foo": [1, 2, 3], "bar": "bat"},))
315317

318+
@testing.combinations(
319+
(
320+
LargeBinary(),
321+
b"this is binary",
322+
),
323+
(LargeBinary(), b"7\xe7\x9f"),
324+
(BYTEA(), b"7\xe7\x9f", testing.only_on("postgresql")),
325+
argnames="type_,value",
326+
)
327+
@testing.variation("sort_by_parameter_order", [True, False])
328+
@testing.variation("multiple_rows", [True, False])
329+
@testing.requires.insert_returning
330+
def test_imv_returning(
331+
self,
332+
connection,
333+
metadata,
334+
sort_by_parameter_order,
335+
type_,
336+
value,
337+
multiple_rows,
338+
):
339+
"""test #9739 (similar to #9701).
340+
341+
this tests insertmanyvalues as well as binary
342+
RETURNING types
343+
344+
"""
345+
t = Table(
346+
"t",
347+
metadata,
348+
Column("id", Integer, Identity(), primary_key=True),
349+
Column("value", type_),
350+
)
351+
352+
t.create(connection)
353+
354+
result = connection.execute(
355+
t.insert().returning(
356+
t.c.id,
357+
t.c.value,
358+
sort_by_parameter_order=bool(sort_by_parameter_order),
359+
),
360+
[{"value": value} for i in range(10)]
361+
if multiple_rows
362+
else {"value": value},
363+
)
364+
365+
if multiple_rows:
366+
i_range = range(1, 11)
367+
else:
368+
i_range = range(1, 2)
369+
370+
eq_(
371+
set(result),
372+
{(id_, value) for id_ in i_range},
373+
)
374+
375+
eq_(
376+
set(connection.scalars(select(t.c.value))),
377+
{value},
378+
)
379+
316380

317381
class TextTest(_LiteralRoundTripFixture, fixtures.TablesTest):
318382
__requires__ = ("text_type",)

0 commit comments

Comments
 (0)