SQLAlchemy 2.1.0rc1__cp315-cp315-win_arm64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (276) hide show
  1. sqlalchemy/__init__.py +299 -0
  2. sqlalchemy/connectors/__init__.py +18 -0
  3. sqlalchemy/connectors/aioodbc.py +171 -0
  4. sqlalchemy/connectors/asyncio.py +476 -0
  5. sqlalchemy/connectors/pyodbc.py +248 -0
  6. sqlalchemy/dialects/__init__.py +62 -0
  7. sqlalchemy/dialects/_typing.py +29 -0
  8. sqlalchemy/dialects/mssql/__init__.py +88 -0
  9. sqlalchemy/dialects/mssql/aioodbc.py +63 -0
  10. sqlalchemy/dialects/mssql/base.py +4833 -0
  11. sqlalchemy/dialects/mssql/information_schema.py +345 -0
  12. sqlalchemy/dialects/mssql/json.py +140 -0
  13. sqlalchemy/dialects/mssql/mssqlpython.py +242 -0
  14. sqlalchemy/dialects/mssql/provision.py +196 -0
  15. sqlalchemy/dialects/mssql/pymssql.py +130 -0
  16. sqlalchemy/dialects/mssql/pyodbc.py +697 -0
  17. sqlalchemy/dialects/mysql/__init__.py +106 -0
  18. sqlalchemy/dialects/mysql/_mariadb_shim.py +312 -0
  19. sqlalchemy/dialects/mysql/aiomysql.py +260 -0
  20. sqlalchemy/dialects/mysql/asyncmy.py +241 -0
  21. sqlalchemy/dialects/mysql/base.py +3896 -0
  22. sqlalchemy/dialects/mysql/cymysql.py +107 -0
  23. sqlalchemy/dialects/mysql/dml.py +279 -0
  24. sqlalchemy/dialects/mysql/enumerated.py +277 -0
  25. sqlalchemy/dialects/mysql/expression.py +146 -0
  26. sqlalchemy/dialects/mysql/json.py +92 -0
  27. sqlalchemy/dialects/mysql/mariadb.py +67 -0
  28. sqlalchemy/dialects/mysql/mariadbconnector.py +314 -0
  29. sqlalchemy/dialects/mysql/mysqlconnector.py +291 -0
  30. sqlalchemy/dialects/mysql/mysqldb.py +318 -0
  31. sqlalchemy/dialects/mysql/provision.py +153 -0
  32. sqlalchemy/dialects/mysql/pymysql.py +188 -0
  33. sqlalchemy/dialects/mysql/pyodbc.py +157 -0
  34. sqlalchemy/dialects/mysql/reflection.py +724 -0
  35. sqlalchemy/dialects/mysql/reserved_words.py +570 -0
  36. sqlalchemy/dialects/mysql/types.py +845 -0
  37. sqlalchemy/dialects/oracle/__init__.py +85 -0
  38. sqlalchemy/dialects/oracle/base.py +3847 -0
  39. sqlalchemy/dialects/oracle/cx_oracle.py +1736 -0
  40. sqlalchemy/dialects/oracle/dictionary.py +507 -0
  41. sqlalchemy/dialects/oracle/json.py +157 -0
  42. sqlalchemy/dialects/oracle/oracledb.py +898 -0
  43. sqlalchemy/dialects/oracle/provision.py +288 -0
  44. sqlalchemy/dialects/oracle/types.py +367 -0
  45. sqlalchemy/dialects/oracle/vector.py +366 -0
  46. sqlalchemy/dialects/postgresql/__init__.py +170 -0
  47. sqlalchemy/dialects/postgresql/_psycopg_common.py +232 -0
  48. sqlalchemy/dialects/postgresql/array.py +534 -0
  49. sqlalchemy/dialects/postgresql/asyncpg.py +1318 -0
  50. sqlalchemy/dialects/postgresql/base.py +5935 -0
  51. sqlalchemy/dialects/postgresql/bitstring.py +327 -0
  52. sqlalchemy/dialects/postgresql/dml.py +360 -0
  53. sqlalchemy/dialects/postgresql/ext.py +599 -0
  54. sqlalchemy/dialects/postgresql/hstore.py +422 -0
  55. sqlalchemy/dialects/postgresql/json.py +411 -0
  56. sqlalchemy/dialects/postgresql/named_types.py +535 -0
  57. sqlalchemy/dialects/postgresql/operators.py +129 -0
  58. sqlalchemy/dialects/postgresql/pg8000.py +655 -0
  59. sqlalchemy/dialects/postgresql/pg_catalog.py +345 -0
  60. sqlalchemy/dialects/postgresql/provision.py +202 -0
  61. sqlalchemy/dialects/postgresql/psycopg.py +800 -0
  62. sqlalchemy/dialects/postgresql/psycopg2.py +860 -0
  63. sqlalchemy/dialects/postgresql/psycopg2cffi.py +62 -0
  64. sqlalchemy/dialects/postgresql/ranges.py +1002 -0
  65. sqlalchemy/dialects/postgresql/types.py +388 -0
  66. sqlalchemy/dialects/sqlite/__init__.py +59 -0
  67. sqlalchemy/dialects/sqlite/aiosqlite.py +375 -0
  68. sqlalchemy/dialects/sqlite/base.py +3103 -0
  69. sqlalchemy/dialects/sqlite/dml.py +314 -0
  70. sqlalchemy/dialects/sqlite/json.py +134 -0
  71. sqlalchemy/dialects/sqlite/provision.py +237 -0
  72. sqlalchemy/dialects/sqlite/pysqlcipher.py +166 -0
  73. sqlalchemy/dialects/sqlite/pysqlite.py +959 -0
  74. sqlalchemy/dialects/type_migration_guidelines.txt +145 -0
  75. sqlalchemy/engine/__init__.py +62 -0
  76. sqlalchemy/engine/_processors_cy.cp315-win_arm64.pyd +0 -0
  77. sqlalchemy/engine/_processors_cy.py +92 -0
  78. sqlalchemy/engine/_result_cy.cp315-win_arm64.pyd +0 -0
  79. sqlalchemy/engine/_result_cy.py +711 -0
  80. sqlalchemy/engine/_row_cy.cp315-win_arm64.pyd +0 -0
  81. sqlalchemy/engine/_row_cy.py +232 -0
  82. sqlalchemy/engine/_util_cy.cp315-win_arm64.pyd +0 -0
  83. sqlalchemy/engine/_util_cy.py +136 -0
  84. sqlalchemy/engine/base.py +3357 -0
  85. sqlalchemy/engine/characteristics.py +155 -0
  86. sqlalchemy/engine/create.py +877 -0
  87. sqlalchemy/engine/cursor.py +2425 -0
  88. sqlalchemy/engine/default.py +2627 -0
  89. sqlalchemy/engine/events.py +965 -0
  90. sqlalchemy/engine/interfaces.py +3636 -0
  91. sqlalchemy/engine/mock.py +133 -0
  92. sqlalchemy/engine/processors.py +83 -0
  93. sqlalchemy/engine/reflection.py +2141 -0
  94. sqlalchemy/engine/result.py +2012 -0
  95. sqlalchemy/engine/row.py +397 -0
  96. sqlalchemy/engine/strategies.py +16 -0
  97. sqlalchemy/engine/url.py +922 -0
  98. sqlalchemy/engine/util.py +164 -0
  99. sqlalchemy/event/__init__.py +26 -0
  100. sqlalchemy/event/api.py +220 -0
  101. sqlalchemy/event/attr.py +675 -0
  102. sqlalchemy/event/base.py +473 -0
  103. sqlalchemy/event/legacy.py +259 -0
  104. sqlalchemy/event/registry.py +391 -0
  105. sqlalchemy/events.py +17 -0
  106. sqlalchemy/exc.py +939 -0
  107. sqlalchemy/ext/__init__.py +10 -0
  108. sqlalchemy/ext/associationproxy.py +2073 -0
  109. sqlalchemy/ext/asyncio/__init__.py +29 -0
  110. sqlalchemy/ext/asyncio/base.py +281 -0
  111. sqlalchemy/ext/asyncio/engine.py +1487 -0
  112. sqlalchemy/ext/asyncio/exc.py +21 -0
  113. sqlalchemy/ext/asyncio/result.py +994 -0
  114. sqlalchemy/ext/asyncio/scoping.py +1679 -0
  115. sqlalchemy/ext/asyncio/session.py +2006 -0
  116. sqlalchemy/ext/automap.py +1702 -0
  117. sqlalchemy/ext/baked.py +558 -0
  118. sqlalchemy/ext/compiler.py +601 -0
  119. sqlalchemy/ext/declarative/__init__.py +65 -0
  120. sqlalchemy/ext/declarative/extensions.py +561 -0
  121. sqlalchemy/ext/horizontal_shard.py +481 -0
  122. sqlalchemy/ext/hybrid.py +1877 -0
  123. sqlalchemy/ext/indexable.py +364 -0
  124. sqlalchemy/ext/instrumentation.py +450 -0
  125. sqlalchemy/ext/mutable.py +1081 -0
  126. sqlalchemy/ext/orderinglist.py +440 -0
  127. sqlalchemy/ext/serializer.py +184 -0
  128. sqlalchemy/future/__init__.py +17 -0
  129. sqlalchemy/future/engine.py +15 -0
  130. sqlalchemy/inspection.py +188 -0
  131. sqlalchemy/log.py +279 -0
  132. sqlalchemy/orm/__init__.py +176 -0
  133. sqlalchemy/orm/_orm_constructors.py +2694 -0
  134. sqlalchemy/orm/_typing.py +180 -0
  135. sqlalchemy/orm/attributes.py +2868 -0
  136. sqlalchemy/orm/base.py +991 -0
  137. sqlalchemy/orm/bulk_persistence.py +2168 -0
  138. sqlalchemy/orm/clsregistry.py +630 -0
  139. sqlalchemy/orm/collections.py +1569 -0
  140. sqlalchemy/orm/context.py +3475 -0
  141. sqlalchemy/orm/decl_api.py +2283 -0
  142. sqlalchemy/orm/decl_base.py +2320 -0
  143. sqlalchemy/orm/dependency.py +1306 -0
  144. sqlalchemy/orm/descriptor_props.py +1183 -0
  145. sqlalchemy/orm/dynamic.py +306 -0
  146. sqlalchemy/orm/evaluator.py +378 -0
  147. sqlalchemy/orm/events.py +3387 -0
  148. sqlalchemy/orm/exc.py +237 -0
  149. sqlalchemy/orm/identity.py +302 -0
  150. sqlalchemy/orm/instrumentation.py +749 -0
  151. sqlalchemy/orm/interfaces.py +1595 -0
  152. sqlalchemy/orm/loading.py +1712 -0
  153. sqlalchemy/orm/mapped_collection.py +557 -0
  154. sqlalchemy/orm/mapper.py +4465 -0
  155. sqlalchemy/orm/path_registry.py +907 -0
  156. sqlalchemy/orm/persistence.py +1790 -0
  157. sqlalchemy/orm/properties.py +972 -0
  158. sqlalchemy/orm/query.py +3528 -0
  159. sqlalchemy/orm/relationships.py +3608 -0
  160. sqlalchemy/orm/scoping.py +2233 -0
  161. sqlalchemy/orm/session.py +5468 -0
  162. sqlalchemy/orm/state.py +1175 -0
  163. sqlalchemy/orm/state_changes.py +196 -0
  164. sqlalchemy/orm/strategies.py +3552 -0
  165. sqlalchemy/orm/strategy_options.py +2648 -0
  166. sqlalchemy/orm/sync.py +164 -0
  167. sqlalchemy/orm/unitofwork.py +797 -0
  168. sqlalchemy/orm/util.py +2461 -0
  169. sqlalchemy/orm/writeonly.py +701 -0
  170. sqlalchemy/pool/__init__.py +41 -0
  171. sqlalchemy/pool/base.py +1540 -0
  172. sqlalchemy/pool/events.py +375 -0
  173. sqlalchemy/pool/impl.py +583 -0
  174. sqlalchemy/py.typed +0 -0
  175. sqlalchemy/schema.py +75 -0
  176. sqlalchemy/sql/__init__.py +156 -0
  177. sqlalchemy/sql/_annotated_cols.py +402 -0
  178. sqlalchemy/sql/_cache_key_cy.cp315-win_arm64.pyd +0 -0
  179. sqlalchemy/sql/_cache_key_cy.py +363 -0
  180. sqlalchemy/sql/_dml_constructors.py +132 -0
  181. sqlalchemy/sql/_elements_constructors.py +2190 -0
  182. sqlalchemy/sql/_orm_types.py +19 -0
  183. sqlalchemy/sql/_selectable_constructors.py +840 -0
  184. sqlalchemy/sql/_typing.py +500 -0
  185. sqlalchemy/sql/_util_cy.cp315-win_arm64.pyd +0 -0
  186. sqlalchemy/sql/_util_cy.pxd +11 -0
  187. sqlalchemy/sql/_util_cy.py +127 -0
  188. sqlalchemy/sql/annotation.py +590 -0
  189. sqlalchemy/sql/base.py +2702 -0
  190. sqlalchemy/sql/cache_key.py +915 -0
  191. sqlalchemy/sql/coercions.py +1373 -0
  192. sqlalchemy/sql/compiler.py +8453 -0
  193. sqlalchemy/sql/crud.py +1816 -0
  194. sqlalchemy/sql/ddl.py +1962 -0
  195. sqlalchemy/sql/default_comparator.py +660 -0
  196. sqlalchemy/sql/dml.py +2018 -0
  197. sqlalchemy/sql/elements.py +6057 -0
  198. sqlalchemy/sql/events.py +458 -0
  199. sqlalchemy/sql/expression.py +171 -0
  200. sqlalchemy/sql/functions.py +2380 -0
  201. sqlalchemy/sql/lambdas.py +1442 -0
  202. sqlalchemy/sql/naming.py +204 -0
  203. sqlalchemy/sql/operators.py +2909 -0
  204. sqlalchemy/sql/roles.py +332 -0
  205. sqlalchemy/sql/schema.py +7075 -0
  206. sqlalchemy/sql/selectable.py +7634 -0
  207. sqlalchemy/sql/sqltypes.py +4130 -0
  208. sqlalchemy/sql/traversals.py +1041 -0
  209. sqlalchemy/sql/type_api.py +2450 -0
  210. sqlalchemy/sql/util.py +1496 -0
  211. sqlalchemy/sql/visitors.py +1153 -0
  212. sqlalchemy/testing/__init__.py +97 -0
  213. sqlalchemy/testing/assertions.py +1007 -0
  214. sqlalchemy/testing/assertsql.py +519 -0
  215. sqlalchemy/testing/asyncio.py +128 -0
  216. sqlalchemy/testing/cancellation.py +237 -0
  217. sqlalchemy/testing/config.py +440 -0
  218. sqlalchemy/testing/engines.py +482 -0
  219. sqlalchemy/testing/entities.py +117 -0
  220. sqlalchemy/testing/exclusions.py +501 -0
  221. sqlalchemy/testing/fixtures/__init__.py +30 -0
  222. sqlalchemy/testing/fixtures/base.py +426 -0
  223. sqlalchemy/testing/fixtures/mypy.py +247 -0
  224. sqlalchemy/testing/fixtures/orm.py +227 -0
  225. sqlalchemy/testing/fixtures/sql.py +538 -0
  226. sqlalchemy/testing/pickleable.py +155 -0
  227. sqlalchemy/testing/plugin/__init__.py +6 -0
  228. sqlalchemy/testing/plugin/bootstrap.py +50 -0
  229. sqlalchemy/testing/plugin/plugin_base.py +828 -0
  230. sqlalchemy/testing/plugin/pytestplugin.py +896 -0
  231. sqlalchemy/testing/profiles_file.py +350 -0
  232. sqlalchemy/testing/profiling.py +294 -0
  233. sqlalchemy/testing/provision.py +633 -0
  234. sqlalchemy/testing/requirements.py +1971 -0
  235. sqlalchemy/testing/schema.py +198 -0
  236. sqlalchemy/testing/suite/__init__.py +19 -0
  237. sqlalchemy/testing/suite/test_cte.py +237 -0
  238. sqlalchemy/testing/suite/test_ddl.py +420 -0
  239. sqlalchemy/testing/suite/test_dialect.py +776 -0
  240. sqlalchemy/testing/suite/test_insert.py +630 -0
  241. sqlalchemy/testing/suite/test_reflection.py +3815 -0
  242. sqlalchemy/testing/suite/test_results.py +660 -0
  243. sqlalchemy/testing/suite/test_rowcount.py +258 -0
  244. sqlalchemy/testing/suite/test_select.py +2112 -0
  245. sqlalchemy/testing/suite/test_sequence.py +317 -0
  246. sqlalchemy/testing/suite/test_table_via_select.py +686 -0
  247. sqlalchemy/testing/suite/test_types.py +2271 -0
  248. sqlalchemy/testing/suite/test_unicode_ddl.py +189 -0
  249. sqlalchemy/testing/suite/test_update_delete.py +139 -0
  250. sqlalchemy/testing/util.py +575 -0
  251. sqlalchemy/testing/warnings.py +52 -0
  252. sqlalchemy/types.py +75 -0
  253. sqlalchemy/util/__init__.py +165 -0
  254. sqlalchemy/util/_collections.py +688 -0
  255. sqlalchemy/util/_collections_cy.cp315-win_arm64.pyd +0 -0
  256. sqlalchemy/util/_collections_cy.pxd +8 -0
  257. sqlalchemy/util/_collections_cy.py +516 -0
  258. sqlalchemy/util/_has_cython.py +48 -0
  259. sqlalchemy/util/_immutabledict_cy.cp315-win_arm64.pyd +0 -0
  260. sqlalchemy/util/_immutabledict_cy.py +240 -0
  261. sqlalchemy/util/compat.py +298 -0
  262. sqlalchemy/util/concurrency.py +272 -0
  263. sqlalchemy/util/cython.py +95 -0
  264. sqlalchemy/util/deprecations.py +401 -0
  265. sqlalchemy/util/langhelpers.py +2797 -0
  266. sqlalchemy/util/preloaded.py +153 -0
  267. sqlalchemy/util/queue.py +304 -0
  268. sqlalchemy/util/tool_support.py +202 -0
  269. sqlalchemy/util/topological.py +120 -0
  270. sqlalchemy/util/typing.py +709 -0
  271. sqlalchemy-2.1.0rc1.dist-info/METADATA +270 -0
  272. sqlalchemy-2.1.0rc1.dist-info/RECORD +276 -0
  273. sqlalchemy-2.1.0rc1.dist-info/WHEEL +5 -0
  274. sqlalchemy-2.1.0rc1.dist-info/licenses/AUTHORS +30 -0
  275. sqlalchemy-2.1.0rc1.dist-info/licenses/LICENSE +19 -0
  276. sqlalchemy-2.1.0rc1.dist-info/top_level.txt +1 -0
@@ -0,0 +1,2627 @@
1
+ # engine/default.py
2
+ # Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3
+ # <see AUTHORS file>
4
+ #
5
+ # This module is part of SQLAlchemy and is released under
6
+ # the MIT License: https://www.opensource.org/licenses/mit-license.php
7
+ # mypy: allow-untyped-defs, allow-untyped-calls
8
+
9
+ """Default implementations of per-dialect sqlalchemy.engine classes.
10
+
11
+ These are semi-private implementation classes which are only of importance
12
+ to database dialect authors; dialects will usually use the classes here
13
+ as the base class for their own corresponding classes.
14
+
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ import functools
20
+ import operator
21
+ import random
22
+ import re
23
+ from time import perf_counter
24
+ import typing
25
+ from typing import Any
26
+ from typing import Callable
27
+ from typing import cast
28
+ from typing import Dict
29
+ from typing import Final
30
+ from typing import Iterable
31
+ from typing import List
32
+ from typing import Literal
33
+ from typing import Mapping
34
+ from typing import MutableMapping
35
+ from typing import MutableSequence
36
+ from typing import Optional
37
+ from typing import Sequence
38
+ from typing import Set
39
+ from typing import Tuple
40
+ from typing import Type
41
+ from typing import TYPE_CHECKING
42
+ from typing import Union
43
+ import weakref
44
+
45
+ from . import characteristics
46
+ from . import cursor as _cursor
47
+ from . import interfaces
48
+ from . import reflection
49
+ from .base import Connection
50
+ from .interfaces import CacheStats
51
+ from .interfaces import DBAPICursor
52
+ from .interfaces import Dialect
53
+ from .interfaces import ExecuteStyle
54
+ from .interfaces import ExecutionContext
55
+ from .reflection import ObjectKind
56
+ from .reflection import ObjectScope
57
+ from .. import event
58
+ from .. import exc
59
+ from .. import pool
60
+ from .. import util
61
+ from ..sql import compiler
62
+ from ..sql import dml
63
+ from ..sql import expression
64
+ from ..sql import type_api
65
+ from ..sql import util as sql_util
66
+ from ..sql._typing import is_tuple_type
67
+ from ..sql.base import _NoArg
68
+ from ..sql.compiler import AggregateOrderByStyle
69
+ from ..sql.compiler import DDLCompiler
70
+ from ..sql.compiler import InsertmanyvaluesSentinelOpts
71
+ from ..sql.compiler import SQLCompiler
72
+ from ..sql.elements import quoted_name
73
+ from ..util.typing import TupleAny
74
+ from ..util.typing import Unpack
75
+
76
+ if typing.TYPE_CHECKING:
77
+ from .base import Engine
78
+ from .cursor import ResultFetchStrategy
79
+ from .interfaces import _CoreMultiExecuteParams
80
+ from .interfaces import _CoreSingleExecuteParams
81
+ from .interfaces import _DBAPICursorDescription
82
+ from .interfaces import _DBAPIMultiExecuteParams
83
+ from .interfaces import _DBAPISingleExecuteParams
84
+ from .interfaces import _ExecuteOptions
85
+ from .interfaces import _MutableCoreSingleExecuteParams
86
+ from .interfaces import _ParamStyle
87
+ from .interfaces import ConnectArgsType
88
+ from .interfaces import DBAPIConnection
89
+ from .interfaces import DBAPIModule
90
+ from .interfaces import DBAPIType
91
+ from .interfaces import IsolationLevel
92
+ from .interfaces import TableKey
93
+ from .row import Row
94
+ from .url import URL
95
+ from ..event import _ListenerFnType
96
+ from ..pool import Pool
97
+ from ..pool import PoolProxiedConnection
98
+ from ..sql import Executable
99
+ from ..sql.compiler import Compiled
100
+ from ..sql.compiler import Linting
101
+ from ..sql.compiler import ResultColumnsEntry
102
+ from ..sql.dml import DMLState
103
+ from ..sql.dml import UpdateBase
104
+ from ..sql.elements import BindParameter
105
+ from ..sql.schema import Column
106
+ from ..sql.sqltypes import _JSON_VALUE
107
+ from ..sql.type_api import _BindProcessorType
108
+ from ..sql.type_api import _ResultProcessorType
109
+ from ..sql.type_api import TypeEngine
110
+
111
+
112
+ # When we're handed literal SQL, ensure it's a SELECT query
113
+ SERVER_SIDE_CURSOR_RE = re.compile(r"\s*SELECT", re.I | re.UNICODE)
114
+
115
+
116
+ (
117
+ CACHE_HIT,
118
+ CACHE_MISS,
119
+ CACHING_DISABLED,
120
+ NO_CACHE_KEY,
121
+ NO_DIALECT_SUPPORT,
122
+ ) = list(CacheStats)
123
+
124
+
125
+ class _BackendsMultiReflection(Dialect):
126
+ """Mixin providing single-table reflection wrappers that delegate to
127
+ the corresponding ``get_multi_*`` methods.
128
+
129
+ Used by dialects that implement native multi-table reflection
130
+ (PostgreSQL, Oracle, MSSQL).
131
+ """
132
+
133
+ @reflection.cache
134
+ def has_table(
135
+ self,
136
+ connection: Connection,
137
+ table_name: str,
138
+ schema: Optional[str] = None,
139
+ **kw: Any,
140
+ ) -> bool:
141
+ # NOTE: assume it's a subclass of DefaultDialect
142
+ self._ensure_has_table_connection(connection) # type: ignore[attr-defined] # noqa: E501
143
+ multi_res = self.has_multi_table(
144
+ connection,
145
+ table_names=[table_name],
146
+ schema=schema,
147
+ **kw,
148
+ )
149
+ # has_multi_table returns all the input table names so it's not
150
+ # possible for the key to be missing
151
+ return dict(multi_res)[(schema, table_name)]
152
+
153
+ def _value_or_raise(self, data, table, schema):
154
+ try:
155
+ return dict(data)[(schema, table)]
156
+ except KeyError:
157
+ raise exc.NoSuchTableError(
158
+ f"{schema}.{table}" if schema else table
159
+ ) from None
160
+
161
+ @reflection.cache
162
+ def get_columns(self, connection, table_name, schema=None, **kw):
163
+ data = self.get_multi_columns(
164
+ connection,
165
+ schema=schema,
166
+ filter_names=[table_name],
167
+ scope=ObjectScope.ANY,
168
+ kind=ObjectKind.ANY,
169
+ **kw,
170
+ )
171
+ return self._value_or_raise(data, table_name, schema)
172
+
173
+ @reflection.cache
174
+ def get_table_options(self, connection, table_name, schema=None, **kw):
175
+ data = self.get_multi_table_options(
176
+ connection,
177
+ schema=schema,
178
+ filter_names=[table_name],
179
+ scope=ObjectScope.ANY,
180
+ kind=ObjectKind.ANY,
181
+ **kw,
182
+ )
183
+ return self._value_or_raise(data, table_name, schema)
184
+
185
+ @reflection.cache
186
+ def get_pk_constraint(self, connection, table_name, schema=None, **kw):
187
+ data = self.get_multi_pk_constraint(
188
+ connection,
189
+ schema=schema,
190
+ filter_names=[table_name],
191
+ scope=ObjectScope.ANY,
192
+ kind=ObjectKind.ANY,
193
+ **kw,
194
+ )
195
+ return self._value_or_raise(data, table_name, schema)
196
+
197
+ @reflection.cache
198
+ def get_foreign_keys(self, connection, table_name, schema=None, **kw):
199
+ data = self.get_multi_foreign_keys(
200
+ connection,
201
+ schema=schema,
202
+ filter_names=[table_name],
203
+ scope=ObjectScope.ANY,
204
+ kind=ObjectKind.ANY,
205
+ **kw,
206
+ )
207
+ return self._value_or_raise(data, table_name, schema)
208
+
209
+ @reflection.cache
210
+ def get_indexes(self, connection, table_name, schema=None, **kw):
211
+ data = self.get_multi_indexes(
212
+ connection,
213
+ schema=schema,
214
+ filter_names=[table_name],
215
+ scope=ObjectScope.ANY,
216
+ kind=ObjectKind.ANY,
217
+ **kw,
218
+ )
219
+ return self._value_or_raise(data, table_name, schema)
220
+
221
+ @reflection.cache
222
+ def get_unique_constraints(
223
+ self, connection, table_name, schema=None, **kw
224
+ ):
225
+ data = self.get_multi_unique_constraints(
226
+ connection,
227
+ schema=schema,
228
+ filter_names=[table_name],
229
+ scope=ObjectScope.ANY,
230
+ kind=ObjectKind.ANY,
231
+ **kw,
232
+ )
233
+ return self._value_or_raise(data, table_name, schema)
234
+
235
+ @reflection.cache
236
+ def get_check_constraints(self, connection, table_name, schema=None, **kw):
237
+ data = self.get_multi_check_constraints(
238
+ connection,
239
+ schema=schema,
240
+ filter_names=[table_name],
241
+ scope=ObjectScope.ANY,
242
+ kind=ObjectKind.ANY,
243
+ **kw,
244
+ )
245
+ return self._value_or_raise(data, table_name, schema)
246
+
247
+ @reflection.cache
248
+ def get_table_comment(self, connection, table_name, schema=None, **kw):
249
+ data = self.get_multi_table_comment(
250
+ connection,
251
+ schema=schema,
252
+ filter_names=[table_name],
253
+ scope=ObjectScope.ANY,
254
+ kind=ObjectKind.ANY,
255
+ **kw,
256
+ )
257
+ return self._value_or_raise(data, table_name, schema)
258
+
259
+
260
+ class DefaultDialect(Dialect):
261
+ """Default implementation of Dialect"""
262
+
263
+ statement_compiler = compiler.SQLCompiler
264
+ ddl_compiler = compiler.DDLCompiler
265
+ type_compiler_cls = compiler.GenericTypeCompiler
266
+
267
+ preparer = compiler.IdentifierPreparer
268
+ supports_alter = True
269
+ supports_comments = False
270
+ supports_constraint_comments = False
271
+ inline_comments = False
272
+ supports_statement_cache = True
273
+
274
+ div_is_floordiv = True
275
+
276
+ bind_typing = interfaces.BindTyping.NONE
277
+
278
+ include_set_input_sizes: Optional[Set[Any]] = None
279
+ exclude_set_input_sizes: Optional[Set[Any]] = None
280
+
281
+ # the first value we'd get for an autoincrement column.
282
+ default_sequence_base = 1
283
+
284
+ # most DBAPIs happy with this for execute().
285
+ # not cx_oracle.
286
+ execute_sequence_format = tuple
287
+
288
+ supports_schemas = True
289
+ supports_views = True
290
+ supports_sequences = False
291
+ sequences_optional = False
292
+ preexecute_autoincrement_sequences = False
293
+ supports_identity_columns = False
294
+ postfetch_lastrowid = True
295
+ favor_returning_over_lastrowid = False
296
+ insert_null_pk_still_autoincrements = False
297
+ update_returning = False
298
+ delete_returning = False
299
+ update_returning_multifrom = False
300
+ delete_returning_multifrom = False
301
+ insert_returning = False
302
+
303
+ aggregate_order_by_style = AggregateOrderByStyle.INLINE
304
+
305
+ cte_follows_insert = False
306
+
307
+ supports_native_enum = False
308
+ supports_native_boolean = False
309
+ supports_native_uuid = False
310
+ returns_native_bytes = False
311
+
312
+ supports_native_json_serialization = False
313
+ supports_native_json_deserialization = False
314
+ dialect_injects_custom_json_deserializer = False
315
+ _json_serializer: Callable[[_JSON_VALUE], str] | None = None
316
+
317
+ _json_deserializer: Callable[[str], _JSON_VALUE] | None = None
318
+
319
+ non_native_boolean_check_constraint = True
320
+
321
+ supports_simple_order_by_label = True
322
+
323
+ tuple_in_values = False
324
+
325
+ connection_characteristics = util.immutabledict(
326
+ {
327
+ "isolation_level": characteristics.IsolationLevelCharacteristic(),
328
+ "logging_token": characteristics.LoggingTokenCharacteristic(),
329
+ }
330
+ )
331
+
332
+ engine_config_types: Mapping[str, Any] = util.immutabledict(
333
+ {
334
+ "pool_timeout": util.asint,
335
+ "echo": util.bool_or_str("debug"),
336
+ "echo_pool": util.bool_or_str("debug"),
337
+ "pool_recycle": util.asint,
338
+ "pool_size": util.asint,
339
+ "max_overflow": util.asint,
340
+ "future": util.asbool,
341
+ }
342
+ )
343
+
344
+ # if the NUMERIC type
345
+ # returns decimal.Decimal.
346
+ # *not* the FLOAT type however.
347
+ supports_native_decimal = False
348
+
349
+ name = "default"
350
+
351
+ # length at which to truncate
352
+ # any identifier.
353
+ max_identifier_length = 9999
354
+ _user_defined_max_identifier_length: Optional[int] = None
355
+
356
+ isolation_level: Optional[str] = None
357
+
358
+ # sub-categories of max_identifier_length.
359
+ # currently these accommodate for MySQL which allows alias names
360
+ # of 255 but DDL names only of 64.
361
+ max_index_name_length: Optional[int] = None
362
+ max_constraint_name_length: Optional[int] = None
363
+
364
+ supports_sane_rowcount = True
365
+ supports_sane_multi_rowcount = True
366
+ colspecs: MutableMapping[Type[TypeEngine[Any]], Type[TypeEngine[Any]]] = {}
367
+ default_paramstyle = "named"
368
+
369
+ supports_default_values = False
370
+ """dialect supports INSERT... DEFAULT VALUES syntax"""
371
+
372
+ supports_default_metavalue = False
373
+ """dialect supports INSERT... VALUES (DEFAULT) syntax"""
374
+
375
+ default_metavalue_token = "DEFAULT"
376
+ """for INSERT... VALUES (DEFAULT) syntax, the token to put in the
377
+ parenthesis."""
378
+
379
+ # not sure if this is a real thing but the compiler will deliver it
380
+ # if this is the only flag enabled.
381
+ supports_empty_insert = True
382
+ """dialect supports INSERT () VALUES ()"""
383
+
384
+ supports_multivalues_insert = False
385
+
386
+ use_insertmanyvalues: bool = False
387
+
388
+ use_insertmanyvalues_wo_returning: bool = False
389
+
390
+ insertmanyvalues_implicit_sentinel: InsertmanyvaluesSentinelOpts = (
391
+ InsertmanyvaluesSentinelOpts.NOT_SUPPORTED
392
+ )
393
+
394
+ insertmanyvalues_page_size: int = 1000
395
+ insertmanyvalues_max_parameters = 32700
396
+
397
+ supports_is_distinct_from = True
398
+
399
+ supports_server_side_cursors = False
400
+
401
+ server_side_cursors = False
402
+
403
+ # extra record-level locking features (#4860)
404
+ supports_for_update_of = False
405
+
406
+ server_version_info = None
407
+
408
+ default_schema_name: Optional[str] = None
409
+
410
+ # indicates symbol names are
411
+ # UPPERCASED if they are case insensitive
412
+ # within the database.
413
+ # if this is True, the methods normalize_name()
414
+ # and denormalize_name() must be provided.
415
+ requires_name_normalize = False
416
+
417
+ is_async = False
418
+
419
+ has_terminate = False
420
+
421
+ # TODO: this is not to be part of 2.0. implement rudimentary binary
422
+ # literals for SQLite, PostgreSQL, MySQL only within
423
+ # _Binary.literal_processor
424
+ _legacy_binary_type_literal_encoding = "utf-8"
425
+
426
+ @util.deprecated_params(
427
+ empty_in_strategy=(
428
+ "1.4",
429
+ "The :paramref:`_sa.create_engine.empty_in_strategy` keyword is "
430
+ "deprecated, and no longer has any effect. All IN expressions "
431
+ "are now rendered using "
432
+ 'the "expanding parameter" strategy which renders a set of bound'
433
+ 'expressions, or an "empty set" SELECT, at statement execution'
434
+ "time.",
435
+ ),
436
+ server_side_cursors=(
437
+ "1.4",
438
+ "The :paramref:`_sa.create_engine.server_side_cursors` parameter "
439
+ "is deprecated and will be removed in a future release. Please "
440
+ "use the "
441
+ ":paramref:`_engine.Connection.execution_options.stream_results` "
442
+ "parameter.",
443
+ ),
444
+ )
445
+ def __init__(
446
+ self,
447
+ paramstyle: Optional[_ParamStyle] = None,
448
+ isolation_level: Optional[IsolationLevel] = None,
449
+ dbapi: Optional[DBAPIModule] = None,
450
+ implicit_returning: Literal[True] = True,
451
+ supports_native_boolean: Optional[bool] = None,
452
+ max_identifier_length: Optional[int] = None,
453
+ label_length: Optional[int] = None,
454
+ insertmanyvalues_page_size: Union[_NoArg, int] = _NoArg.NO_ARG,
455
+ use_insertmanyvalues: Optional[bool] = None,
456
+ # util.deprecated_params decorator cannot render the
457
+ # Linting.NO_LINTING constant
458
+ compiler_linting: Linting = int(compiler.NO_LINTING), # type: ignore[assignment] # noqa: E501
459
+ server_side_cursors: bool = False,
460
+ skip_autocommit_rollback: bool = False,
461
+ **kwargs: Any,
462
+ ):
463
+ if server_side_cursors:
464
+ if not self.supports_server_side_cursors:
465
+ raise exc.ArgumentError(
466
+ "Dialect %s does not support server side cursors" % self
467
+ )
468
+ else:
469
+ self.server_side_cursors = True
470
+
471
+ if getattr(self, "use_setinputsizes", False):
472
+ util.warn_deprecated(
473
+ "The dialect-level use_setinputsizes attribute is "
474
+ "deprecated. Please use "
475
+ "bind_typing = BindTyping.SETINPUTSIZES",
476
+ "2.0",
477
+ )
478
+ self.bind_typing = interfaces.BindTyping.SETINPUTSIZES
479
+
480
+ self.positional = False
481
+ self._ischema = None
482
+
483
+ self.dbapi = dbapi
484
+
485
+ self.skip_autocommit_rollback = skip_autocommit_rollback
486
+
487
+ if paramstyle is not None:
488
+ self.paramstyle = paramstyle
489
+ elif self.dbapi is not None:
490
+ self.paramstyle = self.dbapi.paramstyle
491
+ else:
492
+ self.paramstyle = self.default_paramstyle
493
+ self.positional = self.paramstyle in (
494
+ "qmark",
495
+ "format",
496
+ "numeric",
497
+ "numeric_dollar",
498
+ )
499
+ self.identifier_preparer = self.preparer(self)
500
+ self._on_connect_isolation_level = isolation_level
501
+
502
+ legacy_tt_callable = getattr(self, "type_compiler", None)
503
+ if legacy_tt_callable is not None:
504
+ tt_callable = cast(
505
+ Type[compiler.GenericTypeCompiler],
506
+ self.type_compiler,
507
+ )
508
+ else:
509
+ tt_callable = self.type_compiler_cls
510
+
511
+ self.type_compiler_instance = self.type_compiler = tt_callable(self)
512
+
513
+ if supports_native_boolean is not None:
514
+ self.supports_native_boolean = supports_native_boolean
515
+
516
+ self._user_defined_max_identifier_length = max_identifier_length
517
+ if self._user_defined_max_identifier_length:
518
+ self.max_identifier_length = (
519
+ self._user_defined_max_identifier_length
520
+ )
521
+ self.label_length = label_length
522
+ self.compiler_linting = compiler_linting
523
+
524
+ if use_insertmanyvalues is not None:
525
+ self.use_insertmanyvalues = use_insertmanyvalues
526
+
527
+ if insertmanyvalues_page_size is not _NoArg.NO_ARG:
528
+ self.insertmanyvalues_page_size = insertmanyvalues_page_size
529
+
530
+ self._check_minimum_dbapi_version()
531
+
532
+ @property
533
+ @util.deprecated(
534
+ "2.0",
535
+ "full_returning is deprecated, please use insert_returning, "
536
+ "update_returning, delete_returning",
537
+ )
538
+ def full_returning(self):
539
+ return (
540
+ self.insert_returning
541
+ and self.update_returning
542
+ and self.delete_returning
543
+ )
544
+
545
+ @util.memoized_property
546
+ def insert_executemany_returning(self):
547
+ """Default implementation for insert_executemany_returning, if not
548
+ otherwise overridden by the specific dialect.
549
+
550
+ The default dialect determines "insert_executemany_returning" is
551
+ available if the dialect in use has opted into using the
552
+ "use_insertmanyvalues" feature. If they haven't opted into that, then
553
+ this attribute is False, unless the dialect in question overrides this
554
+ and provides some other implementation (such as the Oracle Database
555
+ dialects).
556
+
557
+ """
558
+ return self.insert_returning and self.use_insertmanyvalues
559
+
560
+ @util.memoized_property
561
+ def insert_executemany_returning_sort_by_parameter_order(self):
562
+ """Default implementation for
563
+ insert_executemany_returning_deterministic_order, if not otherwise
564
+ overridden by the specific dialect.
565
+
566
+ The default dialect determines "insert_executemany_returning" can have
567
+ deterministic order only if the dialect in use has opted into using the
568
+ "use_insertmanyvalues" feature, which implements deterministic ordering
569
+ using client side sentinel columns only by default. The
570
+ "insertmanyvalues" feature also features alternate forms that can
571
+ use server-generated PK values as "sentinels", but those are only
572
+ used if the :attr:`.Dialect.insertmanyvalues_implicit_sentinel`
573
+ bitflag enables those alternate SQL forms, which are disabled
574
+ by default.
575
+
576
+ If the dialect in use hasn't opted into that, then this attribute is
577
+ False, unless the dialect in question overrides this and provides some
578
+ other implementation (such as the Oracle Database dialects).
579
+
580
+ """
581
+ return self.insert_returning and self.use_insertmanyvalues
582
+
583
+ update_executemany_returning = False
584
+ delete_executemany_returning = False
585
+
586
+ @util.memoized_property
587
+ def loaded_dbapi(self) -> DBAPIModule:
588
+ if self.dbapi is None:
589
+ raise exc.NoDBAPILoaded(
590
+ f"Dialect {self} does not have a Python DBAPI established "
591
+ "and cannot be used for actual database interaction"
592
+ )
593
+ return self.dbapi
594
+
595
+ @util.memoized_property
596
+ def dbapi_version(self) -> util.VersionInfo:
597
+ # memoization applies to a successfully determined version only;
598
+ # memoized_property does not cache when the function raises, so a
599
+ # DBAPI which is established after this dialect was constructed is
600
+ # still picked up
601
+ if self.dbapi is None:
602
+ raise exc.NoDBAPILoaded(
603
+ f"Dialect {self.name}+{self.driver} has no DBAPI module "
604
+ "loaded; no DBAPI version is available"
605
+ )
606
+
607
+ try:
608
+ version = self.retrieve_dbapi_version(self.dbapi)
609
+ except NotImplementedError as ne:
610
+ raise NotImplementedError(
611
+ f"Dialect {self.name}+{self.driver} does not implement "
612
+ "retrieve_dbapi_version(); no DBAPI version is available"
613
+ ) from ne
614
+
615
+ if not version:
616
+ # the DBAPI is loaded but publishes no version of its own; as
617
+ # with a DBAPI that isn't loaded, this is not an error on the
618
+ # part of the dialect
619
+ # asyncio dialects have a wrapper object here rather than a
620
+ # module, which has no __name__
621
+ dbapi_name = getattr(self.dbapi, "__name__", self.driver)
622
+ raise exc.NoDBAPILoaded(
623
+ f"Dialect {self.name}+{self.driver} could not determine a "
624
+ f"version for its DBAPI module {dbapi_name!r}"
625
+ )
626
+
627
+ return version
628
+
629
+ @property
630
+ def _dbapi_version_or_none(self) -> Optional[util.VersionInfo]:
631
+ """:attr:`.Dialect.dbapi_version`, or None if it can't be
632
+ determined.
633
+
634
+ For use by dialect startup checks, which run before a DBAPI is
635
+ necessarily present and which must not fail when no version is
636
+ available. Only :class:`.exc.NoDBAPILoaded` is accommodated;
637
+ ``NotImplementedError``, indicating a dialect which does not
638
+ implement :meth:`.Dialect.retrieve_dbapi_version` at all, is a bug
639
+ in that dialect and is allowed to propagate. Deliberately not
640
+ memoized itself; the underlying :attr:`.Dialect.dbapi_version`
641
+ memoizes the success case.
642
+
643
+ """
644
+ try:
645
+ return self.dbapi_version
646
+ except exc.NoDBAPILoaded:
647
+ return None
648
+
649
+ def _check_minimum_dbapi_version(self) -> None:
650
+ """Enforce :attr:`.Dialect.minimum_dbapi_version`, if present.
651
+
652
+ Takes place as the dialect is constructed. No check occurs when
653
+ the version of the DBAPI is not available at all.
654
+
655
+ """
656
+ minimum = self.minimum_dbapi_version
657
+ if minimum is None:
658
+ return
659
+
660
+ version = self._dbapi_version_or_none
661
+ if version is not None and version < minimum:
662
+ dbapi_name = getattr(self.dbapi, "__name__", self.driver)
663
+ raise exc.InvalidRequestError(
664
+ f"Dialect {self.name}+{self.driver} requires version "
665
+ f"{minimum} or greater of the {dbapi_name} DBAPI; "
666
+ f"version {version} is installed"
667
+ )
668
+
669
+ @util.memoized_property
670
+ def _bind_typing_render_casts(self):
671
+ return self.bind_typing is interfaces.BindTyping.RENDER_CASTS
672
+
673
+ def _ensure_has_table_connection(self, arg: Connection) -> None:
674
+ if not isinstance(arg, Connection):
675
+ raise exc.ArgumentError(
676
+ "The argument passed to Dialect.has_table() should be a "
677
+ "%s, got %s. "
678
+ "Additionally, the Dialect.has_table() method is for "
679
+ "internal dialect "
680
+ "use only; please use "
681
+ "``inspect(some_engine).has_table(<tablename>>)`` "
682
+ "for public API use." % (Connection, type(arg))
683
+ )
684
+
685
+ @util.memoized_property
686
+ def _supports_statement_cache(self):
687
+ ssc = self.__class__.__dict__.get("supports_statement_cache", None)
688
+ if ssc is None:
689
+ util.warn(
690
+ "Dialect %s:%s will not make use of SQL compilation caching "
691
+ "as it does not set the 'supports_statement_cache' attribute "
692
+ "to ``True``. This can have "
693
+ "significant performance implications including some "
694
+ "performance degradations in comparison to prior SQLAlchemy "
695
+ "versions. Dialect maintainers should seek to set this "
696
+ "attribute to True after appropriate development and testing "
697
+ "for SQLAlchemy 1.4 caching support. Alternatively, this "
698
+ "attribute may be set to False which will disable this "
699
+ "warning." % (self.name, self.driver),
700
+ code="cprf",
701
+ )
702
+
703
+ return bool(ssc)
704
+
705
+ @util.memoized_property
706
+ def _type_memos(self):
707
+ return weakref.WeakKeyDictionary()
708
+
709
+ @property
710
+ def dialect_description(self): # type: ignore[override]
711
+ return self.name + "+" + self.driver
712
+
713
+ @property
714
+ def supports_sane_rowcount_returning(self):
715
+ """True if this dialect supports sane rowcount even if RETURNING is
716
+ in use.
717
+
718
+ For dialects that don't support RETURNING, this is synonymous with
719
+ ``supports_sane_rowcount``.
720
+
721
+ """
722
+ return self.supports_sane_rowcount
723
+
724
+ @classmethod
725
+ def get_pool_class(cls, url: URL) -> Type[Pool]:
726
+ default: Type[pool.Pool]
727
+ if cls.is_async:
728
+ default = pool.AsyncAdaptedQueuePool
729
+ else:
730
+ default = pool.QueuePool
731
+
732
+ return getattr(cls, "poolclass", default)
733
+
734
+ def get_dialect_pool_class(self, url: URL) -> Type[Pool]:
735
+ return self.get_pool_class(url)
736
+
737
+ @classmethod
738
+ def load_provisioning(cls):
739
+ package = ".".join(cls.__module__.split(".")[0:-1])
740
+ try:
741
+ __import__(package + ".provision")
742
+ except ImportError:
743
+ pass
744
+
745
+ def _builtin_onconnect(self) -> Optional[_ListenerFnType]:
746
+ if self._on_connect_isolation_level is not None:
747
+
748
+ def builtin_connect(dbapi_conn, conn_rec):
749
+ self._assert_and_set_isolation_level(
750
+ dbapi_conn, self._on_connect_isolation_level
751
+ )
752
+
753
+ return builtin_connect
754
+ else:
755
+ return None
756
+
757
+ def initialize(self, connection: Connection) -> None:
758
+ try:
759
+ self.server_version_info = self._get_server_version_info(
760
+ connection
761
+ )
762
+ except NotImplementedError:
763
+ self.server_version_info = None
764
+ try:
765
+ self.default_schema_name = self._get_default_schema_name(
766
+ connection
767
+ )
768
+ except NotImplementedError:
769
+ self.default_schema_name = None
770
+
771
+ try:
772
+ self.default_isolation_level = self.get_default_isolation_level(
773
+ connection.connection.dbapi_connection
774
+ )
775
+ except NotImplementedError:
776
+ self.default_isolation_level = None
777
+
778
+ if not self._user_defined_max_identifier_length:
779
+ max_ident_length = self._check_max_identifier_length(connection)
780
+ if max_ident_length:
781
+ self.max_identifier_length = max_ident_length
782
+
783
+ if (
784
+ self.label_length
785
+ and self.label_length > self.max_identifier_length
786
+ ):
787
+ raise exc.ArgumentError(
788
+ "Label length of %d is greater than this dialect's"
789
+ " maximum identifier length of %d"
790
+ % (self.label_length, self.max_identifier_length)
791
+ )
792
+
793
+ def on_connect(self) -> Optional[Callable[[Any], None]]:
794
+ # inherits the docstring from interfaces.Dialect.on_connect
795
+ return None
796
+
797
+ def _check_max_identifier_length(self, connection):
798
+ """Perform a connection / server version specific check to determine
799
+ the max_identifier_length.
800
+
801
+ If the dialect's class level max_identifier_length should be used,
802
+ can return None.
803
+
804
+ """
805
+ return None
806
+
807
+ def get_default_isolation_level(self, dbapi_conn):
808
+ """Given a DBAPI connection, return its isolation level, or
809
+ a default isolation level if one cannot be retrieved.
810
+
811
+ May be overridden by subclasses in order to provide a
812
+ "fallback" isolation level for databases that cannot reliably
813
+ retrieve the actual isolation level.
814
+
815
+ By default, calls the :meth:`_engine.Interfaces.get_isolation_level`
816
+ method, propagating any exceptions raised.
817
+
818
+ """
819
+ return self.get_isolation_level(dbapi_conn)
820
+
821
+ def type_descriptor(self, typeobj):
822
+ """Provide a database-specific :class:`.TypeEngine` object, given
823
+ the generic object which comes from the types module.
824
+
825
+ This method looks for a dictionary called
826
+ ``colspecs`` as a class or instance-level variable,
827
+ and passes on to :func:`_types.adapt_type`.
828
+
829
+ """
830
+ return type_api.adapt_type(typeobj, self.colspecs)
831
+
832
+ def has_index(self, connection, table_name, index_name, schema=None, **kw):
833
+ if not self.has_table(connection, table_name, schema=schema, **kw):
834
+ return False
835
+ for idx in self.get_indexes(
836
+ connection, table_name, schema=schema, **kw
837
+ ):
838
+ if idx["name"] == index_name:
839
+ return True
840
+ else:
841
+ return False
842
+
843
+ def has_schema(
844
+ self, connection: Connection, schema_name: str, **kw: Any
845
+ ) -> bool:
846
+ return schema_name in self.get_schema_names(connection, **kw)
847
+
848
+ def validate_identifier(self, ident: str) -> None:
849
+ if len(ident) > self.max_identifier_length:
850
+ raise exc.IdentifierError(
851
+ "Identifier '%s' exceeds maximum length of %d characters"
852
+ % (ident, self.max_identifier_length)
853
+ )
854
+
855
+ def connect(self, *cargs: Any, **cparams: Any) -> DBAPIConnection:
856
+ # inherits the docstring from interfaces.Dialect.connect
857
+ return self.loaded_dbapi.connect(*cargs, **cparams) # type: ignore[no-any-return] # NOQA: E501
858
+
859
+ def create_connect_args(self, url: URL) -> ConnectArgsType:
860
+ # inherits the docstring from interfaces.Dialect.create_connect_args
861
+ opts = url.translate_connect_args()
862
+ opts.update(url.query)
863
+ return ([], opts)
864
+
865
+ def set_engine_execution_options(
866
+ self, engine: Engine, opts: Mapping[str, Any]
867
+ ) -> None:
868
+ supported_names = set(self.connection_characteristics).intersection(
869
+ opts
870
+ )
871
+ if supported_names:
872
+ characteristics: Mapping[str, Any] = util.immutabledict(
873
+ (name, opts[name]) for name in supported_names
874
+ )
875
+
876
+ @event.listens_for(engine, "engine_connect")
877
+ def set_connection_characteristics(connection):
878
+ self._set_connection_characteristics(
879
+ connection, characteristics
880
+ )
881
+
882
+ def set_connection_execution_options(
883
+ self, connection: Connection, opts: Mapping[str, Any]
884
+ ) -> None:
885
+ supported_names = set(self.connection_characteristics).intersection(
886
+ opts
887
+ )
888
+ if supported_names:
889
+ characteristics: Mapping[str, Any] = util.immutabledict(
890
+ (name, opts[name]) for name in supported_names
891
+ )
892
+ self._set_connection_characteristics(connection, characteristics)
893
+
894
+ def _set_connection_characteristics(self, connection, characteristics):
895
+ characteristic_values = [
896
+ (name, self.connection_characteristics[name], value)
897
+ for name, value in characteristics.items()
898
+ ]
899
+
900
+ if connection.in_transaction():
901
+ trans_objs = [
902
+ (name, obj)
903
+ for name, obj, _ in characteristic_values
904
+ if obj.transactional
905
+ ]
906
+ if trans_objs:
907
+ raise exc.InvalidRequestError(
908
+ "This connection has already initialized a SQLAlchemy "
909
+ "Transaction() object via begin() or autobegin; "
910
+ "%s may not be altered unless rollback() or commit() "
911
+ "is called first."
912
+ % (", ".join(name for name, obj in trans_objs))
913
+ )
914
+
915
+ dbapi_connection = connection.connection.dbapi_connection
916
+ for _, characteristic, value in characteristic_values:
917
+ characteristic.set_connection_characteristic(
918
+ self, connection, dbapi_connection, value
919
+ )
920
+ connection.connection._connection_record.finalize_callback.append(
921
+ functools.partial(self._reset_characteristics, characteristics)
922
+ )
923
+
924
+ def _reset_characteristics(self, characteristics, dbapi_connection):
925
+ for characteristic_name in characteristics:
926
+ characteristic = self.connection_characteristics[
927
+ characteristic_name
928
+ ]
929
+ characteristic.reset_characteristic(self, dbapi_connection)
930
+
931
+ def do_begin(self, dbapi_connection):
932
+ pass
933
+
934
+ def do_rollback(self, dbapi_connection):
935
+ if self.skip_autocommit_rollback and self.detect_autocommit_setting(
936
+ dbapi_connection
937
+ ):
938
+ return
939
+ dbapi_connection.rollback()
940
+
941
+ def do_commit(self, dbapi_connection):
942
+ dbapi_connection.commit()
943
+
944
+ def do_terminate(self, dbapi_connection):
945
+ self.do_close(dbapi_connection)
946
+
947
+ def do_close(self, dbapi_connection):
948
+ dbapi_connection.close()
949
+
950
+ @util.memoized_property
951
+ def _dialect_specific_select_one(self):
952
+ return str(expression.select(1).compile(dialect=self))
953
+
954
+ def _do_ping_w_event(self, dbapi_connection: DBAPIConnection) -> bool:
955
+ try:
956
+ return self.do_ping(dbapi_connection)
957
+ except self.loaded_dbapi.Error as err:
958
+ is_disconnect = self.is_disconnect(err, dbapi_connection, None)
959
+
960
+ if self._has_events:
961
+ try:
962
+ Connection._handle_dbapi_exception_noconnection(
963
+ err,
964
+ self,
965
+ is_disconnect=is_disconnect,
966
+ invalidate_pool_on_disconnect=False,
967
+ is_pre_ping=True,
968
+ )
969
+ except exc.StatementError as new_err:
970
+ is_disconnect = new_err.connection_invalidated
971
+
972
+ if is_disconnect:
973
+ return False
974
+ else:
975
+ raise
976
+
977
+ def do_ping(self, dbapi_connection: DBAPIConnection) -> bool:
978
+ cursor = dbapi_connection.cursor()
979
+ try:
980
+ cursor.execute(self._dialect_specific_select_one)
981
+ finally:
982
+ cursor.close()
983
+ return True
984
+
985
+ def create_xid(self):
986
+ """Create a random two-phase transaction ID.
987
+
988
+ This id will be passed to do_begin_twophase(), do_rollback_twophase(),
989
+ do_commit_twophase(). Its format is unspecified.
990
+ """
991
+
992
+ return "_sa_%032x" % random.randint(0, 2**128)
993
+
994
+ def do_savepoint(self, connection, name):
995
+ connection.execute(expression.SavepointClause(name))
996
+
997
+ def do_rollback_to_savepoint(self, connection, name):
998
+ connection.execute(expression.RollbackToSavepointClause(name))
999
+
1000
+ def do_release_savepoint(self, connection, name):
1001
+ connection.execute(expression.ReleaseSavepointClause(name))
1002
+
1003
+ def _deliver_insertmanyvalues_batches(
1004
+ self,
1005
+ connection,
1006
+ cursor,
1007
+ statement,
1008
+ parameters,
1009
+ generic_setinputsizes,
1010
+ context,
1011
+ ):
1012
+ context = cast(DefaultExecutionContext, context)
1013
+ compiled = cast(SQLCompiler, context.compiled)
1014
+
1015
+ _composite_sentinel_proc: Sequence[
1016
+ Optional[_ResultProcessorType[Any]]
1017
+ ] = ()
1018
+ _scalar_sentinel_proc: Optional[_ResultProcessorType[Any]] = None
1019
+ _sentinel_proc_initialized: bool = False
1020
+
1021
+ compiled_parameters = context.compiled_parameters
1022
+
1023
+ imv = compiled._insertmanyvalues
1024
+ assert imv is not None
1025
+
1026
+ is_returning: Final[bool] = bool(compiled.effective_returning)
1027
+ batch_size = context.execution_options.get(
1028
+ "insertmanyvalues_page_size", self.insertmanyvalues_page_size
1029
+ )
1030
+
1031
+ if compiled.schema_translate_map:
1032
+ schema_translate_map = context.execution_options.get(
1033
+ "schema_translate_map", {}
1034
+ )
1035
+ else:
1036
+ schema_translate_map = None
1037
+
1038
+ if is_returning:
1039
+ result: Optional[List[Any]] = []
1040
+ context._insertmanyvalues_rows = result
1041
+
1042
+ sort_by_parameter_order = imv.sort_by_parameter_order
1043
+
1044
+ else:
1045
+ sort_by_parameter_order = False
1046
+ result = None
1047
+
1048
+ for imv_batch in compiled._deliver_insertmanyvalues_batches(
1049
+ statement,
1050
+ parameters,
1051
+ compiled_parameters,
1052
+ generic_setinputsizes,
1053
+ batch_size,
1054
+ sort_by_parameter_order,
1055
+ schema_translate_map,
1056
+ ):
1057
+ yield imv_batch
1058
+
1059
+ if is_returning:
1060
+
1061
+ try:
1062
+ rows = context.fetchall_for_returning(cursor)
1063
+ except BaseException as be:
1064
+ connection._handle_dbapi_exception(
1065
+ be,
1066
+ sql_util._long_statement(imv_batch.replaced_statement),
1067
+ imv_batch.replaced_parameters,
1068
+ None,
1069
+ context,
1070
+ is_sub_exec=True,
1071
+ )
1072
+
1073
+ # I would have thought "is_returning: Final[bool]"
1074
+ # would have assured this but pylance thinks not
1075
+ assert result is not None
1076
+
1077
+ if imv.num_sentinel_columns and not imv_batch.is_downgraded:
1078
+ composite_sentinel = imv.num_sentinel_columns > 1
1079
+ if imv.implicit_sentinel:
1080
+ # for implicit sentinel, which is currently single-col
1081
+ # integer autoincrement, do a simple sort.
1082
+ assert not composite_sentinel
1083
+ result.extend(
1084
+ sorted(rows, key=operator.itemgetter(-1))
1085
+ )
1086
+ continue
1087
+
1088
+ # otherwise, create dictionaries to match up batches
1089
+ # with parameters
1090
+ assert imv.sentinel_param_keys
1091
+ assert imv.sentinel_columns
1092
+
1093
+ _nsc = imv.num_sentinel_columns
1094
+
1095
+ if not _sentinel_proc_initialized:
1096
+ if composite_sentinel:
1097
+ _composite_sentinel_proc = [
1098
+ col.type._cached_result_processor(
1099
+ self, cursor_desc[1]
1100
+ )
1101
+ for col, cursor_desc in zip(
1102
+ imv.sentinel_columns,
1103
+ cursor.description[-_nsc:],
1104
+ )
1105
+ ]
1106
+ else:
1107
+ _scalar_sentinel_proc = (
1108
+ imv.sentinel_columns[0]
1109
+ ).type._cached_result_processor(
1110
+ self, cursor.description[-1][1]
1111
+ )
1112
+ _sentinel_proc_initialized = True
1113
+
1114
+ rows_by_sentinel: Union[
1115
+ Dict[Tuple[Any, ...], Any],
1116
+ Dict[Any, Any],
1117
+ ]
1118
+
1119
+ if composite_sentinel:
1120
+ rows_by_sentinel = {
1121
+ tuple(
1122
+ (proc(val) if proc else val)
1123
+ for val, proc in zip(
1124
+ row[-_nsc:], _composite_sentinel_proc
1125
+ )
1126
+ ): row
1127
+ for row in rows
1128
+ }
1129
+ elif _scalar_sentinel_proc:
1130
+ rows_by_sentinel = {
1131
+ _scalar_sentinel_proc(row[-1]): row for row in rows
1132
+ }
1133
+ else:
1134
+ rows_by_sentinel = {row[-1]: row for row in rows}
1135
+
1136
+ if len(rows_by_sentinel) != len(imv_batch.batch):
1137
+ # see test_insert_exec.py::
1138
+ # IMVSentinelTest::test_sentinel_incorrect_rowcount
1139
+ # for coverage / demonstration
1140
+ raise exc.InvalidRequestError(
1141
+ f"Sentinel-keyed result set did not produce "
1142
+ f"correct number of rows {len(imv_batch.batch)}; "
1143
+ "produced "
1144
+ f"{len(rows_by_sentinel)}. Please ensure the "
1145
+ "sentinel column is fully unique and populated in "
1146
+ "all cases."
1147
+ )
1148
+
1149
+ try:
1150
+ ordered_rows = [
1151
+ rows_by_sentinel[sentinel_keys]
1152
+ for sentinel_keys in imv_batch.sentinel_values
1153
+ ]
1154
+ except KeyError as ke:
1155
+ # see test_insert_exec.py::
1156
+ # IMVSentinelTest::test_sentinel_cant_match_keys
1157
+ # for coverage / demonstration
1158
+ raise exc.InvalidRequestError(
1159
+ f"Can't match sentinel values in result set to "
1160
+ f"parameter sets; key {ke.args[0]!r} was not "
1161
+ "found. "
1162
+ "There may be a mismatch between the datatype "
1163
+ "passed to the DBAPI driver vs. that which it "
1164
+ "returns in a result row. Ensure the given "
1165
+ "Python value matches the expected result type "
1166
+ "*exactly*, taking care to not rely upon implicit "
1167
+ "conversions which may occur such as when using "
1168
+ "strings in place of UUID or integer values, etc. "
1169
+ ) from ke
1170
+
1171
+ result.extend(ordered_rows)
1172
+
1173
+ else:
1174
+ result.extend(rows)
1175
+
1176
+ def do_executemany(self, cursor, statement, parameters, context=None):
1177
+ cursor.executemany(statement, parameters)
1178
+
1179
+ def do_execute(self, cursor, statement, parameters, context=None):
1180
+ cursor.execute(statement, parameters)
1181
+
1182
+ def do_execute_no_params(self, cursor, statement, context=None):
1183
+ cursor.execute(statement)
1184
+
1185
+ def is_disconnect(
1186
+ self,
1187
+ e: DBAPIModule.Error,
1188
+ connection: Union[
1189
+ pool.PoolProxiedConnection, interfaces.DBAPIConnection, None
1190
+ ],
1191
+ cursor: Optional[interfaces.DBAPICursor],
1192
+ ) -> bool:
1193
+ return False
1194
+
1195
+ @util.memoized_instancemethod
1196
+ def _gen_allowed_isolation_levels(self, dbapi_conn):
1197
+ try:
1198
+ raw_levels = list(self.get_isolation_level_values(dbapi_conn))
1199
+ except NotImplementedError:
1200
+ return None
1201
+ else:
1202
+ normalized_levels = [
1203
+ level.replace("_", " ").upper() for level in raw_levels
1204
+ ]
1205
+ if raw_levels != normalized_levels:
1206
+ raise ValueError(
1207
+ f"Dialect {self.name!r} get_isolation_level_values() "
1208
+ f"method should return names as UPPERCASE using spaces, "
1209
+ f"not underscores; got "
1210
+ f"{sorted(set(raw_levels).difference(normalized_levels))}"
1211
+ )
1212
+ return tuple(normalized_levels)
1213
+
1214
+ def _assert_and_set_isolation_level(self, dbapi_conn, level):
1215
+ level = level.replace("_", " ").upper()
1216
+
1217
+ _allowed_isolation_levels = self._gen_allowed_isolation_levels(
1218
+ dbapi_conn
1219
+ )
1220
+ if (
1221
+ _allowed_isolation_levels
1222
+ and level not in _allowed_isolation_levels
1223
+ ):
1224
+ raise exc.ArgumentError(
1225
+ f"Invalid value {level!r} for isolation_level. "
1226
+ f"Valid isolation levels for {self.name!r} are "
1227
+ f"{', '.join(_allowed_isolation_levels)}"
1228
+ )
1229
+
1230
+ self.set_isolation_level(dbapi_conn, level)
1231
+
1232
+ def reset_isolation_level(self, dbapi_conn):
1233
+ if self._on_connect_isolation_level is not None:
1234
+ assert (
1235
+ self._on_connect_isolation_level == "AUTOCOMMIT"
1236
+ or self._on_connect_isolation_level
1237
+ == self.default_isolation_level
1238
+ )
1239
+ self._assert_and_set_isolation_level(
1240
+ dbapi_conn, self._on_connect_isolation_level
1241
+ )
1242
+ else:
1243
+ assert self.default_isolation_level is not None
1244
+ self._assert_and_set_isolation_level(
1245
+ dbapi_conn,
1246
+ self.default_isolation_level,
1247
+ )
1248
+
1249
+ def normalize_name(self, name):
1250
+ if name is None:
1251
+ return None
1252
+
1253
+ name_lower = name.lower()
1254
+ name_upper = name.upper()
1255
+
1256
+ if name_upper == name_lower:
1257
+ # name has no upper/lower conversion, e.g. non-european characters.
1258
+ # return unchanged
1259
+ return name
1260
+ elif name_upper == name and not (
1261
+ self.identifier_preparer._requires_quotes
1262
+ )(name_lower):
1263
+ # name is all uppercase and doesn't require quoting; normalize
1264
+ # to all lower case
1265
+ return name_lower
1266
+ elif name_lower == name:
1267
+ # name is all lower case, which if denormalized means we need to
1268
+ # force quoting on it
1269
+ return quoted_name(name, quote=True)
1270
+ else:
1271
+ # name is mixed case, means it will be quoted in SQL when used
1272
+ # later, no normalizes
1273
+ return name
1274
+
1275
+ def denormalize_name(self, name):
1276
+ if name is None:
1277
+ return None
1278
+
1279
+ name_lower = name.lower()
1280
+ name_upper = name.upper()
1281
+
1282
+ if name_upper == name_lower:
1283
+ # name has no upper/lower conversion, e.g. non-european characters.
1284
+ # return unchanged
1285
+ return name
1286
+ elif name_lower == name and not (
1287
+ self.identifier_preparer._requires_quotes
1288
+ )(name_lower):
1289
+ name = name_upper
1290
+ return name
1291
+
1292
+ def get_driver_connection(self, connection: DBAPIConnection) -> Any:
1293
+ return connection
1294
+
1295
+ def _overrides_default(self, method):
1296
+ return (
1297
+ getattr(type(self), method).__code__
1298
+ is not getattr(DefaultDialect, method).__code__
1299
+ )
1300
+
1301
+ def _default_multi_reflect(
1302
+ self,
1303
+ single_tbl_method,
1304
+ connection,
1305
+ kind,
1306
+ schema,
1307
+ filter_names,
1308
+ scope,
1309
+ **kw,
1310
+ ):
1311
+ names_fns = []
1312
+ temp_names_fns = []
1313
+ if ObjectKind.TABLE in kind:
1314
+ names_fns.append(self.get_table_names)
1315
+ temp_names_fns.append(self.get_temp_table_names)
1316
+ if ObjectKind.VIEW in kind:
1317
+ names_fns.append(self.get_view_names)
1318
+ temp_names_fns.append(self.get_temp_view_names)
1319
+ if ObjectKind.MATERIALIZED_VIEW in kind:
1320
+ names_fns.append(self.get_materialized_view_names)
1321
+ # no temp materialized view at the moment
1322
+ # temp_names_fns.append(self.get_temp_materialized_view_names)
1323
+
1324
+ unreflectable = kw.pop("unreflectable", {})
1325
+
1326
+ if (
1327
+ filter_names
1328
+ and scope is ObjectScope.ANY
1329
+ and kind is ObjectKind.ANY
1330
+ ):
1331
+ # if names are given and no qualification on type of table
1332
+ # (i.e. the Table(..., autoload) case), take the names as given,
1333
+ # don't run names queries. If a table does not exit
1334
+ # NoSuchTableError is raised and it's skipped
1335
+
1336
+ # this also suits the case for mssql where we can reflect
1337
+ # individual temp tables but there's no temp_names_fn
1338
+ names = filter_names
1339
+ else:
1340
+ names = []
1341
+ name_kw = {"schema": schema, **kw}
1342
+ fns = []
1343
+ if ObjectScope.DEFAULT in scope:
1344
+ fns.extend(names_fns)
1345
+ if ObjectScope.TEMPORARY in scope:
1346
+ fns.extend(temp_names_fns)
1347
+
1348
+ for fn in fns:
1349
+ try:
1350
+ names.extend(fn(connection, **name_kw))
1351
+ except NotImplementedError:
1352
+ pass
1353
+
1354
+ if filter_names:
1355
+ filter_names = set(filter_names)
1356
+
1357
+ # iterate over all the tables/views and call the single table method
1358
+ for table in names:
1359
+ if not filter_names or table in filter_names:
1360
+ key = (schema, table)
1361
+ try:
1362
+ yield (
1363
+ key,
1364
+ single_tbl_method(
1365
+ connection, table, schema=schema, **kw
1366
+ ),
1367
+ )
1368
+ except exc.UnreflectableTableError as err:
1369
+ if key not in unreflectable:
1370
+ unreflectable[key] = err
1371
+ except exc.NoSuchTableError:
1372
+ pass
1373
+
1374
+ def has_multi_table(
1375
+ self,
1376
+ connection: Connection,
1377
+ table_names: Sequence[str],
1378
+ schema: Optional[str] = None,
1379
+ **kw: Any,
1380
+ ) -> Iterable[tuple[TableKey, bool]]:
1381
+ for table_name in table_names:
1382
+ exist = self.has_table(connection, table_name, schema=schema, **kw)
1383
+ yield (schema, table_name), exist
1384
+
1385
+ def get_multi_table_options(self, connection, **kw):
1386
+ return self._default_multi_reflect(
1387
+ self.get_table_options, connection, **kw
1388
+ )
1389
+
1390
+ def get_multi_columns(self, connection, **kw):
1391
+ return self._default_multi_reflect(self.get_columns, connection, **kw)
1392
+
1393
+ def get_multi_pk_constraint(self, connection, **kw):
1394
+ return self._default_multi_reflect(
1395
+ self.get_pk_constraint, connection, **kw
1396
+ )
1397
+
1398
+ def get_multi_foreign_keys(self, connection, **kw):
1399
+ return self._default_multi_reflect(
1400
+ self.get_foreign_keys, connection, **kw
1401
+ )
1402
+
1403
+ def get_multi_indexes(self, connection, **kw):
1404
+ return self._default_multi_reflect(self.get_indexes, connection, **kw)
1405
+
1406
+ def get_multi_unique_constraints(self, connection, **kw):
1407
+ return self._default_multi_reflect(
1408
+ self.get_unique_constraints, connection, **kw
1409
+ )
1410
+
1411
+ def get_multi_check_constraints(self, connection, **kw):
1412
+ return self._default_multi_reflect(
1413
+ self.get_check_constraints, connection, **kw
1414
+ )
1415
+
1416
+ def get_multi_table_comment(self, connection, **kw):
1417
+ return self._default_multi_reflect(
1418
+ self.get_table_comment, connection, **kw
1419
+ )
1420
+
1421
+
1422
+ class StrCompileDialect(DefaultDialect):
1423
+ statement_compiler = compiler.StrSQLCompiler
1424
+ ddl_compiler = compiler.DDLCompiler
1425
+ type_compiler_cls = compiler.StrSQLTypeCompiler
1426
+ preparer = compiler.IdentifierPreparer
1427
+
1428
+ insert_returning = True
1429
+ update_returning = True
1430
+ delete_returning = True
1431
+
1432
+ supports_statement_cache = True
1433
+
1434
+ supports_identity_columns = True
1435
+
1436
+ supports_sequences = True
1437
+ sequences_optional = True
1438
+ preexecute_autoincrement_sequences = False
1439
+
1440
+ supports_native_boolean = True
1441
+
1442
+ supports_multivalues_insert = True
1443
+ supports_simple_order_by_label = True
1444
+
1445
+
1446
+ class DefaultExecutionContext(ExecutionContext):
1447
+ isinsert = False
1448
+ isupdate = False
1449
+ isdelete = False
1450
+ is_crud = False
1451
+ is_text = False
1452
+ isddl = False
1453
+
1454
+ execute_style: ExecuteStyle = ExecuteStyle.EXECUTE
1455
+
1456
+ compiled: Optional[Compiled] = None
1457
+ result_column_struct: Optional[
1458
+ Tuple[List[ResultColumnsEntry], bool, bool, bool, bool]
1459
+ ] = None
1460
+ returned_default_rows: Optional[Sequence[Row[Unpack[TupleAny]]]] = None
1461
+
1462
+ execution_options: _ExecuteOptions = util.EMPTY_DICT
1463
+
1464
+ cursor_fetch_strategy = _cursor._DEFAULT_FETCH
1465
+
1466
+ invoked_statement: Optional[Executable] = None
1467
+
1468
+ _is_implicit_returning = False
1469
+ _is_explicit_returning = False
1470
+ _is_supplemental_returning = False
1471
+ _is_server_side = False
1472
+
1473
+ _soft_closed = False
1474
+
1475
+ _rowcount: Optional[int] = None
1476
+
1477
+ # a hook for SQLite's translation of
1478
+ # result column names
1479
+ # NOTE: pyhive is using this hook, can't remove it :(
1480
+ _translate_colname: Optional[
1481
+ Callable[[str], Tuple[str, Optional[str]]]
1482
+ ] = None
1483
+
1484
+ _expanded_parameters: Mapping[str, List[str]] = util.immutabledict()
1485
+ """used by set_input_sizes().
1486
+
1487
+ This collection comes from ``ExpandedState.parameter_expansion``.
1488
+
1489
+ """
1490
+
1491
+ cache_hit = NO_CACHE_KEY
1492
+
1493
+ root_connection: Connection
1494
+ _dbapi_connection: PoolProxiedConnection
1495
+ dialect: Dialect
1496
+ unicode_statement: str
1497
+ cursor: DBAPICursor
1498
+ compiled_parameters: List[_MutableCoreSingleExecuteParams]
1499
+ parameters: _DBAPIMultiExecuteParams
1500
+ extracted_parameters: Optional[Sequence[BindParameter[Any]]]
1501
+
1502
+ _empty_dict_params = cast("Mapping[str, Any]", util.EMPTY_DICT)
1503
+
1504
+ _insertmanyvalues_rows: Optional[List[Tuple[Any, ...]]] = None
1505
+ _num_sentinel_cols: int = 0
1506
+
1507
+ @classmethod
1508
+ def _init_ddl(
1509
+ cls,
1510
+ dialect: Dialect,
1511
+ connection: Connection,
1512
+ dbapi_connection: PoolProxiedConnection,
1513
+ execution_options: _ExecuteOptions,
1514
+ compiled_ddl: DDLCompiler,
1515
+ ) -> ExecutionContext:
1516
+ """Initialize execution context for an ExecutableDDLElement
1517
+ construct."""
1518
+
1519
+ self = cls.__new__(cls)
1520
+ self.root_connection = connection
1521
+ self._dbapi_connection = dbapi_connection
1522
+ self.dialect = connection.dialect
1523
+
1524
+ self.compiled = compiled = compiled_ddl
1525
+ self.isddl = True
1526
+
1527
+ self.execution_options = execution_options
1528
+
1529
+ self.unicode_statement = str(compiled)
1530
+ if compiled.schema_translate_map:
1531
+ schema_translate_map = self.execution_options.get(
1532
+ "schema_translate_map", {}
1533
+ )
1534
+
1535
+ rst = compiled.preparer._render_schema_translates
1536
+ self.unicode_statement = rst(
1537
+ self.unicode_statement, schema_translate_map
1538
+ )
1539
+
1540
+ self.statement = self.unicode_statement
1541
+
1542
+ self.cursor = self.create_cursor()
1543
+ self.compiled_parameters = []
1544
+
1545
+ if dialect.positional:
1546
+ self.parameters = [dialect.execute_sequence_format()]
1547
+ else:
1548
+ self.parameters = [self._empty_dict_params]
1549
+
1550
+ return self
1551
+
1552
+ @classmethod
1553
+ def _init_compiled(
1554
+ cls,
1555
+ dialect: Dialect,
1556
+ connection: Connection,
1557
+ dbapi_connection: PoolProxiedConnection,
1558
+ execution_options: _ExecuteOptions,
1559
+ compiled: SQLCompiler,
1560
+ parameters: _CoreMultiExecuteParams,
1561
+ invoked_statement: Executable,
1562
+ extracted_parameters: Optional[Sequence[BindParameter[Any]]],
1563
+ cache_hit: CacheStats = CacheStats.CACHING_DISABLED,
1564
+ param_dict: _CoreSingleExecuteParams | None = None,
1565
+ ) -> ExecutionContext:
1566
+ """Initialize execution context for a Compiled construct."""
1567
+
1568
+ self = cls.__new__(cls)
1569
+ self.root_connection = connection
1570
+ self._dbapi_connection = dbapi_connection
1571
+ self.dialect = connection.dialect
1572
+ self.extracted_parameters = extracted_parameters
1573
+ self.invoked_statement = invoked_statement
1574
+ self.compiled = compiled
1575
+ self.cache_hit = cache_hit
1576
+
1577
+ self.execution_options = execution_options
1578
+
1579
+ self.result_column_struct = (
1580
+ compiled._result_columns,
1581
+ compiled._ordered_columns,
1582
+ compiled._textual_ordered_columns,
1583
+ compiled._ad_hoc_textual,
1584
+ compiled._loose_column_name_matching,
1585
+ )
1586
+
1587
+ self.isinsert = ii = compiled.isinsert
1588
+ self.isupdate = iu = compiled.isupdate
1589
+ self.isdelete = id_ = compiled.isdelete
1590
+ self.is_text = compiled.isplaintext
1591
+
1592
+ if ii or iu or id_:
1593
+ dml_statement = compiled.compile_state.statement # type: ignore[union-attr] # noqa: E501
1594
+ if TYPE_CHECKING:
1595
+ assert isinstance(dml_statement, UpdateBase)
1596
+ self.is_crud = True
1597
+ self._is_explicit_returning = ier = bool(dml_statement._returning)
1598
+ self._is_implicit_returning = iir = bool(
1599
+ compiled.implicit_returning
1600
+ )
1601
+ if iir and dml_statement._supplemental_returning:
1602
+ self._is_supplemental_returning = True
1603
+
1604
+ # dont mix implicit and explicit returning
1605
+ assert not (iir and ier)
1606
+
1607
+ if (ier or iir) and compiled.for_executemany:
1608
+ if ii and not self.dialect.insert_executemany_returning:
1609
+ raise exc.InvalidRequestError(
1610
+ f"Dialect {self.dialect.dialect_description} with "
1611
+ f"current server capabilities does not support "
1612
+ "INSERT..RETURNING when executemany is used"
1613
+ )
1614
+ elif (
1615
+ ii
1616
+ and dml_statement._sort_by_parameter_order
1617
+ and not self.dialect.insert_executemany_returning_sort_by_parameter_order # noqa: E501
1618
+ ):
1619
+ raise exc.InvalidRequestError(
1620
+ f"Dialect {self.dialect.dialect_description} with "
1621
+ f"current server capabilities does not support "
1622
+ "INSERT..RETURNING with deterministic row ordering "
1623
+ "when executemany is used"
1624
+ )
1625
+ elif (
1626
+ ii
1627
+ and self.dialect.use_insertmanyvalues
1628
+ and not compiled._insertmanyvalues
1629
+ ):
1630
+ raise exc.InvalidRequestError(
1631
+ 'Statement does not have "insertmanyvalues" '
1632
+ "enabled, can't use INSERT..RETURNING with "
1633
+ "executemany in this case."
1634
+ )
1635
+ elif iu and not self.dialect.update_executemany_returning:
1636
+ raise exc.InvalidRequestError(
1637
+ f"Dialect {self.dialect.dialect_description} with "
1638
+ f"current server capabilities does not support "
1639
+ "UPDATE..RETURNING when executemany is used"
1640
+ )
1641
+ elif id_ and not self.dialect.delete_executemany_returning:
1642
+ raise exc.InvalidRequestError(
1643
+ f"Dialect {self.dialect.dialect_description} with "
1644
+ f"current server capabilities does not support "
1645
+ "DELETE..RETURNING when executemany is used"
1646
+ )
1647
+
1648
+ if not parameters:
1649
+ self.compiled_parameters = [
1650
+ compiled.construct_params(
1651
+ extracted_parameters=extracted_parameters,
1652
+ escape_names=False,
1653
+ _collected_params=param_dict,
1654
+ )
1655
+ ]
1656
+ else:
1657
+ self.compiled_parameters = [
1658
+ compiled.construct_params(
1659
+ m,
1660
+ escape_names=False,
1661
+ _group_number=grp,
1662
+ extracted_parameters=extracted_parameters,
1663
+ _collected_params=param_dict,
1664
+ )
1665
+ for grp, m in enumerate(parameters)
1666
+ ]
1667
+
1668
+ if len(parameters) > 1:
1669
+ if self.isinsert and compiled._insertmanyvalues:
1670
+ self.execute_style = ExecuteStyle.INSERTMANYVALUES
1671
+
1672
+ imv = compiled._insertmanyvalues
1673
+ if imv.sentinel_columns is not None:
1674
+ self._num_sentinel_cols = imv.num_sentinel_columns
1675
+ else:
1676
+ self.execute_style = ExecuteStyle.EXECUTEMANY
1677
+
1678
+ self.unicode_statement = compiled.string
1679
+
1680
+ self.cursor = self.create_cursor()
1681
+
1682
+ if self.compiled.insert_prefetch or self.compiled.update_prefetch:
1683
+ self._process_execute_defaults()
1684
+
1685
+ processors = compiled._bind_processors
1686
+
1687
+ flattened_processors: Mapping[
1688
+ str, _BindProcessorType[Any]
1689
+ ] = processors # type: ignore[assignment]
1690
+
1691
+ if compiled.literal_execute_params or compiled.post_compile_params:
1692
+ if self.executemany:
1693
+ raise exc.InvalidRequestError(
1694
+ "'literal_execute' or 'expanding' parameters can't be "
1695
+ "used with executemany()"
1696
+ )
1697
+
1698
+ expanded_state = compiled._process_parameters_for_postcompile(
1699
+ self.compiled_parameters[0]
1700
+ )
1701
+
1702
+ # re-assign self.unicode_statement
1703
+ self.unicode_statement = expanded_state.statement
1704
+
1705
+ self._expanded_parameters = expanded_state.parameter_expansion
1706
+
1707
+ flattened_processors = dict(processors) # type: ignore[arg-type]
1708
+ flattened_processors.update(expanded_state.processors)
1709
+ positiontup = expanded_state.positiontup
1710
+ elif compiled.positional:
1711
+ positiontup = self.compiled.positiontup
1712
+ else:
1713
+ positiontup = None
1714
+
1715
+ if compiled.schema_translate_map:
1716
+ schema_translate_map = self.execution_options.get(
1717
+ "schema_translate_map", {}
1718
+ )
1719
+ rst = compiled.preparer._render_schema_translates
1720
+ self.unicode_statement = rst(
1721
+ self.unicode_statement, schema_translate_map
1722
+ )
1723
+
1724
+ # final self.unicode_statement is now assigned, encode if needed
1725
+ # by dialect
1726
+ self.statement = self.unicode_statement
1727
+
1728
+ # Convert the dictionary of bind parameter values
1729
+ # into a dict or list to be sent to the DBAPI's
1730
+ # execute() or executemany() method.
1731
+
1732
+ if compiled.positional:
1733
+ core_positional_parameters: MutableSequence[Sequence[Any]] = []
1734
+ assert positiontup is not None
1735
+ for compiled_params in self.compiled_parameters:
1736
+ l_param: List[Any] = [
1737
+ (
1738
+ flattened_processors[key](compiled_params[key])
1739
+ if key in flattened_processors
1740
+ else compiled_params[key]
1741
+ )
1742
+ for key in positiontup
1743
+ ]
1744
+ core_positional_parameters.append(
1745
+ dialect.execute_sequence_format(l_param)
1746
+ )
1747
+
1748
+ self.parameters = core_positional_parameters
1749
+ else:
1750
+ core_dict_parameters: MutableSequence[Dict[str, Any]] = []
1751
+ escaped_names = compiled.escaped_bind_names
1752
+
1753
+ # note that currently, "expanded" parameters will be present
1754
+ # in self.compiled_parameters in their quoted form. This is
1755
+ # slightly inconsistent with the approach taken as of
1756
+ # #8056 where self.compiled_parameters is meant to contain unquoted
1757
+ # param names.
1758
+ d_param: Dict[str, Any]
1759
+ for compiled_params in self.compiled_parameters:
1760
+ if escaped_names:
1761
+ d_param = {
1762
+ escaped_names.get(key, key): (
1763
+ flattened_processors[key](compiled_params[key])
1764
+ if key in flattened_processors
1765
+ else compiled_params[key]
1766
+ )
1767
+ for key in compiled_params
1768
+ }
1769
+ else:
1770
+ d_param = {
1771
+ key: (
1772
+ flattened_processors[key](compiled_params[key])
1773
+ if key in flattened_processors
1774
+ else compiled_params[key]
1775
+ )
1776
+ for key in compiled_params
1777
+ }
1778
+
1779
+ core_dict_parameters.append(d_param)
1780
+
1781
+ self.parameters = core_dict_parameters
1782
+
1783
+ return self
1784
+
1785
+ @classmethod
1786
+ def _init_statement(
1787
+ cls,
1788
+ dialect: Dialect,
1789
+ connection: Connection,
1790
+ dbapi_connection: PoolProxiedConnection,
1791
+ execution_options: _ExecuteOptions,
1792
+ statement: str,
1793
+ parameters: _DBAPIMultiExecuteParams,
1794
+ ) -> ExecutionContext:
1795
+ """Initialize execution context for a string SQL statement."""
1796
+
1797
+ self = cls.__new__(cls)
1798
+ self.root_connection = connection
1799
+ self._dbapi_connection = dbapi_connection
1800
+ self.dialect = connection.dialect
1801
+ self.is_text = True
1802
+
1803
+ self.execution_options = execution_options
1804
+
1805
+ if not parameters:
1806
+ if self.dialect.positional:
1807
+ self.parameters = [dialect.execute_sequence_format()]
1808
+ else:
1809
+ self.parameters = [self._empty_dict_params]
1810
+ elif isinstance(parameters[0], dialect.execute_sequence_format):
1811
+ self.parameters = parameters
1812
+ elif isinstance(parameters[0], dict):
1813
+ self.parameters = parameters
1814
+ else:
1815
+ self.parameters = [
1816
+ dialect.execute_sequence_format(p) for p in parameters
1817
+ ]
1818
+
1819
+ if len(parameters) > 1:
1820
+ self.execute_style = ExecuteStyle.EXECUTEMANY
1821
+
1822
+ self.statement = self.unicode_statement = statement
1823
+
1824
+ self.cursor = self.create_cursor()
1825
+ return self
1826
+
1827
+ @classmethod
1828
+ def _init_default(
1829
+ cls,
1830
+ dialect: Dialect,
1831
+ connection: Connection,
1832
+ dbapi_connection: PoolProxiedConnection,
1833
+ execution_options: _ExecuteOptions,
1834
+ ) -> ExecutionContext:
1835
+ """Initialize execution context for a ColumnDefault construct."""
1836
+
1837
+ self = cls.__new__(cls)
1838
+ self.root_connection = connection
1839
+ self._dbapi_connection = dbapi_connection
1840
+ self.dialect = connection.dialect
1841
+
1842
+ self.execution_options = execution_options
1843
+
1844
+ self.cursor = self.create_cursor()
1845
+ return self
1846
+
1847
+ def _get_cache_stats(self) -> str:
1848
+ if self.compiled is None:
1849
+ return "raw sql"
1850
+
1851
+ now = perf_counter()
1852
+
1853
+ ch = self.cache_hit
1854
+
1855
+ gen_time = self.compiled._gen_time
1856
+ assert gen_time is not None
1857
+
1858
+ if ch is NO_CACHE_KEY:
1859
+ return "no key %.5fs" % (now - gen_time,)
1860
+ elif ch is CACHE_HIT:
1861
+ return "cached since %.4gs ago" % (now - gen_time,)
1862
+ elif ch is CACHE_MISS:
1863
+ return "generated in %.5fs" % (now - gen_time,)
1864
+ elif ch is CACHING_DISABLED:
1865
+ if "_cache_disable_reason" in self.execution_options:
1866
+ return "caching disabled (%s) %.5fs " % (
1867
+ self.execution_options["_cache_disable_reason"],
1868
+ now - gen_time,
1869
+ )
1870
+ else:
1871
+ return "caching disabled %.5fs" % (now - gen_time,)
1872
+ elif ch is NO_DIALECT_SUPPORT:
1873
+ return "dialect %s+%s does not support caching %.5fs" % (
1874
+ self.dialect.name,
1875
+ self.dialect.driver,
1876
+ now - gen_time,
1877
+ )
1878
+ else:
1879
+ return "unknown"
1880
+
1881
+ @property
1882
+ def executemany(self): # type: ignore[override]
1883
+ return self.execute_style in (
1884
+ ExecuteStyle.EXECUTEMANY,
1885
+ ExecuteStyle.INSERTMANYVALUES,
1886
+ )
1887
+
1888
+ @util.memoized_property
1889
+ def identifier_preparer(self):
1890
+ if self.compiled:
1891
+ return self.compiled.preparer
1892
+ elif "schema_translate_map" in self.execution_options:
1893
+ return self.dialect.identifier_preparer._with_schema_translate(
1894
+ self.execution_options["schema_translate_map"]
1895
+ )
1896
+ else:
1897
+ return self.dialect.identifier_preparer
1898
+
1899
+ @util.memoized_property
1900
+ def engine(self):
1901
+ return self.root_connection.engine
1902
+
1903
+ @util.memoized_property
1904
+ def postfetch_cols(self) -> Optional[Sequence[Column[Any]]]:
1905
+ if TYPE_CHECKING:
1906
+ assert isinstance(self.compiled, SQLCompiler)
1907
+ return self.compiled.postfetch
1908
+
1909
+ @util.memoized_property
1910
+ def prefetch_cols(self) -> Optional[Sequence[Column[Any]]]:
1911
+ if TYPE_CHECKING:
1912
+ assert isinstance(self.compiled, SQLCompiler)
1913
+ if self.isinsert:
1914
+ return self.compiled.insert_prefetch
1915
+ elif self.isupdate:
1916
+ return self.compiled.update_prefetch
1917
+ else:
1918
+ return ()
1919
+
1920
+ @util.memoized_property
1921
+ def no_parameters(self):
1922
+ return self.execution_options.get("no_parameters", False)
1923
+
1924
+ def _execute_scalar(
1925
+ self,
1926
+ stmt: str,
1927
+ type_: Optional[TypeEngine[Any]],
1928
+ parameters: Optional[_DBAPISingleExecuteParams] = None,
1929
+ ) -> Any:
1930
+ """Execute a string statement on the current cursor, returning a
1931
+ scalar result.
1932
+
1933
+ Used to fire off sequences, default phrases, and "select lastrowid"
1934
+ types of statements individually or in the context of a parent INSERT
1935
+ or UPDATE statement.
1936
+
1937
+ """
1938
+
1939
+ conn = self.root_connection
1940
+
1941
+ if "schema_translate_map" in self.execution_options:
1942
+ schema_translate_map = self.execution_options.get(
1943
+ "schema_translate_map", {}
1944
+ )
1945
+
1946
+ rst = self.identifier_preparer._render_schema_translates
1947
+ stmt = rst(stmt, schema_translate_map)
1948
+
1949
+ if not parameters:
1950
+ if self.dialect.positional:
1951
+ parameters = self.dialect.execute_sequence_format()
1952
+ else:
1953
+ parameters = {}
1954
+
1955
+ conn._cursor_execute(self.cursor, stmt, parameters, context=self)
1956
+ row = self.cursor.fetchone()
1957
+ if row is not None:
1958
+ r = row[0]
1959
+ else:
1960
+ r = None
1961
+ if type_ is not None:
1962
+ # apply type post processors to the result
1963
+ proc = type_._cached_result_processor(
1964
+ self.dialect, self.cursor.description[0][1]
1965
+ )
1966
+ if proc:
1967
+ return proc(r)
1968
+ return r
1969
+
1970
+ @util.memoized_property
1971
+ def connection(self):
1972
+ return self.root_connection
1973
+
1974
+ def _use_server_side_cursor(self):
1975
+ if not self.dialect.supports_server_side_cursors:
1976
+ return False
1977
+
1978
+ if self.dialect.server_side_cursors:
1979
+ # this is deprecated
1980
+ use_server_side = self.execution_options.get(
1981
+ "stream_results", True
1982
+ ) and (
1983
+ self.compiled
1984
+ and isinstance(self.compiled.statement, expression.Selectable)
1985
+ or (
1986
+ (
1987
+ not self.compiled
1988
+ or isinstance(
1989
+ self.compiled.statement, expression.TextClause
1990
+ )
1991
+ )
1992
+ and self.unicode_statement
1993
+ and SERVER_SIDE_CURSOR_RE.match(self.unicode_statement)
1994
+ )
1995
+ )
1996
+ else:
1997
+ use_server_side = self.execution_options.get(
1998
+ "stream_results", False
1999
+ )
2000
+
2001
+ return use_server_side
2002
+
2003
+ def create_cursor(self) -> DBAPICursor:
2004
+ if (
2005
+ # inlining initial preference checks for SS cursors
2006
+ self.dialect.supports_server_side_cursors
2007
+ and (
2008
+ self.execution_options.get("stream_results", False)
2009
+ or (
2010
+ self.dialect.server_side_cursors
2011
+ and self._use_server_side_cursor()
2012
+ )
2013
+ )
2014
+ ):
2015
+ self._is_server_side = True
2016
+ return self.create_server_side_cursor()
2017
+ else:
2018
+ self._is_server_side = False
2019
+ return self.create_default_cursor()
2020
+
2021
+ def fetchall_for_returning(self, cursor):
2022
+ return cursor.fetchall()
2023
+
2024
+ def create_default_cursor(self) -> DBAPICursor:
2025
+ return self._dbapi_connection.cursor()
2026
+
2027
+ def create_server_side_cursor(self) -> DBAPICursor:
2028
+ raise NotImplementedError()
2029
+
2030
+ def pre_exec(self):
2031
+ pass
2032
+
2033
+ def get_out_parameter_values(self, names):
2034
+ raise NotImplementedError(
2035
+ "This dialect does not support OUT parameters"
2036
+ )
2037
+
2038
+ def post_exec(self):
2039
+ pass
2040
+
2041
+ def get_result_processor(
2042
+ self, type_: TypeEngine[Any], colname: str, coltype: DBAPIType
2043
+ ) -> Optional[_ResultProcessorType[Any]]:
2044
+ """Return a 'result processor' for a given type as present in
2045
+ cursor.description.
2046
+
2047
+ This has a default implementation that dialects can override
2048
+ for context-sensitive result type handling.
2049
+
2050
+ """
2051
+ return type_._cached_result_processor(self.dialect, coltype)
2052
+
2053
+ def get_lastrowid(self) -> int:
2054
+ """return self.cursor.lastrowid, or equivalent, after an INSERT.
2055
+
2056
+ This may involve calling special cursor functions, issuing a new SELECT
2057
+ on the cursor (or a new one), or returning a stored value that was
2058
+ calculated within post_exec().
2059
+
2060
+ This function will only be called for dialects which support "implicit"
2061
+ primary key generation, keep preexecute_autoincrement_sequences set to
2062
+ False, and when no explicit id value was bound to the statement.
2063
+
2064
+ The function is called once for an INSERT statement that would need to
2065
+ return the last inserted primary key for those dialects that make use
2066
+ of the lastrowid concept. In these cases, it is called directly after
2067
+ :meth:`.ExecutionContext.post_exec`.
2068
+
2069
+ """
2070
+ return self.cursor.lastrowid
2071
+
2072
+ def handle_dbapi_exception(self, e):
2073
+ pass
2074
+
2075
+ @util.non_memoized_property
2076
+ def rowcount(self) -> int:
2077
+ if self._rowcount is not None:
2078
+ return self._rowcount
2079
+ else:
2080
+ return self.cursor.rowcount
2081
+
2082
+ @property
2083
+ def _has_rowcount(self):
2084
+ return self._rowcount is not None
2085
+
2086
+ def supports_sane_rowcount(self):
2087
+ return self.dialect.supports_sane_rowcount
2088
+
2089
+ def supports_sane_multi_rowcount(self):
2090
+ return self.dialect.supports_sane_multi_rowcount
2091
+
2092
+ def _setup_result_proxy(self):
2093
+ exec_opt = self.execution_options
2094
+
2095
+ if self._rowcount is None and exec_opt.get("preserve_rowcount", False):
2096
+ self._rowcount = self.cursor.rowcount
2097
+
2098
+ yp: Optional[Union[int, bool]]
2099
+ if self.is_crud or self.is_text:
2100
+ result = self._setup_dml_or_text_result()
2101
+ yp = False
2102
+ else:
2103
+ yp = exec_opt.get("yield_per", None)
2104
+ sr = self._is_server_side or exec_opt.get("stream_results", False)
2105
+ strategy = self.cursor_fetch_strategy
2106
+ if sr and strategy is _cursor._DEFAULT_FETCH:
2107
+ strategy = _cursor.BufferedRowCursorFetchStrategy(
2108
+ self.cursor, self.execution_options
2109
+ )
2110
+ cursor_description: _DBAPICursorDescription = (
2111
+ strategy.alternate_cursor_description
2112
+ or self.cursor.description
2113
+ )
2114
+ if cursor_description is None:
2115
+ strategy = _cursor._NO_CURSOR_DQL
2116
+
2117
+ result = _cursor.CursorResult(self, strategy, cursor_description)
2118
+
2119
+ compiled = self.compiled
2120
+
2121
+ if (
2122
+ compiled
2123
+ and not self.isddl
2124
+ and cast(SQLCompiler, compiled).has_out_parameters
2125
+ ):
2126
+ self._setup_out_parameters(result)
2127
+
2128
+ self._soft_closed = result._soft_closed
2129
+
2130
+ if yp:
2131
+ result = result.yield_per(yp)
2132
+
2133
+ return result
2134
+
2135
+ def _setup_out_parameters(self, result):
2136
+ compiled = cast(SQLCompiler, self.compiled)
2137
+
2138
+ out_bindparams = [
2139
+ (param, name)
2140
+ for param, name in compiled.bind_names.items()
2141
+ if param.isoutparam
2142
+ ]
2143
+ out_parameters = {}
2144
+
2145
+ for bindparam, raw_value in zip(
2146
+ [param for param, name in out_bindparams],
2147
+ self.get_out_parameter_values(
2148
+ [name for param, name in out_bindparams]
2149
+ ),
2150
+ ):
2151
+ type_ = bindparam.type
2152
+ impl_type = type_.dialect_impl(self.dialect)
2153
+ dbapi_type = impl_type.get_dbapi_type(self.dialect.loaded_dbapi)
2154
+ result_processor = impl_type.result_processor(
2155
+ self.dialect, dbapi_type
2156
+ )
2157
+ if result_processor is not None:
2158
+ raw_value = result_processor(raw_value)
2159
+ out_parameters[bindparam.key] = raw_value
2160
+
2161
+ result.out_parameters = out_parameters
2162
+
2163
+ def _setup_dml_or_text_result(self):
2164
+ compiled = cast(SQLCompiler, self.compiled)
2165
+
2166
+ strategy: ResultFetchStrategy = self.cursor_fetch_strategy
2167
+
2168
+ if self.isinsert:
2169
+ if (
2170
+ self.execute_style is ExecuteStyle.INSERTMANYVALUES
2171
+ and compiled.effective_returning
2172
+ ):
2173
+ strategy = _cursor.FullyBufferedCursorFetchStrategy(
2174
+ self.cursor,
2175
+ initial_buffer=self._insertmanyvalues_rows,
2176
+ # maintain alt cursor description if set by the
2177
+ # dialect, e.g. mssql preserves it
2178
+ alternate_description=(
2179
+ strategy.alternate_cursor_description
2180
+ ),
2181
+ )
2182
+
2183
+ if compiled.postfetch_lastrowid:
2184
+ self.inserted_primary_key_rows = (
2185
+ self._setup_ins_pk_from_lastrowid()
2186
+ )
2187
+ # else if not self._is_implicit_returning,
2188
+ # the default inserted_primary_key_rows accessor will
2189
+ # return an "empty" primary key collection when accessed.
2190
+
2191
+ if self._is_server_side and strategy is _cursor._DEFAULT_FETCH:
2192
+ strategy = _cursor.BufferedRowCursorFetchStrategy(
2193
+ self.cursor, self.execution_options
2194
+ )
2195
+
2196
+ if strategy is _cursor._NO_CURSOR_DML:
2197
+ cursor_description = None
2198
+ else:
2199
+ cursor_description = (
2200
+ strategy.alternate_cursor_description
2201
+ or self.cursor.description
2202
+ )
2203
+
2204
+ if cursor_description is None:
2205
+ strategy = _cursor._NO_CURSOR_DML
2206
+ elif self._num_sentinel_cols:
2207
+ assert self.execute_style is ExecuteStyle.INSERTMANYVALUES
2208
+ # the sentinel columns are handled in CursorResult._init_metadata
2209
+ # using essentially _reduce
2210
+
2211
+ result: _cursor.CursorResult[Any] = _cursor.CursorResult(
2212
+ self, strategy, cursor_description
2213
+ )
2214
+
2215
+ if self.isinsert:
2216
+ if self._is_implicit_returning:
2217
+ rows = result.all()
2218
+
2219
+ self.returned_default_rows = rows
2220
+
2221
+ self.inserted_primary_key_rows = (
2222
+ self._setup_ins_pk_from_implicit_returning(result, rows)
2223
+ )
2224
+
2225
+ # test that it has a cursor metadata that is accurate. the
2226
+ # first row will have been fetched and current assumptions
2227
+ # are that the result has only one row, until executemany()
2228
+ # support is added here.
2229
+ assert result._metadata.returns_rows
2230
+
2231
+ # Insert statement has both return_defaults() and
2232
+ # returning(). rewind the result on the list of rows
2233
+ # we just used.
2234
+ if self._is_supplemental_returning:
2235
+ result._rewind(rows)
2236
+ else:
2237
+ result._soft_close()
2238
+ elif not self._is_explicit_returning:
2239
+ result._soft_close()
2240
+
2241
+ # we assume here the result does not return any rows.
2242
+ # *usually*, this will be true. However, some dialects
2243
+ # such as that of MSSQL/pyodbc need to SELECT a post fetch
2244
+ # function so this is not necessarily true.
2245
+ # assert not result.returns_rows
2246
+
2247
+ elif self._is_implicit_returning:
2248
+ rows = result.all()
2249
+
2250
+ if rows:
2251
+ self.returned_default_rows = rows
2252
+ self._rowcount = len(rows)
2253
+
2254
+ if self._is_supplemental_returning:
2255
+ result._rewind(rows)
2256
+ else:
2257
+ result._soft_close()
2258
+
2259
+ # test that it has a cursor metadata that is accurate.
2260
+ # the rows have all been fetched however.
2261
+ assert result._metadata.returns_rows
2262
+
2263
+ elif not result._metadata.returns_rows:
2264
+ # no results, get rowcount
2265
+ # (which requires open cursor on some drivers)
2266
+ if self._rowcount is None:
2267
+ self._rowcount = self.cursor.rowcount
2268
+ result._soft_close()
2269
+ elif self.isupdate or self.isdelete:
2270
+ if self._rowcount is None:
2271
+ self._rowcount = self.cursor.rowcount
2272
+ return result
2273
+
2274
+ @util.memoized_property
2275
+ def inserted_primary_key_rows(self):
2276
+ # if no specific "get primary key" strategy was set up
2277
+ # during execution, return a "default" primary key based
2278
+ # on what's in the compiled_parameters and nothing else.
2279
+ return self._setup_ins_pk_from_empty()
2280
+
2281
+ def _setup_ins_pk_from_lastrowid(self):
2282
+ getter = cast(
2283
+ SQLCompiler, self.compiled
2284
+ )._inserted_primary_key_from_lastrowid_getter
2285
+ lastrowid = self.get_lastrowid()
2286
+ return [getter(lastrowid, self.compiled_parameters[0])]
2287
+
2288
+ def _setup_ins_pk_from_empty(self):
2289
+ getter = cast(
2290
+ SQLCompiler, self.compiled
2291
+ )._inserted_primary_key_from_lastrowid_getter
2292
+ return [getter(None, param) for param in self.compiled_parameters]
2293
+
2294
+ def _setup_ins_pk_from_implicit_returning(self, result, rows):
2295
+ if not rows:
2296
+ return []
2297
+
2298
+ getter = cast(
2299
+ SQLCompiler, self.compiled
2300
+ )._inserted_primary_key_from_returning_getter
2301
+ compiled_params = self.compiled_parameters
2302
+
2303
+ return [
2304
+ getter(row, param) for row, param in zip(rows, compiled_params)
2305
+ ]
2306
+
2307
+ def lastrow_has_defaults(self) -> bool:
2308
+ return (self.isinsert or self.isupdate) and bool(
2309
+ cast(SQLCompiler, self.compiled).postfetch
2310
+ )
2311
+
2312
+ def _prepare_set_input_sizes(
2313
+ self,
2314
+ ) -> Optional[List[Tuple[str, Any, TypeEngine[Any]]]]:
2315
+ """Given a cursor and ClauseParameters, prepare arguments
2316
+ in order to call the appropriate
2317
+ style of ``setinputsizes()`` on the cursor, using DB-API types
2318
+ from the bind parameter's ``TypeEngine`` objects.
2319
+
2320
+ This method only called by those dialects which set the
2321
+ :attr:`.Dialect.bind_typing` attribute to
2322
+ :attr:`.BindTyping.SETINPUTSIZES`. Python-oracledb and cx_Oracle are
2323
+ the only DBAPIs that requires setinputsizes(); pyodbc offers it as an
2324
+ option.
2325
+
2326
+ Prior to SQLAlchemy 2.0, the setinputsizes() approach was also used
2327
+ for pg8000 and asyncpg, which has been changed to inline rendering
2328
+ of casts.
2329
+
2330
+ """
2331
+ if self.isddl or self.is_text:
2332
+ return None
2333
+
2334
+ compiled = cast(SQLCompiler, self.compiled)
2335
+
2336
+ inputsizes = compiled._get_set_input_sizes_lookup()
2337
+
2338
+ if inputsizes is None:
2339
+ return None
2340
+
2341
+ dialect = self.dialect
2342
+
2343
+ # all of the rest of this... cython?
2344
+
2345
+ if dialect._has_events:
2346
+ inputsizes = dict(inputsizes)
2347
+ dialect.dispatch.do_setinputsizes(
2348
+ inputsizes, self.cursor, self.statement, self.parameters, self
2349
+ )
2350
+
2351
+ if compiled.escaped_bind_names:
2352
+ escaped_bind_names = compiled.escaped_bind_names
2353
+ else:
2354
+ escaped_bind_names = None
2355
+
2356
+ if dialect.positional:
2357
+ items = [
2358
+ (key, compiled.binds[key])
2359
+ for key in compiled.positiontup or ()
2360
+ ]
2361
+ else:
2362
+ items = [
2363
+ (key, bindparam)
2364
+ for bindparam, key in compiled.bind_names.items()
2365
+ ]
2366
+
2367
+ generic_inputsizes: List[Tuple[str, Any, TypeEngine[Any]]] = []
2368
+ for key, bindparam in items:
2369
+ if bindparam in compiled.literal_execute_params:
2370
+ continue
2371
+
2372
+ if key in self._expanded_parameters:
2373
+ if is_tuple_type(bindparam.type):
2374
+ num = len(bindparam.type.types)
2375
+ dbtypes = inputsizes[bindparam]
2376
+ generic_inputsizes.extend(
2377
+ (
2378
+ (
2379
+ escaped_bind_names.get(paramname, paramname)
2380
+ if escaped_bind_names is not None
2381
+ else paramname
2382
+ ),
2383
+ dbtypes[idx % num],
2384
+ bindparam.type.types[idx % num],
2385
+ )
2386
+ for idx, paramname in enumerate(
2387
+ self._expanded_parameters[key]
2388
+ )
2389
+ )
2390
+ else:
2391
+ dbtype = inputsizes.get(bindparam, None)
2392
+ generic_inputsizes.extend(
2393
+ (
2394
+ (
2395
+ escaped_bind_names.get(paramname, paramname)
2396
+ if escaped_bind_names is not None
2397
+ else paramname
2398
+ ),
2399
+ dbtype,
2400
+ bindparam.type,
2401
+ )
2402
+ for paramname in self._expanded_parameters[key]
2403
+ )
2404
+ else:
2405
+ dbtype = inputsizes.get(bindparam, None)
2406
+
2407
+ escaped_name = (
2408
+ escaped_bind_names.get(key, key)
2409
+ if escaped_bind_names is not None
2410
+ else key
2411
+ )
2412
+
2413
+ generic_inputsizes.append(
2414
+ (escaped_name, dbtype, bindparam.type)
2415
+ )
2416
+
2417
+ return generic_inputsizes
2418
+
2419
+ def _exec_default(self, column, default, type_):
2420
+ if default.is_sequence:
2421
+ return self.fire_sequence(default, type_)
2422
+ elif default.is_callable:
2423
+ # this codepath is not normally used as it's inlined
2424
+ # into _process_execute_defaults
2425
+ self.current_column = column
2426
+ return default.arg(self)
2427
+ elif default.is_clause_element:
2428
+ return self._exec_default_clause_element(column, default, type_)
2429
+ else:
2430
+ # this codepath is not normally used as it's inlined
2431
+ # into _process_execute_defaults
2432
+ return default.arg
2433
+
2434
+ def _exec_default_clause_element(self, column, default, type_):
2435
+ # execute a default that's a complete clause element. Here, we have
2436
+ # to re-implement a miniature version of the compile->parameters->
2437
+ # cursor.execute() sequence, since we don't want to modify the state
2438
+ # of the connection / result in progress or create new connection/
2439
+ # result objects etc.
2440
+ # .. versionchanged:: 1.4
2441
+
2442
+ if not default._arg_is_typed:
2443
+ default_arg = expression.type_coerce(default.arg, type_)
2444
+ else:
2445
+ default_arg = default.arg
2446
+ compiled = expression.select(default_arg).compile(dialect=self.dialect)
2447
+ compiled_params = compiled.construct_params()
2448
+ processors = compiled._bind_processors
2449
+ if compiled.positional:
2450
+ parameters = self.dialect.execute_sequence_format(
2451
+ [
2452
+ (
2453
+ processors[key](compiled_params[key]) # type: ignore[operator] # noqa: E501
2454
+ if key in processors
2455
+ else compiled_params[key]
2456
+ )
2457
+ for key in compiled.positiontup or ()
2458
+ ]
2459
+ )
2460
+ else:
2461
+ parameters = {
2462
+ key: (
2463
+ processors[key](compiled_params[key]) # type: ignore[assignment, operator] # noqa: E501
2464
+ if key in processors
2465
+ else compiled_params[key]
2466
+ )
2467
+ for key in compiled_params
2468
+ }
2469
+ return self._execute_scalar(
2470
+ str(compiled), type_, parameters=parameters
2471
+ )
2472
+
2473
+ current_parameters: Optional[_CoreSingleExecuteParams] = None
2474
+ """A dictionary of parameters applied to the current row.
2475
+
2476
+ This attribute is only available in the context of a user-defined default
2477
+ generation function, e.g. as described at :ref:`context_default_functions`.
2478
+ It consists of a dictionary which includes entries for each column/value
2479
+ pair that is to be part of the INSERT or UPDATE statement. The keys of the
2480
+ dictionary will be the key value of each :class:`_schema.Column`,
2481
+ which is usually
2482
+ synonymous with the name.
2483
+
2484
+ Note that the :attr:`.DefaultExecutionContext.current_parameters` attribute
2485
+ does not accommodate for the "multi-values" feature of the
2486
+ :meth:`_expression.Insert.values` method. The
2487
+ :meth:`.DefaultExecutionContext.get_current_parameters` method should be
2488
+ preferred.
2489
+
2490
+ .. seealso::
2491
+
2492
+ :meth:`.DefaultExecutionContext.get_current_parameters`
2493
+
2494
+ :ref:`context_default_functions`
2495
+
2496
+ """
2497
+
2498
+ def get_current_parameters(self, isolate_multiinsert_groups=True):
2499
+ """Return a dictionary of parameters applied to the current row.
2500
+
2501
+ This method can only be used in the context of a user-defined default
2502
+ generation function, e.g. as described at
2503
+ :ref:`context_default_functions`. When invoked, a dictionary is
2504
+ returned which includes entries for each column/value pair that is part
2505
+ of the INSERT or UPDATE statement. The keys of the dictionary will be
2506
+ the key value of each :class:`_schema.Column`,
2507
+ which is usually synonymous
2508
+ with the name.
2509
+
2510
+ :param isolate_multiinsert_groups=True: indicates that multi-valued
2511
+ INSERT constructs created using :meth:`_expression.Insert.values`
2512
+ should be
2513
+ handled by returning only the subset of parameters that are local
2514
+ to the current column default invocation. When ``False``, the
2515
+ raw parameters of the statement are returned including the
2516
+ naming convention used in the case of multi-valued INSERT.
2517
+
2518
+ .. seealso::
2519
+
2520
+ :attr:`.DefaultExecutionContext.current_parameters`
2521
+
2522
+ :ref:`context_default_functions`
2523
+
2524
+ """
2525
+ try:
2526
+ parameters = self.current_parameters
2527
+ column = self.current_column
2528
+ except AttributeError:
2529
+ raise exc.InvalidRequestError(
2530
+ "get_current_parameters() can only be invoked in the "
2531
+ "context of a Python side column default function"
2532
+ )
2533
+ else:
2534
+ assert column is not None
2535
+ assert parameters is not None
2536
+ compile_state = cast(
2537
+ "DMLState", cast(SQLCompiler, self.compiled).compile_state
2538
+ )
2539
+ assert compile_state is not None
2540
+ if (
2541
+ isolate_multiinsert_groups
2542
+ and dml.isinsert(compile_state)
2543
+ and compile_state._has_multi_parameters
2544
+ ):
2545
+ if column._is_multiparam_column:
2546
+ index = column.index + 1
2547
+ d = {column.original.key: parameters[column.key]}
2548
+ else:
2549
+ d = {column.key: parameters[column.key]}
2550
+ index = 0
2551
+ assert compile_state._dict_parameters is not None
2552
+ keys = compile_state._dict_parameters.keys()
2553
+ d.update(
2554
+ (key, parameters["%s_m%d" % (key, index)]) for key in keys
2555
+ )
2556
+ return d
2557
+ else:
2558
+ return parameters
2559
+
2560
+ def get_insert_default(self, column):
2561
+ if column.default is None:
2562
+ return None
2563
+ else:
2564
+ return self._exec_default(column, column.default, column.type)
2565
+
2566
+ def get_update_default(self, column):
2567
+ if column.onupdate is None:
2568
+ return None
2569
+ else:
2570
+ return self._exec_default(column, column.onupdate, column.type)
2571
+
2572
+ def _process_execute_defaults(self):
2573
+ compiled = cast(SQLCompiler, self.compiled)
2574
+
2575
+ key_getter = compiled._within_exec_param_key_getter
2576
+
2577
+ sentinel_counter = 0
2578
+
2579
+ if compiled.insert_prefetch:
2580
+ prefetch_recs = [
2581
+ (
2582
+ c,
2583
+ key_getter(c),
2584
+ c._default_description_tuple,
2585
+ self.get_insert_default,
2586
+ )
2587
+ for c in compiled.insert_prefetch
2588
+ ]
2589
+ elif compiled.update_prefetch:
2590
+ prefetch_recs = [
2591
+ (
2592
+ c,
2593
+ key_getter(c),
2594
+ c._onupdate_description_tuple,
2595
+ self.get_update_default,
2596
+ )
2597
+ for c in compiled.update_prefetch
2598
+ ]
2599
+ else:
2600
+ prefetch_recs = []
2601
+
2602
+ for param in self.compiled_parameters:
2603
+ self.current_parameters = param
2604
+
2605
+ for (
2606
+ c,
2607
+ param_key,
2608
+ (arg, is_scalar, is_callable, is_sentinel),
2609
+ fallback,
2610
+ ) in prefetch_recs:
2611
+ if is_sentinel:
2612
+ param[param_key] = sentinel_counter
2613
+ sentinel_counter += 1
2614
+ elif is_scalar:
2615
+ param[param_key] = arg
2616
+ elif is_callable:
2617
+ self.current_column = c
2618
+ param[param_key] = arg(self)
2619
+ else:
2620
+ val = fallback(c)
2621
+ if val is not None:
2622
+ param[param_key] = val
2623
+
2624
+ del self.current_parameters
2625
+
2626
+
2627
+ DefaultDialect.execution_ctx_cls = DefaultExecutionContext