This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
# engine/base.py
|
||||
# Copyright (C) 2005-2025 the SQLAlchemy authors and contributors
|
||||
# Copyright (C) 2005-2023 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: https://www.opensource.org/licenses/mit-license.php
|
||||
"""Defines :class:`_engine.Connection` and :class:`_engine.Engine`."""
|
||||
"""Defines :class:`_engine.Connection` and :class:`_engine.Engine`.
|
||||
|
||||
"""
|
||||
from __future__ import annotations
|
||||
|
||||
import contextlib
|
||||
@@ -68,11 +70,12 @@ if typing.TYPE_CHECKING:
|
||||
from ..sql._typing import _InfoType
|
||||
from ..sql.compiler import Compiled
|
||||
from ..sql.ddl import ExecutableDDLElement
|
||||
from ..sql.ddl import InvokeDDLBase
|
||||
from ..sql.ddl import SchemaDropper
|
||||
from ..sql.ddl import SchemaGenerator
|
||||
from ..sql.functions import FunctionElement
|
||||
from ..sql.schema import DefaultGenerator
|
||||
from ..sql.schema import HasSchemaAttr
|
||||
from ..sql.schema import SchemaVisitable
|
||||
from ..sql.schema import SchemaItem
|
||||
from ..sql.selectable import TypedReturnsRows
|
||||
|
||||
|
||||
@@ -106,7 +109,6 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
"""
|
||||
|
||||
dialect: Dialect
|
||||
dispatch: dispatcher[ConnectionEventsTarget]
|
||||
|
||||
_sqla_logger_namespace = "sqlalchemy.engine.Connection"
|
||||
@@ -171,9 +173,13 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
if self._has_events or self.engine._has_events:
|
||||
self.dispatch.engine_connect(self)
|
||||
|
||||
# this can be assigned differently via
|
||||
# characteristics.LoggingTokenCharacteristic
|
||||
_message_formatter: Any = None
|
||||
@util.memoized_property
|
||||
def _message_formatter(self) -> Any:
|
||||
if "logging_token" in self._execution_options:
|
||||
token = self._execution_options["logging_token"]
|
||||
return lambda msg: "[%s] %s" % (token, msg)
|
||||
else:
|
||||
return None
|
||||
|
||||
def _log_info(self, message: str, *arg: Any, **kw: Any) -> None:
|
||||
fmt = self._message_formatter
|
||||
@@ -199,9 +205,9 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
@property
|
||||
def _schema_translate_map(self) -> Optional[SchemaTranslateMapType]:
|
||||
schema_translate_map: Optional[SchemaTranslateMapType] = (
|
||||
self._execution_options.get("schema_translate_map", None)
|
||||
)
|
||||
schema_translate_map: Optional[
|
||||
SchemaTranslateMapType
|
||||
] = self._execution_options.get("schema_translate_map", None)
|
||||
|
||||
return schema_translate_map
|
||||
|
||||
@@ -212,9 +218,9 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
"""
|
||||
|
||||
name = obj.schema
|
||||
schema_translate_map: Optional[SchemaTranslateMapType] = (
|
||||
self._execution_options.get("schema_translate_map", None)
|
||||
)
|
||||
schema_translate_map: Optional[
|
||||
SchemaTranslateMapType
|
||||
] = self._execution_options.get("schema_translate_map", None)
|
||||
|
||||
if (
|
||||
schema_translate_map
|
||||
@@ -244,12 +250,13 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
yield_per: int = ...,
|
||||
insertmanyvalues_page_size: int = ...,
|
||||
schema_translate_map: Optional[SchemaTranslateMapType] = ...,
|
||||
preserve_rowcount: bool = False,
|
||||
**opt: Any,
|
||||
) -> Connection: ...
|
||||
) -> Connection:
|
||||
...
|
||||
|
||||
@overload
|
||||
def execution_options(self, **opt: Any) -> Connection: ...
|
||||
def execution_options(self, **opt: Any) -> Connection:
|
||||
...
|
||||
|
||||
def execution_options(self, **opt: Any) -> Connection:
|
||||
r"""Set non-SQL options for the connection which take effect
|
||||
@@ -375,11 +382,12 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
:param stream_results: Available on: :class:`_engine.Connection`,
|
||||
:class:`_sql.Executable`.
|
||||
|
||||
Indicate to the dialect that results should be "streamed" and not
|
||||
pre-buffered, if possible. For backends such as PostgreSQL, MySQL
|
||||
and MariaDB, this indicates the use of a "server side cursor" as
|
||||
opposed to a client side cursor. Other backends such as that of
|
||||
Oracle Database may already use server side cursors by default.
|
||||
Indicate to the dialect that results should be
|
||||
"streamed" and not pre-buffered, if possible. For backends
|
||||
such as PostgreSQL, MySQL and MariaDB, this indicates the use of
|
||||
a "server side cursor" as opposed to a client side cursor.
|
||||
Other backends such as that of Oracle may already use server
|
||||
side cursors by default.
|
||||
|
||||
The usage of
|
||||
:paramref:`_engine.Connection.execution_options.stream_results` is
|
||||
@@ -484,18 +492,6 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
:ref:`schema_translating`
|
||||
|
||||
:param preserve_rowcount: Boolean; when True, the ``cursor.rowcount``
|
||||
attribute will be unconditionally memoized within the result and
|
||||
made available via the :attr:`.CursorResult.rowcount` attribute.
|
||||
Normally, this attribute is only preserved for UPDATE and DELETE
|
||||
statements. Using this option, the DBAPIs rowcount value can
|
||||
be accessed for other kinds of statements such as INSERT and SELECT,
|
||||
to the degree that the DBAPI supports these statements. See
|
||||
:attr:`.CursorResult.rowcount` for notes regarding the behavior
|
||||
of this attribute.
|
||||
|
||||
.. versionadded:: 2.0.28
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`_engine.Engine.execution_options`
|
||||
@@ -797,6 +793,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
with conn.begin() as trans:
|
||||
conn.execute(table.insert(), {"username": "sandy"})
|
||||
|
||||
|
||||
The returned object is an instance of :class:`_engine.RootTransaction`.
|
||||
This object represents the "scope" of the transaction,
|
||||
which completes when either the :meth:`_engine.Transaction.rollback`
|
||||
@@ -902,7 +899,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
trans.rollback() # rollback to savepoint
|
||||
|
||||
# outer transaction continues
|
||||
connection.execute(...)
|
||||
connection.execute( ... )
|
||||
|
||||
If :meth:`_engine.Connection.begin_nested` is called without first
|
||||
calling :meth:`_engine.Connection.begin` or
|
||||
@@ -912,11 +909,11 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
with engine.connect() as connection: # begin() wasn't called
|
||||
|
||||
with connection.begin_nested(): # will auto-"begin()" first
|
||||
connection.execute(...)
|
||||
with connection.begin_nested(): will auto-"begin()" first
|
||||
connection.execute( ... )
|
||||
# savepoint is released
|
||||
|
||||
connection.execute(...)
|
||||
connection.execute( ... )
|
||||
|
||||
# explicitly commit outer transaction
|
||||
connection.commit()
|
||||
@@ -1112,16 +1109,10 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
if self._still_open_and_dbapi_connection_is_valid:
|
||||
if self._echo:
|
||||
if self._is_autocommit_isolation():
|
||||
if self.dialect.skip_autocommit_rollback:
|
||||
self._log_info(
|
||||
"ROLLBACK will be skipped by "
|
||||
"skip_autocommit_rollback"
|
||||
)
|
||||
else:
|
||||
self._log_info(
|
||||
"ROLLBACK using DBAPI connection.rollback(); "
|
||||
"set skip_autocommit_rollback to prevent fully"
|
||||
)
|
||||
self._log_info(
|
||||
"ROLLBACK using DBAPI connection.rollback(), "
|
||||
"DBAPI should ignore due to autocommit mode"
|
||||
)
|
||||
else:
|
||||
self._log_info("ROLLBACK")
|
||||
try:
|
||||
@@ -1137,7 +1128,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
if self._is_autocommit_isolation():
|
||||
self._log_info(
|
||||
"COMMIT using DBAPI connection.commit(), "
|
||||
"has no effect due to autocommit mode"
|
||||
"DBAPI should ignore due to autocommit mode"
|
||||
)
|
||||
else:
|
||||
self._log_info("COMMIT")
|
||||
@@ -1271,7 +1262,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreSingleExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> Optional[_T]: ...
|
||||
) -> Optional[_T]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def scalar(
|
||||
@@ -1280,7 +1272,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreSingleExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> Any: ...
|
||||
) -> Any:
|
||||
...
|
||||
|
||||
def scalar(
|
||||
self,
|
||||
@@ -1318,7 +1311,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreAnyExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> ScalarResult[_T]: ...
|
||||
) -> ScalarResult[_T]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def scalars(
|
||||
@@ -1327,7 +1321,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreAnyExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> ScalarResult[Any]: ...
|
||||
) -> ScalarResult[Any]:
|
||||
...
|
||||
|
||||
def scalars(
|
||||
self,
|
||||
@@ -1361,7 +1356,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreAnyExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> CursorResult[_T]: ...
|
||||
) -> CursorResult[_T]:
|
||||
...
|
||||
|
||||
@overload
|
||||
def execute(
|
||||
@@ -1370,7 +1366,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
parameters: Optional[_CoreAnyExecuteParams] = None,
|
||||
*,
|
||||
execution_options: Optional[CoreExecuteOptionsParameter] = None,
|
||||
) -> CursorResult[Any]: ...
|
||||
) -> CursorResult[Any]:
|
||||
...
|
||||
|
||||
def execute(
|
||||
self,
|
||||
@@ -1501,7 +1498,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
) -> CursorResult[Any]:
|
||||
"""Execute a schema.DDL object."""
|
||||
|
||||
exec_opts = ddl._execution_options.merge_with(
|
||||
execution_options = ddl._execution_options.merge_with(
|
||||
self._execution_options, execution_options
|
||||
)
|
||||
|
||||
@@ -1515,11 +1512,12 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
event_multiparams,
|
||||
event_params,
|
||||
) = self._invoke_before_exec_event(
|
||||
ddl, distilled_parameters, exec_opts
|
||||
ddl, distilled_parameters, execution_options
|
||||
)
|
||||
else:
|
||||
event_multiparams = event_params = None
|
||||
|
||||
exec_opts = self._execution_options.merge_with(execution_options)
|
||||
schema_translate_map = exec_opts.get("schema_translate_map", None)
|
||||
|
||||
dialect = self.dialect
|
||||
@@ -1532,7 +1530,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
dialect.execution_ctx_cls._init_ddl,
|
||||
compiled,
|
||||
None,
|
||||
exec_opts,
|
||||
execution_options,
|
||||
compiled,
|
||||
)
|
||||
if self._has_events or self.engine._has_events:
|
||||
@@ -1541,7 +1539,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
ddl,
|
||||
event_multiparams,
|
||||
event_params,
|
||||
exec_opts,
|
||||
execution_options,
|
||||
ret,
|
||||
)
|
||||
return ret
|
||||
@@ -1739,20 +1737,21 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
conn.exec_driver_sql(
|
||||
"INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
|
||||
[{"id": 1, "value": "v1"}, {"id": 2, "value": "v2"}],
|
||||
[{"id":1, "value":"v1"}, {"id":2, "value":"v2"}]
|
||||
)
|
||||
|
||||
Single dictionary::
|
||||
|
||||
conn.exec_driver_sql(
|
||||
"INSERT INTO table (id, value) VALUES (%(id)s, %(value)s)",
|
||||
dict(id=1, value="v1"),
|
||||
dict(id=1, value="v1")
|
||||
)
|
||||
|
||||
Single tuple::
|
||||
|
||||
conn.exec_driver_sql(
|
||||
"INSERT INTO table (id, value) VALUES (?, ?)", (1, "v1")
|
||||
"INSERT INTO table (id, value) VALUES (?, ?)",
|
||||
(1, 'v1')
|
||||
)
|
||||
|
||||
.. note:: The :meth:`_engine.Connection.exec_driver_sql` method does
|
||||
@@ -1841,7 +1840,10 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
context.pre_exec()
|
||||
|
||||
if context.execute_style is ExecuteStyle.INSERTMANYVALUES:
|
||||
return self._exec_insertmany_context(dialect, context)
|
||||
return self._exec_insertmany_context(
|
||||
dialect,
|
||||
context,
|
||||
)
|
||||
else:
|
||||
return self._exec_single_context(
|
||||
dialect, context, statement, parameters
|
||||
@@ -2016,22 +2018,16 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
engine_events = self._has_events or self.engine._has_events
|
||||
if self.dialect._has_events:
|
||||
do_execute_dispatch: Iterable[Any] = (
|
||||
self.dialect.dispatch.do_execute
|
||||
)
|
||||
do_execute_dispatch: Iterable[
|
||||
Any
|
||||
] = self.dialect.dispatch.do_execute
|
||||
else:
|
||||
do_execute_dispatch = ()
|
||||
|
||||
if self._echo:
|
||||
stats = context._get_cache_stats() + " (insertmanyvalues)"
|
||||
|
||||
preserve_rowcount = context.execution_options.get(
|
||||
"preserve_rowcount", False
|
||||
)
|
||||
rowcount = 0
|
||||
|
||||
for imv_batch in dialect._deliver_insertmanyvalues_batches(
|
||||
self,
|
||||
cursor,
|
||||
str_statement,
|
||||
effective_parameters,
|
||||
@@ -2052,7 +2048,6 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
imv_batch.replaced_parameters,
|
||||
None,
|
||||
context,
|
||||
is_sub_exec=True,
|
||||
)
|
||||
|
||||
sub_stmt = imv_batch.replaced_statement
|
||||
@@ -2072,16 +2067,15 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
if self._echo:
|
||||
self._log_info(sql_util._long_statement(sub_stmt))
|
||||
|
||||
imv_stats = f""" {imv_batch.batchnum}/{
|
||||
imv_batch.total_batches
|
||||
} ({
|
||||
'ordered'
|
||||
if imv_batch.rows_sorted else 'unordered'
|
||||
}{
|
||||
'; batch not supported'
|
||||
if imv_batch.is_downgraded
|
||||
else ''
|
||||
})"""
|
||||
imv_stats = f""" {
|
||||
imv_batch.batchnum}/{imv_batch.total_batches} ({
|
||||
'ordered'
|
||||
if imv_batch.rows_sorted else 'unordered'
|
||||
}{
|
||||
'; batch not supported'
|
||||
if imv_batch.is_downgraded
|
||||
else ''
|
||||
})"""
|
||||
|
||||
if imv_batch.batchnum == 1:
|
||||
stats += imv_stats
|
||||
@@ -2142,15 +2136,9 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
context.executemany,
|
||||
)
|
||||
|
||||
if preserve_rowcount:
|
||||
rowcount += imv_batch.current_batch_size
|
||||
|
||||
try:
|
||||
context.post_exec()
|
||||
|
||||
if preserve_rowcount:
|
||||
context._rowcount = rowcount # type: ignore[attr-defined]
|
||||
|
||||
result = context._setup_result_proxy()
|
||||
|
||||
except BaseException as e:
|
||||
@@ -2392,9 +2380,9 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
None,
|
||||
cast(Exception, e),
|
||||
dialect.loaded_dbapi.Error,
|
||||
hide_parameters=(
|
||||
engine.hide_parameters if engine is not None else False
|
||||
),
|
||||
hide_parameters=engine.hide_parameters
|
||||
if engine is not None
|
||||
else False,
|
||||
connection_invalidated=is_disconnect,
|
||||
dialect=dialect,
|
||||
)
|
||||
@@ -2431,7 +2419,9 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
break
|
||||
|
||||
if sqlalchemy_exception and is_disconnect != ctx.is_disconnect:
|
||||
sqlalchemy_exception.connection_invalidated = ctx.is_disconnect
|
||||
sqlalchemy_exception.connection_invalidated = (
|
||||
is_disconnect
|
||||
) = ctx.is_disconnect
|
||||
|
||||
if newraise:
|
||||
raise newraise.with_traceback(exc_info[2]) from e
|
||||
@@ -2444,8 +2434,8 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
|
||||
def _run_ddl_visitor(
|
||||
self,
|
||||
visitorcallable: Type[InvokeDDLBase],
|
||||
element: SchemaVisitable,
|
||||
visitorcallable: Type[Union[SchemaGenerator, SchemaDropper]],
|
||||
element: SchemaItem,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
"""run a DDL visitor.
|
||||
@@ -2454,9 +2444,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
|
||||
options given to the visitor so that "checkfirst" is skipped.
|
||||
|
||||
"""
|
||||
visitorcallable(
|
||||
dialect=self.dialect, connection=self, **kwargs
|
||||
).traverse_single(element)
|
||||
visitorcallable(self.dialect, self, **kwargs).traverse_single(element)
|
||||
|
||||
|
||||
class ExceptionContextImpl(ExceptionContext):
|
||||
@@ -2514,7 +2502,6 @@ class Transaction(TransactionalContext):
|
||||
:class:`_engine.Connection`::
|
||||
|
||||
from sqlalchemy import create_engine
|
||||
|
||||
engine = create_engine("postgresql+psycopg2://scott:tiger@localhost/test")
|
||||
connection = engine.connect()
|
||||
trans = connection.begin()
|
||||
@@ -3003,7 +2990,7 @@ class Engine(
|
||||
This applies **only** to the built-in cache that is established
|
||||
via the :paramref:`_engine.create_engine.query_cache_size` parameter.
|
||||
It will not impact any dictionary caches that were passed via the
|
||||
:paramref:`.Connection.execution_options.compiled_cache` parameter.
|
||||
:paramref:`.Connection.execution_options.query_cache` parameter.
|
||||
|
||||
.. versionadded:: 1.4
|
||||
|
||||
@@ -3042,10 +3029,12 @@ class Engine(
|
||||
insertmanyvalues_page_size: int = ...,
|
||||
schema_translate_map: Optional[SchemaTranslateMapType] = ...,
|
||||
**opt: Any,
|
||||
) -> OptionEngine: ...
|
||||
) -> OptionEngine:
|
||||
...
|
||||
|
||||
@overload
|
||||
def execution_options(self, **opt: Any) -> OptionEngine: ...
|
||||
def execution_options(self, **opt: Any) -> OptionEngine:
|
||||
...
|
||||
|
||||
def execution_options(self, **opt: Any) -> OptionEngine:
|
||||
"""Return a new :class:`_engine.Engine` that will provide
|
||||
@@ -3092,10 +3081,10 @@ class Engine(
|
||||
|
||||
shards = {"default": "base", "shard_1": "db1", "shard_2": "db2"}
|
||||
|
||||
|
||||
@event.listens_for(Engine, "before_cursor_execute")
|
||||
def _switch_shard(conn, cursor, stmt, params, context, executemany):
|
||||
shard_id = conn.get_execution_options().get("shard_id", "default")
|
||||
def _switch_shard(conn, cursor, stmt,
|
||||
params, context, executemany):
|
||||
shard_id = conn.get_execution_options().get('shard_id', "default")
|
||||
current_shard = conn.info.get("current_shard", None)
|
||||
|
||||
if current_shard != shard_id:
|
||||
@@ -3221,7 +3210,9 @@ class Engine(
|
||||
E.g.::
|
||||
|
||||
with engine.begin() as conn:
|
||||
conn.execute(text("insert into table (x, y, z) values (1, 2, 3)"))
|
||||
conn.execute(
|
||||
text("insert into table (x, y, z) values (1, 2, 3)")
|
||||
)
|
||||
conn.execute(text("my_special_procedure(5)"))
|
||||
|
||||
Upon successful operation, the :class:`.Transaction`
|
||||
@@ -3237,15 +3228,15 @@ class Engine(
|
||||
:meth:`_engine.Connection.begin` - start a :class:`.Transaction`
|
||||
for a particular :class:`_engine.Connection`.
|
||||
|
||||
""" # noqa: E501
|
||||
"""
|
||||
with self.connect() as conn:
|
||||
with conn.begin():
|
||||
yield conn
|
||||
|
||||
def _run_ddl_visitor(
|
||||
self,
|
||||
visitorcallable: Type[InvokeDDLBase],
|
||||
element: SchemaVisitable,
|
||||
visitorcallable: Type[Union[SchemaGenerator, SchemaDropper]],
|
||||
element: SchemaItem,
|
||||
**kwargs: Any,
|
||||
) -> None:
|
||||
with self.begin() as conn:
|
||||
|
||||
Reference in New Issue
Block a user