default.py 84 KB

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