default.py 83 KB

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