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