--- /dev/null
+.. change::
+ :tags: bug, postgresql, regression
+ :tickets: 9808
+
+ Repaired the base :class:`.Uuid` datatype for the PostgreSQL dialect to
+ make proper use of the PG-specific ``UUID`` internal datatype when
+ "native_uuid" is selected, so that PG driver behaviors are included. This
+ issue became apparent due to the insertmanyvalues improvement made as part
+ of :ticket:`9618`, where in a similar manner as that of :ticket:` 9739`
+ where the asyncpg driver is very sensitive to datatype casts being present
+ or not, the PostgreSQL driver-specific native ``UUID`` datatype must be
+ invoked when this generic type is used.
+
sqltypes.Enum: ENUM,
sqltypes.JSON.JSONPathType: _json.JSONPATH,
sqltypes.JSON: _json.JSON,
- UUID: PGUuid,
+ sqltypes.Uuid: PGUuid,
}
self.connection.execute(DropEnumType(enum))
-class ENUM(NamedType, sqltypes.NativeForEmulated, sqltypes.Enum):
+class ENUM(NamedType, type_api.NativeForEmulated, sqltypes.Enum):
"""PostgreSQL ENUM type.
_UUID_RETURN = TypeVar("_UUID_RETURN", str, _python_UUID)
-class Uuid(TypeEngine[_UUID_RETURN]):
+class Uuid(Emulated, TypeEngine[_UUID_RETURN]):
"""Represent a database agnostic UUID datatype.
def python_type(self):
return _python_UUID if self.as_uuid else str
+ @property
+ def native(self):
+ return self.native_uuid
+
def coerce_compared_value(self, op, value):
"""See :meth:`.TypeEngine.coerce_compared_value` for a description."""
return process
-class UUID(Uuid[_UUID_RETURN]):
+class UUID(Uuid[_UUID_RETURN], type_api.NativeForEmulated):
"""Represent the SQL UUID type.
self.as_uuid = as_uuid
self.native_uuid = True
+ @classmethod
+ def adapt_emulated_to_native(cls, impl, **kw):
+ kw.setdefault("as_uuid", impl.as_uuid)
+ return cls(**kw)
+
NULLTYPE = NullType()
BOOLEANTYPE = Boolean()
# mypy: ignore-errors
from decimal import Decimal
+import uuid
from . import testing
from .. import fixtures
from ... import Numeric
from ... import select
from ... import String
+from ...dialects.postgresql import BYTEA
+from ...types import LargeBinary
+from ...types import UUID
+from ...types import Uuid
class LastrowidTest(fixtures.TablesTest):
this tests insertmanyvalues as well as decimal / floating point
RETURNING types
- TODO: this might be better in suite/test_types?
-
"""
t = Table(
- "t",
+ # Oracle backends seems to be getting confused if
+ # this table is named the same as the one
+ # in test_imv_returning_datatypes. use a different name
+ "f_t",
metadata,
Column("id", Integer, Identity(), primary_key=True),
Column("value", type_),
{value},
)
+ @testing.combinations(
+ (
+ "non_native_uuid",
+ Uuid(native_uuid=False),
+ uuid.uuid4(),
+ ),
+ (
+ "non_native_uuid_str",
+ Uuid(as_uuid=False, native_uuid=False),
+ str(uuid.uuid4()),
+ ),
+ (
+ "generic_native_uuid",
+ Uuid(native_uuid=True),
+ uuid.uuid4(),
+ testing.requires.uuid_data_type,
+ ),
+ ("UUID", UUID(), uuid.uuid4(), testing.requires.uuid_data_type),
+ (
+ "LargeBinary1",
+ LargeBinary(),
+ b"this is binary",
+ ),
+ ("LargeBinary2", LargeBinary(), b"7\xe7\x9f"),
+ ("PG BYTEA", BYTEA(), b"7\xe7\x9f", testing.only_on("postgresql")),
+ argnames="type_,value",
+ id_="iaa",
+ )
+ @testing.variation("sort_by_parameter_order", [True, False])
+ @testing.variation("multiple_rows", [True, False])
+ @testing.requires.insert_returning
+ def test_imv_returning_datatypes(
+ self,
+ connection,
+ metadata,
+ sort_by_parameter_order,
+ type_,
+ value,
+ multiple_rows,
+ ):
+ """test #9739, #9808 (similar to #9701).
+
+ this tests insertmanyvalues in conjunction with various datatypes.
+
+ These tests are particularly for the asyncpg driver which needs
+ most types to be explicitly cast for the new IMV format
+
+ """
+ t = Table(
+ "d_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},
+ )
+
__all__ = ("LastrowidTest", "InsertBehaviorTest", "ReturningTest")
from ... import Date
from ... import DateTime
from ... import Float
-from ... import Identity
from ... import Integer
from ... import JSON
from ... import literal
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 import sqltypes
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",)