summaryrefslogtreecommitdiff
path: root/lib/sqlalchemy/engine
diff options
context:
space:
mode:
Diffstat (limited to 'lib/sqlalchemy/engine')
-rw-r--r--lib/sqlalchemy/engine/__init__.py5
-rw-r--r--lib/sqlalchemy/engine/base.py3
-rw-r--r--lib/sqlalchemy/engine/cursor.py136
-rw-r--r--lib/sqlalchemy/engine/default.py109
-rw-r--r--lib/sqlalchemy/engine/interfaces.py22
-rw-r--r--lib/sqlalchemy/engine/result.py1
6 files changed, 148 insertions, 128 deletions
diff --git a/lib/sqlalchemy/engine/__init__.py b/lib/sqlalchemy/engine/__init__.py
index 32f3f2ecc..29dd6aff9 100644
--- a/lib/sqlalchemy/engine/__init__.py
+++ b/lib/sqlalchemy/engine/__init__.py
@@ -25,12 +25,7 @@ from .base import Transaction as Transaction
from .base import TwoPhaseTransaction as TwoPhaseTransaction
from .create import create_engine as create_engine
from .create import engine_from_config as engine_from_config
-from .cursor import BaseCursorResult as BaseCursorResult
-from .cursor import BufferedColumnResultProxy as BufferedColumnResultProxy
-from .cursor import BufferedColumnRow as BufferedColumnRow
-from .cursor import BufferedRowResultProxy as BufferedRowResultProxy
from .cursor import CursorResult as CursorResult
-from .cursor import FullyBufferedResultProxy as FullyBufferedResultProxy
from .cursor import ResultProxy as ResultProxy
from .interfaces import AdaptedConnection as AdaptedConnection
from .interfaces import BindTyping as BindTyping
diff --git a/lib/sqlalchemy/engine/base.py b/lib/sqlalchemy/engine/base.py
index 37faa880e..d8009e26c 100644
--- a/lib/sqlalchemy/engine/base.py
+++ b/lib/sqlalchemy/engine/base.py
@@ -23,6 +23,7 @@ from typing import Tuple
from typing import Type
from typing import Union
+from .interfaces import _IsolationLevel
from .interfaces import BindTyping
from .interfaces import ConnectionEventsTarget
from .interfaces import DBAPICursor
@@ -510,7 +511,7 @@ class Connection(ConnectionEventsTarget, inspection.Inspectable["Inspector"]):
self._handle_dbapi_exception(e, None, None, None, None)
@property
- def default_isolation_level(self) -> str:
+ def default_isolation_level(self) -> Optional[_IsolationLevel]:
"""The default isolation level assigned to this
:class:`_engine.Connection`.
diff --git a/lib/sqlalchemy/engine/cursor.py b/lib/sqlalchemy/engine/cursor.py
index 78805bac1..821c0cb8e 100644
--- a/lib/sqlalchemy/engine/cursor.py
+++ b/lib/sqlalchemy/engine/cursor.py
@@ -23,8 +23,9 @@ from typing import List
from typing import Optional
from typing import Sequence
from typing import Tuple
-from typing import Type
+from typing import Union
+from .result import MergedResult
from .result import Result
from .result import ResultMetaData
from .result import SimpleResultMetaData
@@ -36,10 +37,12 @@ from ..sql import elements
from ..sql import sqltypes
from ..sql import util as sql_util
from ..sql.base import _generative
+from ..sql.compiler import ResultColumnsEntry
from ..sql.compiler import RM_NAME
from ..sql.compiler import RM_OBJECTS
from ..sql.compiler import RM_RENDERED_NAME
from ..sql.compiler import RM_TYPE
+from ..sql.type_api import TypeEngine
from ..util import compat
from ..util.typing import Literal
@@ -101,6 +104,7 @@ class CursorResultMetaData(ResultMetaData):
_keymap_by_result_column_idx: Optional[Dict[int, _KeyMapRecType]]
_unpickled: bool
_safe_for_cache: bool
+ _translated_indexes: Optional[List[int]]
returns_rows: ClassVar[bool] = True
@@ -123,7 +127,6 @@ class CursorResultMetaData(ResultMetaData):
if self._translated_indexes:
indexes = [self._translated_indexes[idx] for idx in indexes]
-
tup = tuplegetter(*indexes)
new_metadata = self.__class__.__new__(self.__class__)
@@ -526,7 +529,7 @@ class CursorResultMetaData(ResultMetaData):
def _merge_textual_cols_by_position(
self, context, cursor_description, result_columns
):
- num_ctx_cols = len(result_columns) if result_columns else None
+ num_ctx_cols = len(result_columns)
if num_ctx_cols > len(cursor_description):
util.warn(
@@ -568,6 +571,8 @@ class CursorResultMetaData(ResultMetaData):
match_map = self._create_description_match_map(
result_columns, loose_column_name_matching
)
+ mapped_type: TypeEngine[Any]
+
for (
idx,
colname,
@@ -597,15 +602,17 @@ class CursorResultMetaData(ResultMetaData):
@classmethod
def _create_description_match_map(
cls,
- result_columns,
- loose_column_name_matching=False,
- ):
+ result_columns: List[ResultColumnsEntry],
+ loose_column_name_matching: bool = False,
+ ) -> Dict[Union[str, object], Tuple[str, List[Any], TypeEngine[Any], int]]:
"""when matching cursor.description to a set of names that are present
in a Compiled object, as is the case with TextualSelect, get all the
names we expect might match those in cursor.description.
"""
- d = {}
+ d: Dict[
+ Union[str, object], Tuple[str, List[Any], TypeEngine[Any], int]
+ ] = {}
for ridx, elem in enumerate(result_columns):
key = elem[RM_RENDERED_NAME]
@@ -630,7 +637,6 @@ class CursorResultMetaData(ResultMetaData):
r_key,
(elem[RM_NAME], elem[RM_OBJECTS], elem[RM_TYPE], ridx),
)
-
return d
def _merge_cols_by_none(self, context, cursor_description):
@@ -739,7 +745,9 @@ class CursorResultMetaData(ResultMetaData):
self._keys = state["_keys"]
self._unpickled = True
if state["_translated_indexes"]:
- self._translated_indexes = state["_translated_indexes"]
+ self._translated_indexes = cast(
+ "List[int]", state["_translated_indexes"]
+ )
self._tuplefilter = tuplegetter(*self._translated_indexes)
else:
self._translated_indexes = self._tuplefilter = None
@@ -1144,12 +1152,32 @@ class _NoResultMetaData(ResultMetaData):
_NO_RESULT_METADATA = _NoResultMetaData()
-class BaseCursorResult:
- """Base class for database result objects."""
+class CursorResult(Result):
+ """A Result that is representing state from a DBAPI cursor.
+
+ .. versionchanged:: 1.4 The :class:`.CursorResult``
+ class replaces the previous :class:`.ResultProxy` interface.
+ This classes are based on the :class:`.Result` calling API
+ which provides an updated usage model and calling facade for
+ SQLAlchemy Core and SQLAlchemy ORM.
+
+ Returns database rows via the :class:`.Row` class, which provides
+ additional API features and behaviors on top of the raw data returned by
+ the DBAPI. Through the use of filters such as the :meth:`.Result.scalars`
+ method, other kinds of objects may also be returned.
+
+ .. seealso::
+
+ :ref:`coretutorial_selecting` - introductory material for accessing
+ :class:`_engine.CursorResult` and :class:`.Row` objects.
- _metadata: ResultMetaData
+ """
+
+ _metadata: Union[CursorResultMetaData, _NoResultMetaData]
+ _no_result_metadata = _NO_RESULT_METADATA
_soft_closed: bool = False
closed: bool = False
+ _is_cursor = True
def __init__(self, context, cursor_strategy, cursor_description):
self.context = context
@@ -1169,11 +1197,11 @@ class BaseCursorResult:
if echo:
log = self.context.connection._log_debug
- def log_row(row):
+ def _log_row(row):
log("Row %r", sql_util._repr_row(row))
return row
- self._row_logging_fn = log_row
+ self._row_logging_fn = log_row = _log_row
else:
log_row = None
@@ -1188,13 +1216,16 @@ class BaseCursorResult:
)
if log_row:
- def make_row(row):
+ def _make_row_2(row):
made_row = _make_row(row)
+ assert log_row is not None
log_row(made_row)
return made_row
+ make_row = _make_row_2
else:
make_row = _make_row
+
self._set_memoized_attribute("_row_getter", make_row)
else:
@@ -1208,7 +1239,7 @@ class BaseCursorResult:
if compiled._cached_metadata:
metadata = compiled._cached_metadata
else:
- metadata = self._cursor_metadata(self, cursor_description)
+ metadata = CursorResultMetaData(self, cursor_description)
if metadata._safe_for_cache:
compiled._cached_metadata = metadata
@@ -1239,7 +1270,7 @@ class BaseCursorResult:
self._metadata = metadata
else:
- self._metadata = metadata = self._cursor_metadata(
+ self._metadata = metadata = CursorResultMetaData(
self, cursor_description
)
if self._echo:
@@ -1669,33 +1700,6 @@ class BaseCursorResult:
"""
return self.context.isinsert
-
-class CursorResult(BaseCursorResult, Result):
- """A Result that is representing state from a DBAPI cursor.
-
- .. versionchanged:: 1.4 The :class:`.CursorResult``
- class replaces the previous :class:`.ResultProxy` interface.
- This classes are based on the :class:`.Result` calling API
- which provides an updated usage model and calling facade for
- SQLAlchemy Core and SQLAlchemy ORM.
-
- Returns database rows via the :class:`.Row` class, which provides
- additional API features and behaviors on top of the raw data returned by
- the DBAPI. Through the use of filters such as the :meth:`.Result.scalars`
- method, other kinds of objects may also be returned.
-
- .. seealso::
-
- :ref:`coretutorial_selecting` - introductory material for accessing
- :class:`_engine.CursorResult` and :class:`.Row` objects.
-
- """
-
- _cursor_metadata: Type[ResultMetaData] = CursorResultMetaData
- _cursor_strategy_cls = CursorFetchStrategy
- _no_result_metadata = _NO_RESULT_METADATA
- _is_cursor = True
-
def _fetchiter_impl(self):
fetchone = self.cursor_strategy.fetchone
@@ -1717,12 +1721,13 @@ class CursorResult(BaseCursorResult, Result):
def _raw_row_iterator(self):
return self._fetchiter_impl()
- def merge(self, *others):
- merged_result = super(CursorResult, self).merge(*others)
+ def merge(self, *others: Result) -> MergedResult:
+ merged_result = super().merge(*others)
setup_rowcounts = not self._metadata.returns_rows
if setup_rowcounts:
merged_result.rowcount = sum(
- result.rowcount for result in (self,) + others
+ cast(CursorResult, result).rowcount
+ for result in (self,) + others
)
return merged_result
@@ -1756,40 +1761,3 @@ class CursorResult(BaseCursorResult, Result):
ResultProxy = CursorResult
-
-
-class BufferedRowResultProxy(ResultProxy):
- """A ResultProxy with row buffering behavior.
-
- .. deprecated:: 1.4 this class is now supplied using a strategy object.
- See :class:`.BufferedRowCursorFetchStrategy`.
-
- """
-
- _cursor_strategy_cls: Type[
- CursorFetchStrategy
- ] = BufferedRowCursorFetchStrategy
-
-
-class FullyBufferedResultProxy(ResultProxy):
- """A result proxy that buffers rows fully upon creation.
-
- .. deprecated:: 1.4 this class is now supplied using a strategy object.
- See :class:`.FullyBufferedCursorFetchStrategy`.
-
- """
-
- _cursor_strategy_cls = FullyBufferedCursorFetchStrategy
-
-
-class BufferedColumnRow(Row):
- """Row is now BufferedColumn in all cases"""
-
-
-class BufferedColumnResultProxy(ResultProxy):
- """A ResultProxy with column buffering behavior.
-
- .. versionchanged:: 1.4 This is now the default behavior of the Row
- and this class does not change behavior in any way.
-
- """
diff --git a/lib/sqlalchemy/engine/default.py b/lib/sqlalchemy/engine/default.py
index 0e0c76389..2579f573c 100644
--- a/lib/sqlalchemy/engine/default.py
+++ b/lib/sqlalchemy/engine/default.py
@@ -55,6 +55,9 @@ from ..sql.compiler import SQLCompiler
from ..sql.elements import quoted_name
if typing.TYPE_CHECKING:
+ from .base import Connection
+ from .base import Engine
+ from .characteristics import ConnectionCharacteristic
from .interfaces import _AnyMultiExecuteParams
from .interfaces import _CoreMultiExecuteParams
from .interfaces import _CoreSingleExecuteParams
@@ -62,6 +65,7 @@ if typing.TYPE_CHECKING:
from .interfaces import _DBAPIMultiExecuteParams
from .interfaces import _DBAPISingleExecuteParams
from .interfaces import _ExecuteOptions
+ from .interfaces import _MutableCoreSingleExecuteParams
from .result import _ProcessorType
from .row import Row
from .url import URL
@@ -71,6 +75,7 @@ if typing.TYPE_CHECKING:
from ..sql import Executable
from ..sql.compiler import Compiled
from ..sql.compiler import ResultColumnsEntry
+ from ..sql.compiler import TypeCompiler
from ..sql.schema import Column
from ..sql.type_api import TypeEngine
@@ -92,7 +97,11 @@ class DefaultDialect(Dialect):
statement_compiler = compiler.SQLCompiler
ddl_compiler = compiler.DDLCompiler
- type_compiler = compiler.GenericTypeCompiler # type: ignore
+ if typing.TYPE_CHECKING:
+ type_compiler: TypeCompiler
+ else:
+ type_compiler = compiler.GenericTypeCompiler
+
preparer = compiler.IdentifierPreparer
supports_alter = True
supports_comments = False
@@ -202,7 +211,7 @@ class DefaultDialect(Dialect):
server_version_info = None
- default_schema_name = None
+ default_schema_name: Optional[str] = None
# indicates symbol names are
# UPPERCASEd if they are case insensitive
@@ -290,7 +299,12 @@ class DefaultDialect(Dialect):
self.positional = self.paramstyle in ("qmark", "format", "numeric")
self.identifier_preparer = self.preparer(self)
self._on_connect_isolation_level = isolation_level
- self.type_compiler = self.type_compiler(self)
+
+ tt_callable = cast(
+ Type[compiler.GenericTypeCompiler],
+ self.type_compiler,
+ )
+ self.type_compiler = tt_callable(self)
if supports_native_boolean is not None:
self.supports_native_boolean = supports_native_boolean
@@ -490,12 +504,14 @@ class DefaultDialect(Dialect):
opts.update(url.query)
return [[], opts]
- def set_engine_execution_options(self, engine, opts):
+ def set_engine_execution_options(
+ self, engine: Engine, opts: Mapping[str, str]
+ ) -> None:
supported_names = set(self.connection_characteristics).intersection(
opts
)
if supported_names:
- characteristics = util.immutabledict(
+ characteristics: Mapping[str, str] = util.immutabledict(
(name, opts[name]) for name in supported_names
)
@@ -505,12 +521,14 @@ class DefaultDialect(Dialect):
connection, characteristics
)
- def set_connection_execution_options(self, connection, opts):
+ def set_connection_execution_options(
+ self, connection: Connection, opts: Mapping[str, str]
+ ) -> None:
supported_names = set(self.connection_characteristics).intersection(
opts
)
if supported_names:
- characteristics = util.immutabledict(
+ characteristics: Mapping[str, str] = util.immutabledict(
(name, opts[name]) for name in supported_names
)
self._set_connection_characteristics(connection, characteristics)
@@ -800,7 +818,7 @@ class DefaultExecutionContext(ExecutionContext):
dialect: Dialect
unicode_statement: str
cursor: DBAPICursor
- compiled_parameters: _CoreMultiExecuteParams
+ compiled_parameters: List[_MutableCoreSingleExecuteParams]
parameters: _DBAPIMultiExecuteParams
extracted_parameters: _CoreSingleExecuteParams
@@ -1157,7 +1175,11 @@ class DefaultExecutionContext(ExecutionContext):
parameters = {}
conn._cursor_execute(self.cursor, stmt, parameters, context=self)
- r = self.cursor.fetchone()[0]
+ row = self.cursor.fetchone()
+ if row is not None:
+ r = row[0]
+ else:
+ r = None
if type_ is not None:
# apply type post processors to the result
proc = type_._cached_result_processor(
@@ -1299,10 +1321,11 @@ class DefaultExecutionContext(ExecutionContext):
result = _cursor.CursorResult(self, strategy, cursor_description)
+ compiled = self.compiled
if (
- self.compiled
+ compiled
and not self.isddl
- and self.compiled.has_out_parameters
+ and cast(SQLCompiler, compiled).has_out_parameters
):
self._setup_out_parameters(result)
@@ -1311,10 +1334,11 @@ class DefaultExecutionContext(ExecutionContext):
return result
def _setup_out_parameters(self, result):
+ compiled = cast(SQLCompiler, self.compiled)
out_bindparams = [
(param, name)
- for param, name in self.compiled.bind_names.items()
+ for param, name in compiled.bind_names.items()
if param.isoutparam
]
out_parameters = {}
@@ -1339,9 +1363,10 @@ class DefaultExecutionContext(ExecutionContext):
result.out_parameters = out_parameters
def _setup_dml_or_text_result(self):
+ compiled = cast(SQLCompiler, self.compiled)
if self.isinsert:
- if self.compiled.postfetch_lastrowid:
+ if compiled.postfetch_lastrowid:
self.inserted_primary_key_rows = (
self._setup_ins_pk_from_lastrowid()
)
@@ -1397,7 +1422,8 @@ class DefaultExecutionContext(ExecutionContext):
result.rowcount
row = result.fetchone()
- self.returned_default_rows = [row]
+ if row is not None:
+ self.returned_default_rows = [row]
result._soft_close()
@@ -1420,13 +1446,17 @@ class DefaultExecutionContext(ExecutionContext):
return self._setup_ins_pk_from_empty()
def _setup_ins_pk_from_lastrowid(self):
- getter = self.compiled._inserted_primary_key_from_lastrowid_getter
+ getter = cast(
+ SQLCompiler, self.compiled
+ )._inserted_primary_key_from_lastrowid_getter
lastrowid = self.get_lastrowid()
return [getter(lastrowid, self.compiled_parameters[0])]
def _setup_ins_pk_from_empty(self):
- getter = self.compiled._inserted_primary_key_from_lastrowid_getter
+ getter = cast(
+ SQLCompiler, self.compiled
+ )._inserted_primary_key_from_lastrowid_getter
return [getter(None, param) for param in self.compiled_parameters]
def _setup_ins_pk_from_implicit_returning(self, result, rows):
@@ -1434,7 +1464,9 @@ class DefaultExecutionContext(ExecutionContext):
if not rows:
return []
- getter = self.compiled._inserted_primary_key_from_returning_getter
+ getter = cast(
+ SQLCompiler, self.compiled
+ )._inserted_primary_key_from_returning_getter
compiled_params = self.compiled_parameters
return [
@@ -1443,7 +1475,7 @@ class DefaultExecutionContext(ExecutionContext):
def lastrow_has_defaults(self):
return (self.isinsert or self.isupdate) and bool(
- self.compiled.postfetch
+ cast(SQLCompiler, self.compiled).postfetch
)
def _set_input_sizes(self):
@@ -1464,7 +1496,7 @@ class DefaultExecutionContext(ExecutionContext):
if self.isddl or self.is_text:
return
- compiled = self.compiled
+ compiled = cast(SQLCompiler, self.compiled)
inputsizes = compiled._get_set_input_sizes_lookup()
@@ -1487,7 +1519,8 @@ class DefaultExecutionContext(ExecutionContext):
if dialect.positional:
items = [
- (key, compiled.binds[key]) for key in compiled.positiontup
+ (key, compiled.binds[key])
+ for key in compiled.positiontup or ()
]
else:
items = [
@@ -1495,7 +1528,7 @@ class DefaultExecutionContext(ExecutionContext):
for bindparam, key in compiled.bind_names.items()
]
- generic_inputsizes = []
+ generic_inputsizes: List[Tuple[str, Any, TypeEngine[Any]]] = []
for key, bindparam in items:
if bindparam in compiled.literal_execute_params:
continue
@@ -1578,20 +1611,19 @@ class DefaultExecutionContext(ExecutionContext):
compiled_params = compiled.construct_params()
processors = compiled._bind_processors
if compiled.positional:
- positiontup = compiled.positiontup
parameters = self.dialect.execute_sequence_format(
[
- processors[key](compiled_params[key])
+ processors[key](compiled_params[key]) # type: ignore
if key in processors
else compiled_params[key]
- for key in positiontup
+ for key in compiled.positiontup or ()
]
)
else:
parameters = dict(
(
key,
- processors[key](compiled_params[key])
+ processors[key](compiled_params[key]) # type: ignore
if key in processors
else compiled_params[key],
)
@@ -1667,15 +1699,18 @@ class DefaultExecutionContext(ExecutionContext):
"get_current_parameters() can only be invoked in the "
"context of a Python side column default function"
)
-
- compile_state = self.compiled.compile_state
+ else:
+ assert column is not None
+ assert parameters is not None
+ compile_state = cast(SQLCompiler, self.compiled).compile_state
+ assert compile_state is not None
if (
isolate_multiinsert_groups
and self.isinsert
and compile_state._has_multi_parameters
):
if column._is_multiparam_column:
- index = column.index + 1
+ index = column.index + 1 # type: ignore
d = {column.original.key: parameters[column.key]}
else:
d = {column.key: parameters[column.key]}
@@ -1701,12 +1736,14 @@ class DefaultExecutionContext(ExecutionContext):
return self._exec_default(column, column.onupdate, column.type)
def _process_executemany_defaults(self):
- key_getter = self.compiled._within_exec_param_key_getter
+ compiled = cast(SQLCompiler, self.compiled)
- scalar_defaults = {}
+ key_getter = compiled._within_exec_param_key_getter
- insert_prefetch = self.compiled.insert_prefetch
- update_prefetch = self.compiled.update_prefetch
+ scalar_defaults: Dict[Column[Any], Any] = {}
+
+ insert_prefetch = compiled.insert_prefetch
+ update_prefetch = compiled.update_prefetch
# pre-determine scalar Python-side defaults
# to avoid many calls of get_insert_default()/
@@ -1739,12 +1776,14 @@ class DefaultExecutionContext(ExecutionContext):
del self.current_parameters
def _process_executesingle_defaults(self):
- key_getter = self.compiled._within_exec_param_key_getter
+ compiled = cast(SQLCompiler, self.compiled)
+
+ key_getter = compiled._within_exec_param_key_getter
self.current_parameters = (
compiled_parameters
) = self.compiled_parameters[0]
- for c in self.compiled.insert_prefetch:
+ for c in compiled.insert_prefetch:
if c.default and not c.default.is_sequence and c.default.is_scalar:
val = c.default.arg
else:
@@ -1753,7 +1792,7 @@ class DefaultExecutionContext(ExecutionContext):
if val is not None:
compiled_parameters[key_getter(c)] = val
- for c in self.compiled.update_prefetch:
+ for c in compiled.update_prefetch:
val = self.get_update_default(c)
if val is not None:
diff --git a/lib/sqlalchemy/engine/interfaces.py b/lib/sqlalchemy/engine/interfaces.py
index 5aefcf5b5..e65546eb7 100644
--- a/lib/sqlalchemy/engine/interfaces.py
+++ b/lib/sqlalchemy/engine/interfaces.py
@@ -36,7 +36,6 @@ from ..sql.compiler import TypeCompiler as TypeCompiler
from ..sql.compiler import TypeCompiler # noqa
from ..util import immutabledict
from ..util.concurrency import await_only
-from ..util.typing import _TypeToInstance
from ..util.typing import Literal
from ..util.typing import NotRequired
from ..util.typing import Protocol
@@ -58,6 +57,8 @@ if TYPE_CHECKING:
from ..sql.elements import ClauseElement
from ..sql.schema import Column
from ..sql.schema import ColumnDefault
+ from ..sql.schema import Sequence as Sequence_SchemaItem
+ from ..sql.sqltypes import Integer
from ..sql.type_api import TypeEngine
ConnectArgsType = Tuple[Tuple[str], MutableMapping[str, Any]]
@@ -156,6 +157,8 @@ class DBAPICursor(Protocol):
arraysize: int
+ lastrowid: int
+
def close(self) -> None:
...
@@ -196,6 +199,7 @@ class DBAPICursor(Protocol):
_CoreSingleExecuteParams = Mapping[str, Any]
+_MutableCoreSingleExecuteParams = MutableMapping[str, Any]
_CoreMultiExecuteParams = Sequence[_CoreSingleExecuteParams]
_CoreAnyExecuteParams = Union[
_CoreMultiExecuteParams, _CoreSingleExecuteParams
@@ -605,7 +609,7 @@ class Dialect(EventTarget):
ddl_compiler: Type[DDLCompiler]
"""a :class:`.Compiled` class used to compile DDL statements"""
- type_compiler: _TypeToInstance[TypeCompiler]
+ type_compiler: Union[Type[TypeCompiler], TypeCompiler]
"""a :class:`.Compiled` class used to compile SQL type objects"""
preparer: Type[IdentifierPreparer]
@@ -633,7 +637,7 @@ class Dialect(EventTarget):
"""
- default_isolation_level: _IsolationLevel
+ default_isolation_level: Optional[_IsolationLevel]
"""the isolation that is implicitly present on new connections"""
execution_ctx_cls: Type["ExecutionContext"]
@@ -653,6 +657,13 @@ class Dialect(EventTarget):
max_identifier_length: int
"""The maximum length of identifier names."""
+ supports_server_side_cursors: bool
+ """indicates if the dialect supports server side cursors"""
+
+ server_side_cursors: bool
+ """deprecated; indicates if the dialect should attempt to use server
+ side cursors by default"""
+
supports_sane_rowcount: bool
"""Indicate whether the dialect properly implements rowcount for
``UPDATE`` and ``DELETE`` statements.
@@ -2302,6 +2313,11 @@ class ExecutionContext:
def _setup_result_proxy(self) -> Result:
raise NotImplementedError()
+ def fire_sequence(self, seq: Sequence_SchemaItem, type_: Integer) -> int:
+ """given a :class:`.Sequence`, invoke it and return the next int
+ value"""
+ raise NotImplementedError()
+
def create_cursor(self) -> DBAPICursor:
"""Return a new cursor generated from this ExecutionContext's
connection.
diff --git a/lib/sqlalchemy/engine/result.py b/lib/sqlalchemy/engine/result.py
index 0951d5770..87d3cac1c 100644
--- a/lib/sqlalchemy/engine/result.py
+++ b/lib/sqlalchemy/engine/result.py
@@ -1880,6 +1880,7 @@ class MergedResult(IteratorResult):
"""
closed = False
+ rowcount: Optional[int]
def __init__(
self, cursor_metadata: ResultMetaData, results: Sequence[Result]