default.py 82 KB

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