default.py 84 KB

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