--- /dev/null
+.. change::
+ :tags: bug, orm
+ :tickets: 11332
+
+ Fixes issue in :meth:`_orm.Session.bulk_save_objects` where it would write a
+ wrong identity key when using ``return_defaults=True``.
+ The wrong identity key could lead to an index error when entities are then pickled.
mapper: Mapper[_O],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
return_defaults: bool,
render_nulls: bool,
mapper: Mapper[_O],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
return_defaults: bool,
render_nulls: bool,
mapper: Mapper[_O],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
return_defaults: bool,
render_nulls: bool,
state.key = (
identity_cls,
tuple([dict_[key] for key in identity_props]),
+ None,
)
if use_orm_insert_stmt is not None:
mapper: Mapper[Any],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
update_changed_only: bool,
use_orm_update_stmt: Literal[None] = ...,
mapper: Mapper[Any],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
update_changed_only: bool,
use_orm_update_stmt: Optional[dml.Update] = ...,
mapper: Mapper[Any],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
session_transaction: SessionTransaction,
+ *,
isstates: bool,
update_changed_only: bool,
use_orm_update_stmt: Optional[dml.Update] = None,
self._bulk_save_mappings(
mapper,
states,
- isupdate,
- True,
- return_defaults,
- update_changed_only,
- False,
+ isupdate=isupdate,
+ isstates=True,
+ return_defaults=return_defaults,
+ update_changed_only=update_changed_only,
+ render_nulls=False,
)
def bulk_insert_mappings(
self._bulk_save_mappings(
mapper,
mappings,
- False,
- False,
- return_defaults,
- False,
- render_nulls,
+ isupdate=False,
+ isstates=False,
+ return_defaults=return_defaults,
+ update_changed_only=False,
+ render_nulls=render_nulls,
)
def bulk_update_mappings(
"""
self._bulk_save_mappings(
- mapper, mappings, True, False, False, False, False
+ mapper,
+ mappings,
+ isupdate=True,
+ isstates=False,
+ return_defaults=False,
+ update_changed_only=False,
+ render_nulls=False,
)
def _bulk_save_mappings(
self,
mapper: Mapper[_O],
mappings: Union[Iterable[InstanceState[_O]], Iterable[Dict[str, Any]]],
+ *,
isupdate: bool,
isstates: bool,
return_defaults: bool,
mapper,
mappings,
transaction,
- isstates,
- update_changed_only,
+ isstates=isstates,
+ update_changed_only=update_changed_only,
)
else:
bulk_persistence._bulk_insert(
mapper,
mappings,
transaction,
- isstates,
- return_defaults,
- render_nulls,
+ isstates=isstates,
+ return_defaults=return_defaults,
+ render_nulls=render_nulls,
)
transaction.commit()
from sqlalchemy import ForeignKey
from sqlalchemy import Identity
from sqlalchemy import insert
+from sqlalchemy import inspect
from sqlalchemy import Integer
from sqlalchemy import String
from sqlalchemy import testing
if statement_type == "save_objects":
eq_(objects[0].__dict__["id"], 1)
+ def test_bulk_save_objects_defaults_key(self):
+ User = self.classes.User
+
+ pes = [User(name=f"foo{i}") for i in range(3)]
+ s = fixture_session()
+ s.bulk_save_objects(pes, return_defaults=True)
+ key = inspect(pes[0]).key
+
+ s.commit()
+ eq_(inspect(s.get(User, 1)).key, key)
+
def test_bulk_save_mappings_preserve_order(self):
(User,) = self.classes("User")
)
is_not_none(collections.collection_adapter(repickled.addresses))
+ def test_bulk_save_objects_defaults_pickle(self):
+ "Test for #11332"
+ users = self.tables.users
+
+ self.mapper_registry.map_imperatively(User, users)
+ pes = [User(name=f"foo{i}") for i in range(3)]
+ s = fixture_session()
+ s.bulk_save_objects(pes, return_defaults=True)
+ state = pickle.dumps(pes)
+ pickle.loads(state)
+
class OptionsTest(_Polymorphic):
def test_options_of_type(self):