From 80b90cbcfe91e94f67d768d407fa274ec75e69cd Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 23 Jun 2021 16:34:05 -0400 Subject: [PATCH] Add Executable to DefaultGenerator Fixed the class hierarchy for the :class:`_schema.Sequence` and the more general :class:`_schema.DefaultGenerator` base, as these are "executable" as statements they need to include :class:`_sql.Executable` in their hierarchy, not just :class:`_roles.StatementRole` as was applied arbitrarily to :class:`_schema.Sequence` previously. The fix allows :class:`_schema.Sequence` to work in all ``.execute()`` methods including with :meth:`_orm.Session.execute` which was not working in the case that a ``do_orm_execute()`` handler was also established. Fixes: #6668 Change-Id: I0d192258c7cbd1bce2552f9e748e8fdd680dc45f --- doc/build/changelog/unreleased_14/6668.rst | 13 +++++++++++ lib/sqlalchemy/engine/base.py | 2 +- lib/sqlalchemy/sql/schema.py | 5 +++-- test/orm/test_session.py | 26 +++++++++++++++------- 4 files changed, 35 insertions(+), 11 deletions(-) create mode 100644 doc/build/changelog/unreleased_14/6668.rst diff --git a/doc/build/changelog/unreleased_14/6668.rst b/doc/build/changelog/unreleased_14/6668.rst new file mode 100644 index 0000000000..489864142c --- /dev/null +++ b/doc/build/changelog/unreleased_14/6668.rst @@ -0,0 +1,13 @@ +.. change:: + :tags: bug, sql, orm + :tickets: 6668 + + Fixed the class hierarchy for the :class:`_schema.Sequence` and the more + general :class:`_schema.DefaultGenerator` base, as these are "executable" + as statements they need to include :class:`_sql.Executable` in their + hierarchy, not just :class:`_roles.StatementRole` as was applied + arbitrarily to :class:`_schema.Sequence` previously. The fix allows + :class:`_schema.Sequence` to work in all ``.execute()`` methods including + with :meth:`_orm.Session.execute` which was not working in the case that a + ``do_orm_execute()`` handler was also established. + diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py index 64f638a50d..c21677a81e 100644 --- a/lib/sqlalchemy/engine/base.py +++ b/lib/sqlalchemy/engine/base.py @@ -1835,7 +1835,7 @@ class Connection(Connectable): if self._echo: self._log_info(statement) - self._log_info("%r", parameters) + self._log_info("[raw sql] %r", parameters) try: for fn in ( () diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 221d49db9a..484cdddc88 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -41,6 +41,7 @@ from . import visitors from .base import _bind_or_error from .base import DedupeColumnCollection from .base import DialectKWArgs +from .base import Executable from .base import SchemaEventTarget from .coercions import _document_text_coercion from .elements import ClauseElement @@ -2464,7 +2465,7 @@ class ForeignKey(DialectKWArgs, SchemaItem): self._set_target_column(_column) -class DefaultGenerator(SchemaItem): +class DefaultGenerator(Executable, SchemaItem): """Base class for column *default* values.""" __visit_name__ = "default_generator" @@ -2678,7 +2679,7 @@ class IdentityOptions(object): self.order = order -class Sequence(IdentityOptions, roles.StatementRole, DefaultGenerator): +class Sequence(IdentityOptions, DefaultGenerator): """Represents a named database sequence. The :class:`.Sequence` object represents the name and configurational diff --git a/test/orm/test_session.py b/test/orm/test_session.py index 421e6320b2..e4010c635f 100644 --- a/test/orm/test_session.py +++ b/test/orm/test_session.py @@ -48,15 +48,25 @@ class ExecutionTest(_fixtures.FixtureTest): run_inserts = None __backend__ = True + @testing.combinations( + (True,), (False,), argnames="add_do_orm_execute_event" + ) @testing.requires.sequences - def test_sequence_execute(self, connection): - seq = Sequence("some_sequence") - seq.create(connection) - try: - sess = Session(connection) - eq_(sess.execute(seq), connection.dialect.default_sequence_base) - finally: - seq.drop(connection) + def test_sequence_execute( + self, connection, metadata, add_do_orm_execute_event + ): + seq = Sequence("some_sequence", metadata=metadata) + metadata.create_all(connection) + sess = Session(connection) + + if add_do_orm_execute_event: + evt = mock.Mock(return_value=None) + event.listen( + sess, "do_orm_execute", lambda ctx: evt(ctx.statement) + ) + eq_(sess.execute(seq), connection.dialect.default_sequence_base) + if add_do_orm_execute_event: + eq_(evt.mock_calls, [mock.call(seq)]) def test_parameter_execute(self): users = self.tables.users -- 2.47.2