default.py 65 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941
  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. """Default implementations of per-dialect sqlalchemy.engine classes.
  8. These are semi-private implementation classes which are only of importance
  9. to database dialect authors; dialects will usually use the classes here
  10. as the base class for their own corresponding classes.
  11. """
  12. import codecs
  13. import functools
  14. import random
  15. import re
  16. import weakref
  17. from . import characteristics
  18. from . import cursor as _cursor
  19. from . import interfaces
  20. from .base import Connection
  21. from .. import event
  22. from .. import exc
  23. from .. import pool
  24. from .. import processors
  25. from .. import types as sqltypes
  26. from .. import util
  27. from ..sql import compiler
  28. from ..sql import expression
  29. from ..sql.elements import quoted_name
  30. AUTOCOMMIT_REGEXP = re.compile(
  31. r"\s*(?:UPDATE|INSERT|CREATE|DELETE|DROP|ALTER)", re.I | re.UNICODE
  32. )
  33. # When we're handed literal SQL, ensure it's a SELECT query
  34. SERVER_SIDE_CURSOR_RE = re.compile(r"\s*SELECT", re.I | re.UNICODE)
  35. CACHE_HIT = util.symbol("CACHE_HIT")
  36. CACHE_MISS = util.symbol("CACHE_MISS")
  37. CACHING_DISABLED = util.symbol("CACHING_DISABLED")
  38. NO_CACHE_KEY = util.symbol("NO_CACHE_KEY")
  39. NO_DIALECT_SUPPORT = util.symbol("NO_DIALECT_SUPPORT")
  40. class DefaultDialect(interfaces.Dialect):
  41. """Default implementation of Dialect"""
  42. statement_compiler = compiler.SQLCompiler
  43. ddl_compiler = compiler.DDLCompiler
  44. type_compiler = compiler.GenericTypeCompiler
  45. preparer = compiler.IdentifierPreparer
  46. supports_alter = True
  47. supports_comments = False
  48. inline_comments = False
  49. use_setinputsizes = False
  50. supports_statement_cache = True
  51. # the first value we'd get for an autoincrement
  52. # column.
  53. default_sequence_base = 1
  54. # most DBAPIs happy with this for execute().
  55. # not cx_oracle.
  56. execute_sequence_format = tuple
  57. supports_schemas = True
  58. supports_views = True
  59. supports_sequences = False
  60. sequences_optional = False
  61. preexecute_autoincrement_sequences = False
  62. supports_identity_columns = False
  63. postfetch_lastrowid = True
  64. implicit_returning = False
  65. full_returning = False
  66. insert_executemany_returning = False
  67. cte_follows_insert = False
  68. supports_native_enum = False
  69. supports_native_boolean = False
  70. non_native_boolean_check_constraint = True
  71. supports_simple_order_by_label = True
  72. tuple_in_values = False
  73. connection_characteristics = util.immutabledict(
  74. {"isolation_level": characteristics.IsolationLevelCharacteristic()}
  75. )
  76. engine_config_types = util.immutabledict(
  77. [
  78. ("convert_unicode", util.bool_or_str("force")),
  79. ("pool_timeout", util.asint),
  80. ("echo", util.bool_or_str("debug")),
  81. ("echo_pool", util.bool_or_str("debug")),
  82. ("pool_recycle", util.asint),
  83. ("pool_size", util.asint),
  84. ("max_overflow", util.asint),
  85. ("future", util.asbool),
  86. ]
  87. )
  88. # if the NUMERIC type
  89. # returns decimal.Decimal.
  90. # *not* the FLOAT type however.
  91. supports_native_decimal = False
  92. if util.py3k:
  93. supports_unicode_statements = True
  94. supports_unicode_binds = True
  95. returns_unicode_strings = sqltypes.String.RETURNS_UNICODE
  96. description_encoding = None
  97. else:
  98. supports_unicode_statements = False
  99. supports_unicode_binds = False
  100. returns_unicode_strings = sqltypes.String.RETURNS_UNKNOWN
  101. description_encoding = "use_encoding"
  102. name = "default"
  103. # length at which to truncate
  104. # any identifier.
  105. max_identifier_length = 9999
  106. _user_defined_max_identifier_length = None
  107. isolation_level = None
  108. # sub-categories of max_identifier_length.
  109. # currently these accommodate for MySQL which allows alias names
  110. # of 255 but DDL names only of 64.
  111. max_index_name_length = None
  112. max_constraint_name_length = None
  113. supports_sane_rowcount = True
  114. supports_sane_multi_rowcount = True
  115. colspecs = {}
  116. default_paramstyle = "named"
  117. supports_default_values = False
  118. """dialect supports INSERT... DEFAULT VALUES syntax"""
  119. supports_default_metavalue = False
  120. """dialect supports INSERT... VALUES (DEFAULT) syntax"""
  121. # not sure if this is a real thing but the compiler will deliver it
  122. # if this is the only flag enabled.
  123. supports_empty_insert = True
  124. """dialect supports INSERT () VALUES ()"""
  125. supports_multivalues_insert = False
  126. supports_is_distinct_from = True
  127. supports_server_side_cursors = False
  128. server_side_cursors = False
  129. # extra record-level locking features (#4860)
  130. supports_for_update_of = False
  131. server_version_info = None
  132. default_schema_name = None
  133. construct_arguments = None
  134. """Optional set of argument specifiers for various SQLAlchemy
  135. constructs, typically schema items.
  136. To implement, establish as a series of tuples, as in::
  137. construct_arguments = [
  138. (schema.Index, {
  139. "using": False,
  140. "where": None,
  141. "ops": None
  142. })
  143. ]
  144. If the above construct is established on the PostgreSQL dialect,
  145. the :class:`.Index` construct will now accept the keyword arguments
  146. ``postgresql_using``, ``postgresql_where``, nad ``postgresql_ops``.
  147. Any other argument specified to the constructor of :class:`.Index`
  148. which is prefixed with ``postgresql_`` will raise :class:`.ArgumentError`.
  149. A dialect which does not include a ``construct_arguments`` member will
  150. not participate in the argument validation system. For such a dialect,
  151. any argument name is accepted by all participating constructs, within
  152. the namespace of arguments prefixed with that dialect name. The rationale
  153. here is so that third-party dialects that haven't yet implemented this
  154. feature continue to function in the old way.
  155. .. versionadded:: 0.9.2
  156. .. seealso::
  157. :class:`.DialectKWArgs` - implementing base class which consumes
  158. :attr:`.DefaultDialect.construct_arguments`
  159. """
  160. # indicates symbol names are
  161. # UPPERCASEd if they are case insensitive
  162. # within the database.
  163. # if this is True, the methods normalize_name()
  164. # and denormalize_name() must be provided.
  165. requires_name_normalize = False
  166. reflection_options = ()
  167. dbapi_exception_translation_map = util.immutabledict()
  168. """mapping used in the extremely unusual case that a DBAPI's
  169. published exceptions don't actually have the __name__ that they
  170. are linked towards.
  171. .. versionadded:: 1.0.5
  172. """
  173. is_async = False
  174. CACHE_HIT = CACHE_HIT
  175. CACHE_MISS = CACHE_MISS
  176. CACHING_DISABLED = CACHING_DISABLED
  177. NO_CACHE_KEY = NO_CACHE_KEY
  178. NO_DIALECT_SUPPORT = NO_DIALECT_SUPPORT
  179. has_terminate = False
  180. @util.deprecated_params(
  181. convert_unicode=(
  182. "1.3",
  183. "The :paramref:`_sa.create_engine.convert_unicode` parameter "
  184. "and corresponding dialect-level parameters are deprecated, "
  185. "and will be removed in a future release. Modern DBAPIs support "
  186. "Python Unicode natively and this parameter is unnecessary.",
  187. ),
  188. empty_in_strategy=(
  189. "1.4",
  190. "The :paramref:`_sa.create_engine.empty_in_strategy` keyword is "
  191. "deprecated, and no longer has any effect. All IN expressions "
  192. "are now rendered using "
  193. 'the "expanding parameter" strategy which renders a set of bound'
  194. 'expressions, or an "empty set" SELECT, at statement execution'
  195. "time.",
  196. ),
  197. case_sensitive=(
  198. "1.4",
  199. "The :paramref:`_sa.create_engine.case_sensitive` parameter "
  200. "is deprecated and will be removed in a future release. "
  201. "Applications should work with result column names in a case "
  202. "sensitive fashion.",
  203. ),
  204. server_side_cursors=(
  205. "1.4",
  206. "The :paramref:`_sa.create_engine.server_side_cursors` parameter "
  207. "is deprecated and will be removed in a future release. Please "
  208. "use the "
  209. ":paramref:`_engine.Connection.execution_options.stream_results` "
  210. "parameter.",
  211. ),
  212. )
  213. def __init__(
  214. self,
  215. convert_unicode=False,
  216. encoding="utf-8",
  217. paramstyle=None,
  218. dbapi=None,
  219. implicit_returning=None,
  220. case_sensitive=True,
  221. supports_native_boolean=None,
  222. max_identifier_length=None,
  223. label_length=None,
  224. # int() is because the @deprecated_params decorator cannot accommodate
  225. # the direct reference to the "NO_LINTING" object
  226. compiler_linting=int(compiler.NO_LINTING),
  227. server_side_cursors=False,
  228. **kwargs
  229. ):
  230. if not getattr(self, "ported_sqla_06", True):
  231. util.warn(
  232. "The %s dialect is not yet ported to the 0.6 format"
  233. % self.name
  234. )
  235. if server_side_cursors:
  236. if not self.supports_server_side_cursors:
  237. raise exc.ArgumentError(
  238. "Dialect %s does not support server side cursors" % self
  239. )
  240. else:
  241. self.server_side_cursors = True
  242. self.convert_unicode = convert_unicode
  243. self.encoding = encoding
  244. self.positional = False
  245. self._ischema = None
  246. self.dbapi = dbapi
  247. if paramstyle is not None:
  248. self.paramstyle = paramstyle
  249. elif self.dbapi is not None:
  250. self.paramstyle = self.dbapi.paramstyle
  251. else:
  252. self.paramstyle = self.default_paramstyle
  253. if implicit_returning is not None:
  254. self.implicit_returning = implicit_returning
  255. self.positional = self.paramstyle in ("qmark", "format", "numeric")
  256. self.identifier_preparer = self.preparer(self)
  257. self.type_compiler = self.type_compiler(self)
  258. if supports_native_boolean is not None:
  259. self.supports_native_boolean = supports_native_boolean
  260. self.case_sensitive = case_sensitive
  261. self._user_defined_max_identifier_length = max_identifier_length
  262. if self._user_defined_max_identifier_length:
  263. self.max_identifier_length = (
  264. self._user_defined_max_identifier_length
  265. )
  266. self.label_length = label_length
  267. self.compiler_linting = compiler_linting
  268. if self.description_encoding == "use_encoding":
  269. self._description_decoder = (
  270. processors.to_unicode_processor_factory
  271. )(encoding)
  272. elif self.description_encoding is not None:
  273. self._description_decoder = (
  274. processors.to_unicode_processor_factory
  275. )(self.description_encoding)
  276. self._encoder = codecs.getencoder(self.encoding)
  277. self._decoder = processors.to_unicode_processor_factory(self.encoding)
  278. def _ensure_has_table_connection(self, arg):
  279. if not isinstance(arg, Connection):
  280. raise exc.ArgumentError(
  281. "The argument passed to Dialect.has_table() should be a "
  282. "%s, got %s. "
  283. "Additionally, the Dialect.has_table() method is for "
  284. "internal dialect "
  285. "use only; please use "
  286. "``inspect(some_engine).has_table(<tablename>>)`` "
  287. "for public API use." % (Connection, type(arg))
  288. )
  289. @util.memoized_property
  290. def _supports_statement_cache(self):
  291. ssc = self.__class__.__dict__.get("supports_statement_cache", None)
  292. if ssc is None:
  293. util.warn(
  294. "Dialect %s:%s will not make use of SQL compilation caching "
  295. "as it does not set the 'supports_statement_cache' attribute "
  296. "to ``True``. This can have "
  297. "significant performance implications including some "
  298. "performance degradations in comparison to prior SQLAlchemy "
  299. "versions. Dialect maintainers should seek to set this "
  300. "attribute to True after appropriate development and testing "
  301. "for SQLAlchemy 1.4 caching support. Alternatively, this "
  302. "attribute may be set to False which will disable this "
  303. "warning." % (self.name, self.driver),
  304. code="cprf",
  305. )
  306. return bool(ssc)
  307. @util.memoized_property
  308. def _type_memos(self):
  309. return weakref.WeakKeyDictionary()
  310. @property
  311. def dialect_description(self):
  312. return self.name + "+" + self.driver
  313. @property
  314. def supports_sane_rowcount_returning(self):
  315. """True if this dialect supports sane rowcount even if RETURNING is
  316. in use.
  317. For dialects that don't support RETURNING, this is synonymous with
  318. ``supports_sane_rowcount``.
  319. """
  320. return self.supports_sane_rowcount
  321. @classmethod
  322. def get_pool_class(cls, url):
  323. return getattr(cls, "poolclass", pool.QueuePool)
  324. def get_dialect_pool_class(self, url):
  325. return self.get_pool_class(url)
  326. @classmethod
  327. def load_provisioning(cls):
  328. package = ".".join(cls.__module__.split(".")[0:-1])
  329. try:
  330. __import__(package + ".provision")
  331. except ImportError:
  332. pass
  333. def initialize(self, connection):
  334. try:
  335. self.server_version_info = self._get_server_version_info(
  336. connection
  337. )
  338. except NotImplementedError:
  339. self.server_version_info = None
  340. try:
  341. self.default_schema_name = self._get_default_schema_name(
  342. connection
  343. )
  344. except NotImplementedError:
  345. self.default_schema_name = None
  346. try:
  347. self.default_isolation_level = self.get_default_isolation_level(
  348. connection.connection
  349. )
  350. except NotImplementedError:
  351. self.default_isolation_level = None
  352. if self.returns_unicode_strings is sqltypes.String.RETURNS_UNKNOWN:
  353. if util.py3k:
  354. raise exc.InvalidRequestError(
  355. "RETURNS_UNKNOWN is unsupported in Python 3"
  356. )
  357. self.returns_unicode_strings = self._check_unicode_returns(
  358. connection
  359. )
  360. if (
  361. self.description_encoding is not None
  362. and self._check_unicode_description(connection)
  363. ):
  364. self._description_decoder = self.description_encoding = None
  365. if not self._user_defined_max_identifier_length:
  366. max_ident_length = self._check_max_identifier_length(connection)
  367. if max_ident_length:
  368. self.max_identifier_length = max_ident_length
  369. if (
  370. self.label_length
  371. and self.label_length > self.max_identifier_length
  372. ):
  373. raise exc.ArgumentError(
  374. "Label length of %d is greater than this dialect's"
  375. " maximum identifier length of %d"
  376. % (self.label_length, self.max_identifier_length)
  377. )
  378. def on_connect(self):
  379. # inherits the docstring from interfaces.Dialect.on_connect
  380. return None
  381. def _check_max_identifier_length(self, connection):
  382. """Perform a connection / server version specific check to determine
  383. the max_identifier_length.
  384. If the dialect's class level max_identifier_length should be used,
  385. can return None.
  386. .. versionadded:: 1.3.9
  387. """
  388. return None
  389. def get_default_isolation_level(self, dbapi_conn):
  390. """Given a DBAPI connection, return its isolation level, or
  391. a default isolation level if one cannot be retrieved.
  392. May be overridden by subclasses in order to provide a
  393. "fallback" isolation level for databases that cannot reliably
  394. retrieve the actual isolation level.
  395. By default, calls the :meth:`_engine.Interfaces.get_isolation_level`
  396. method, propagating any exceptions raised.
  397. .. versionadded:: 1.3.22
  398. """
  399. return self.get_isolation_level(dbapi_conn)
  400. def _check_unicode_returns(self, connection, additional_tests=None):
  401. # this now runs in py2k only and will be removed in 2.0; disabled for
  402. # Python 3 in all cases under #5315
  403. if util.py2k and not self.supports_unicode_statements:
  404. cast_to = util.binary_type
  405. else:
  406. cast_to = util.text_type
  407. if self.positional:
  408. parameters = self.execute_sequence_format()
  409. else:
  410. parameters = {}
  411. def check_unicode(test):
  412. statement = cast_to(expression.select(test).compile(dialect=self))
  413. try:
  414. cursor = connection.connection.cursor()
  415. connection._cursor_execute(cursor, statement, parameters)
  416. row = cursor.fetchone()
  417. cursor.close()
  418. except exc.DBAPIError as de:
  419. # note that _cursor_execute() will have closed the cursor
  420. # if an exception is thrown.
  421. util.warn(
  422. "Exception attempting to "
  423. "detect unicode returns: %r" % de
  424. )
  425. return False
  426. else:
  427. return isinstance(row[0], util.text_type)
  428. tests = [
  429. # detect plain VARCHAR
  430. expression.cast(
  431. expression.literal_column("'test plain returns'"),
  432. sqltypes.VARCHAR(60),
  433. ),
  434. # detect if there's an NVARCHAR type with different behavior
  435. # available
  436. expression.cast(
  437. expression.literal_column("'test unicode returns'"),
  438. sqltypes.Unicode(60),
  439. ),
  440. ]
  441. if additional_tests:
  442. tests += additional_tests
  443. results = {check_unicode(test) for test in tests}
  444. if results.issuperset([True, False]):
  445. return sqltypes.String.RETURNS_CONDITIONAL
  446. else:
  447. return (
  448. sqltypes.String.RETURNS_UNICODE
  449. if results == {True}
  450. else sqltypes.String.RETURNS_BYTES
  451. )
  452. def _check_unicode_description(self, connection):
  453. # all DBAPIs on Py2K return cursor.description as encoded
  454. if util.py2k and not self.supports_unicode_statements:
  455. cast_to = util.binary_type
  456. else:
  457. cast_to = util.text_type
  458. cursor = connection.connection.cursor()
  459. try:
  460. cursor.execute(
  461. cast_to(
  462. expression.select(
  463. expression.literal_column("'x'").label("some_label")
  464. ).compile(dialect=self)
  465. )
  466. )
  467. return isinstance(cursor.description[0][0], util.text_type)
  468. finally:
  469. cursor.close()
  470. def type_descriptor(self, typeobj):
  471. """Provide a database-specific :class:`.TypeEngine` object, given
  472. the generic object which comes from the types module.
  473. This method looks for a dictionary called
  474. ``colspecs`` as a class or instance-level variable,
  475. and passes on to :func:`_types.adapt_type`.
  476. """
  477. return sqltypes.adapt_type(typeobj, self.colspecs)
  478. def has_index(self, connection, table_name, index_name, schema=None):
  479. if not self.has_table(connection, table_name, schema=schema):
  480. return False
  481. for idx in self.get_indexes(connection, table_name, schema=schema):
  482. if idx["name"] == index_name:
  483. return True
  484. else:
  485. return False
  486. def validate_identifier(self, ident):
  487. if len(ident) > self.max_identifier_length:
  488. raise exc.IdentifierError(
  489. "Identifier '%s' exceeds maximum length of %d characters"
  490. % (ident, self.max_identifier_length)
  491. )
  492. def connect(self, *cargs, **cparams):
  493. # inherits the docstring from interfaces.Dialect.connect
  494. return self.dbapi.connect(*cargs, **cparams)
  495. def create_connect_args(self, url):
  496. # inherits the docstring from interfaces.Dialect.create_connect_args
  497. opts = url.translate_connect_args()
  498. opts.update(url.query)
  499. return [[], opts]
  500. def set_engine_execution_options(self, engine, opts):
  501. supported_names = set(self.connection_characteristics).intersection(
  502. opts
  503. )
  504. if supported_names:
  505. characteristics = util.immutabledict(
  506. (name, opts[name]) for name in supported_names
  507. )
  508. @event.listens_for(engine, "engine_connect")
  509. def set_connection_characteristics(connection, branch):
  510. if not branch:
  511. self._set_connection_characteristics(
  512. connection, characteristics
  513. )
  514. def set_connection_execution_options(self, connection, opts):
  515. supported_names = set(self.connection_characteristics).intersection(
  516. opts
  517. )
  518. if supported_names:
  519. characteristics = util.immutabledict(
  520. (name, opts[name]) for name in supported_names
  521. )
  522. self._set_connection_characteristics(connection, characteristics)
  523. def _set_connection_characteristics(self, connection, characteristics):
  524. characteristic_values = [
  525. (name, self.connection_characteristics[name], value)
  526. for name, value in characteristics.items()
  527. ]
  528. if connection.in_transaction():
  529. trans_objs = [
  530. (name, obj)
  531. for name, obj, value in characteristic_values
  532. if obj.transactional
  533. ]
  534. if trans_objs:
  535. if connection._is_future:
  536. raise exc.InvalidRequestError(
  537. "This connection has already initialized a SQLAlchemy "
  538. "Transaction() object via begin() or autobegin; "
  539. "%s may not be altered unless rollback() or commit() "
  540. "is called first."
  541. % (", ".join(name for name, obj in trans_objs))
  542. )
  543. else:
  544. util.warn(
  545. "Connection is already established with a "
  546. "Transaction; "
  547. "setting %s may implicitly rollback or "
  548. "commit "
  549. "the existing transaction, or have no effect until "
  550. "next transaction"
  551. % (", ".join(name for name, obj in trans_objs))
  552. )
  553. dbapi_connection = connection.connection.dbapi_connection
  554. for name, characteristic, value in characteristic_values:
  555. characteristic.set_characteristic(self, dbapi_connection, value)
  556. connection.connection._connection_record.finalize_callback.append(
  557. functools.partial(self._reset_characteristics, characteristics)
  558. )
  559. def _reset_characteristics(self, characteristics, dbapi_connection):
  560. for characteristic_name in characteristics:
  561. characteristic = self.connection_characteristics[
  562. characteristic_name
  563. ]
  564. characteristic.reset_characteristic(self, dbapi_connection)
  565. def do_begin(self, dbapi_connection):
  566. pass
  567. def do_rollback(self, dbapi_connection):
  568. dbapi_connection.rollback()
  569. def do_commit(self, dbapi_connection):
  570. dbapi_connection.commit()
  571. def do_terminate(self, dbapi_connection):
  572. self.do_close(dbapi_connection)
  573. def do_close(self, dbapi_connection):
  574. dbapi_connection.close()
  575. @util.memoized_property
  576. def _dialect_specific_select_one(self):
  577. return str(expression.select(1).compile(dialect=self))
  578. def do_ping(self, dbapi_connection):
  579. cursor = None
  580. try:
  581. cursor = dbapi_connection.cursor()
  582. try:
  583. cursor.execute(self._dialect_specific_select_one)
  584. finally:
  585. cursor.close()
  586. except self.dbapi.Error as err:
  587. if self.is_disconnect(err, dbapi_connection, cursor):
  588. return False
  589. else:
  590. raise
  591. else:
  592. return True
  593. def create_xid(self):
  594. """Create a random two-phase transaction ID.
  595. This id will be passed to do_begin_twophase(), do_rollback_twophase(),
  596. do_commit_twophase(). Its format is unspecified.
  597. """
  598. return "_sa_%032x" % random.randint(0, 2 ** 128)
  599. def do_savepoint(self, connection, name):
  600. connection.execute(expression.SavepointClause(name))
  601. def do_rollback_to_savepoint(self, connection, name):
  602. connection.execute(expression.RollbackToSavepointClause(name))
  603. def do_release_savepoint(self, connection, name):
  604. connection.execute(expression.ReleaseSavepointClause(name))
  605. def do_executemany(self, cursor, statement, parameters, context=None):
  606. cursor.executemany(statement, parameters)
  607. def do_execute(self, cursor, statement, parameters, context=None):
  608. cursor.execute(statement, parameters)
  609. def do_execute_no_params(self, cursor, statement, context=None):
  610. cursor.execute(statement)
  611. def is_disconnect(self, e, connection, cursor):
  612. return False
  613. def reset_isolation_level(self, dbapi_conn):
  614. # default_isolation_level is read from the first connection
  615. # after the initial set of 'isolation_level', if any, so is
  616. # the configured default of this dialect.
  617. self.set_isolation_level(dbapi_conn, self.default_isolation_level)
  618. def normalize_name(self, name):
  619. if name is None:
  620. return None
  621. if util.py2k:
  622. if isinstance(name, str):
  623. name = name.decode(self.encoding)
  624. name_lower = name.lower()
  625. name_upper = name.upper()
  626. if name_upper == name_lower:
  627. # name has no upper/lower conversion, e.g. non-european characters.
  628. # return unchanged
  629. return name
  630. elif name_upper == name and not (
  631. self.identifier_preparer._requires_quotes
  632. )(name_lower):
  633. # name is all uppercase and doesn't require quoting; normalize
  634. # to all lower case
  635. return name_lower
  636. elif name_lower == name:
  637. # name is all lower case, which if denormalized means we need to
  638. # force quoting on it
  639. return quoted_name(name, quote=True)
  640. else:
  641. # name is mixed case, means it will be quoted in SQL when used
  642. # later, no normalizes
  643. return name
  644. def denormalize_name(self, name):
  645. if name is None:
  646. return None
  647. name_lower = name.lower()
  648. name_upper = name.upper()
  649. if name_upper == name_lower:
  650. # name has no upper/lower conversion, e.g. non-european characters.
  651. # return unchanged
  652. return name
  653. elif name_lower == name and not (
  654. self.identifier_preparer._requires_quotes
  655. )(name_lower):
  656. name = name_upper
  657. if util.py2k:
  658. if not self.supports_unicode_binds:
  659. name = name.encode(self.encoding)
  660. else:
  661. name = unicode(name) # noqa
  662. return name
  663. def get_driver_connection(self, connection):
  664. return connection
  665. class _RendersLiteral(object):
  666. def literal_processor(self, dialect):
  667. def process(value):
  668. return "'%s'" % value
  669. return process
  670. class _StrDateTime(_RendersLiteral, sqltypes.DateTime):
  671. pass
  672. class _StrDate(_RendersLiteral, sqltypes.Date):
  673. pass
  674. class _StrTime(_RendersLiteral, sqltypes.Time):
  675. pass
  676. class StrCompileDialect(DefaultDialect):
  677. statement_compiler = compiler.StrSQLCompiler
  678. ddl_compiler = compiler.DDLCompiler
  679. type_compiler = compiler.StrSQLTypeCompiler
  680. preparer = compiler.IdentifierPreparer
  681. supports_statement_cache = True
  682. supports_identity_columns = True
  683. supports_sequences = True
  684. sequences_optional = True
  685. preexecute_autoincrement_sequences = False
  686. implicit_returning = False
  687. supports_native_boolean = True
  688. supports_multivalues_insert = True
  689. supports_simple_order_by_label = True
  690. colspecs = {
  691. sqltypes.DateTime: _StrDateTime,
  692. sqltypes.Date: _StrDate,
  693. sqltypes.Time: _StrTime,
  694. }
  695. class DefaultExecutionContext(interfaces.ExecutionContext):
  696. isinsert = False
  697. isupdate = False
  698. isdelete = False
  699. is_crud = False
  700. is_text = False
  701. isddl = False
  702. executemany = False
  703. compiled = None
  704. statement = None
  705. result_column_struct = None
  706. returned_default_rows = None
  707. execution_options = util.immutabledict()
  708. include_set_input_sizes = None
  709. exclude_set_input_sizes = None
  710. cursor_fetch_strategy = _cursor._DEFAULT_FETCH
  711. cache_stats = None
  712. invoked_statement = None
  713. _is_implicit_returning = False
  714. _is_explicit_returning = False
  715. _is_future_result = False
  716. _is_server_side = False
  717. _soft_closed = False
  718. # a hook for SQLite's translation of
  719. # result column names
  720. # NOTE: pyhive is using this hook, can't remove it :(
  721. _translate_colname = None
  722. _expanded_parameters = util.immutabledict()
  723. cache_hit = NO_CACHE_KEY
  724. @classmethod
  725. def _init_ddl(
  726. cls,
  727. dialect,
  728. connection,
  729. dbapi_connection,
  730. execution_options,
  731. compiled_ddl,
  732. ):
  733. """Initialize execution context for a DDLElement construct."""
  734. self = cls.__new__(cls)
  735. self.root_connection = connection
  736. self._dbapi_connection = dbapi_connection
  737. self.dialect = connection.dialect
  738. self.compiled = compiled = compiled_ddl
  739. self.isddl = True
  740. self.execution_options = execution_options
  741. self._is_future_result = (
  742. connection._is_future
  743. or self.execution_options.get("future_result", False)
  744. )
  745. self.unicode_statement = util.text_type(compiled)
  746. if compiled.schema_translate_map:
  747. schema_translate_map = self.execution_options.get(
  748. "schema_translate_map", {}
  749. )
  750. rst = compiled.preparer._render_schema_translates
  751. self.unicode_statement = rst(
  752. self.unicode_statement, schema_translate_map
  753. )
  754. if not dialect.supports_unicode_statements:
  755. self.statement = dialect._encoder(self.unicode_statement)[0]
  756. else:
  757. self.statement = self.unicode_statement
  758. self.cursor = self.create_cursor()
  759. self.compiled_parameters = []
  760. if dialect.positional:
  761. self.parameters = [dialect.execute_sequence_format()]
  762. else:
  763. self.parameters = [{}]
  764. return self
  765. @classmethod
  766. def _init_compiled(
  767. cls,
  768. dialect,
  769. connection,
  770. dbapi_connection,
  771. execution_options,
  772. compiled,
  773. parameters,
  774. invoked_statement,
  775. extracted_parameters,
  776. cache_hit=CACHING_DISABLED,
  777. ):
  778. """Initialize execution context for a Compiled construct."""
  779. self = cls.__new__(cls)
  780. self.root_connection = connection
  781. self._dbapi_connection = dbapi_connection
  782. self.dialect = connection.dialect
  783. self.extracted_parameters = extracted_parameters
  784. self.invoked_statement = invoked_statement
  785. self.compiled = compiled
  786. self.cache_hit = cache_hit
  787. self.execution_options = execution_options
  788. self._is_future_result = (
  789. connection._is_future
  790. or self.execution_options.get("future_result", False)
  791. )
  792. self.result_column_struct = (
  793. compiled._result_columns,
  794. compiled._ordered_columns,
  795. compiled._textual_ordered_columns,
  796. compiled._ad_hoc_textual,
  797. compiled._loose_column_name_matching,
  798. )
  799. self.isinsert = compiled.isinsert
  800. self.isupdate = compiled.isupdate
  801. self.isdelete = compiled.isdelete
  802. self.is_text = compiled.isplaintext
  803. if self.isinsert or self.isupdate or self.isdelete:
  804. self.is_crud = True
  805. self._is_explicit_returning = bool(compiled.statement._returning)
  806. self._is_implicit_returning = bool(
  807. compiled.returning and not compiled.statement._returning
  808. )
  809. if not parameters:
  810. self.compiled_parameters = [
  811. compiled.construct_params(
  812. extracted_parameters=extracted_parameters,
  813. escape_names=False,
  814. )
  815. ]
  816. else:
  817. self.compiled_parameters = [
  818. compiled.construct_params(
  819. m,
  820. escape_names=False,
  821. _group_number=grp,
  822. extracted_parameters=extracted_parameters,
  823. )
  824. for grp, m in enumerate(parameters)
  825. ]
  826. self.executemany = len(parameters) > 1
  827. # this must occur before create_cursor() since the statement
  828. # has to be regexed in some cases for server side cursor
  829. if util.py2k:
  830. self.unicode_statement = util.text_type(compiled.string)
  831. else:
  832. self.unicode_statement = compiled.string
  833. self.cursor = self.create_cursor()
  834. if self.compiled.insert_prefetch or self.compiled.update_prefetch:
  835. if self.executemany:
  836. self._process_executemany_defaults()
  837. else:
  838. self._process_executesingle_defaults()
  839. processors = compiled._bind_processors
  840. if compiled.literal_execute_params or compiled.post_compile_params:
  841. if self.executemany:
  842. raise exc.InvalidRequestError(
  843. "'literal_execute' or 'expanding' parameters can't be "
  844. "used with executemany()"
  845. )
  846. expanded_state = compiled._process_parameters_for_postcompile(
  847. self.compiled_parameters[0]
  848. )
  849. # re-assign self.unicode_statement
  850. self.unicode_statement = expanded_state.statement
  851. # used by set_input_sizes() which is needed for Oracle
  852. self._expanded_parameters = expanded_state.parameter_expansion
  853. processors = dict(processors)
  854. processors.update(expanded_state.processors)
  855. positiontup = expanded_state.positiontup
  856. elif compiled.positional:
  857. positiontup = self.compiled.positiontup
  858. if compiled.schema_translate_map:
  859. schema_translate_map = self.execution_options.get(
  860. "schema_translate_map", {}
  861. )
  862. rst = compiled.preparer._render_schema_translates
  863. self.unicode_statement = rst(
  864. self.unicode_statement, schema_translate_map
  865. )
  866. # final self.unicode_statement is now assigned, encode if needed
  867. # by dialect
  868. if not dialect.supports_unicode_statements:
  869. self.statement = self.unicode_statement.encode(
  870. self.dialect.encoding
  871. )
  872. else:
  873. self.statement = self.unicode_statement
  874. # Convert the dictionary of bind parameter values
  875. # into a dict or list to be sent to the DBAPI's
  876. # execute() or executemany() method.
  877. parameters = []
  878. if compiled.positional:
  879. for compiled_params in self.compiled_parameters:
  880. param = [
  881. processors[key](compiled_params[key])
  882. if key in processors
  883. else compiled_params[key]
  884. for key in positiontup
  885. ]
  886. parameters.append(dialect.execute_sequence_format(param))
  887. else:
  888. encode = not dialect.supports_unicode_statements
  889. if encode:
  890. encoder = dialect._encoder
  891. for compiled_params in self.compiled_parameters:
  892. escaped_bind_names = compiled.escaped_bind_names
  893. if encode:
  894. if escaped_bind_names:
  895. param = {
  896. encoder(escaped_bind_names.get(key, key))[
  897. 0
  898. ]: processors[key](compiled_params[key])
  899. if key in processors
  900. else compiled_params[key]
  901. for key in compiled_params
  902. }
  903. else:
  904. param = {
  905. encoder(key)[0]: processors[key](
  906. compiled_params[key]
  907. )
  908. if key in processors
  909. else compiled_params[key]
  910. for key in compiled_params
  911. }
  912. else:
  913. if escaped_bind_names:
  914. param = {
  915. escaped_bind_names.get(key, key): processors[key](
  916. compiled_params[key]
  917. )
  918. if key in processors
  919. else compiled_params[key]
  920. for key in compiled_params
  921. }
  922. else:
  923. param = {
  924. key: processors[key](compiled_params[key])
  925. if key in processors
  926. else compiled_params[key]
  927. for key in compiled_params
  928. }
  929. parameters.append(param)
  930. self.parameters = dialect.execute_sequence_format(parameters)
  931. return self
  932. @classmethod
  933. def _init_statement(
  934. cls,
  935. dialect,
  936. connection,
  937. dbapi_connection,
  938. execution_options,
  939. statement,
  940. parameters,
  941. ):
  942. """Initialize execution context for a string SQL statement."""
  943. self = cls.__new__(cls)
  944. self.root_connection = connection
  945. self._dbapi_connection = dbapi_connection
  946. self.dialect = connection.dialect
  947. self.is_text = True
  948. self.execution_options = execution_options
  949. self._is_future_result = (
  950. connection._is_future
  951. or self.execution_options.get("future_result", False)
  952. )
  953. if not parameters:
  954. if self.dialect.positional:
  955. self.parameters = [dialect.execute_sequence_format()]
  956. else:
  957. self.parameters = [{}]
  958. elif isinstance(parameters[0], dialect.execute_sequence_format):
  959. self.parameters = parameters
  960. elif isinstance(parameters[0], dict):
  961. if dialect.supports_unicode_statements:
  962. self.parameters = parameters
  963. else:
  964. self.parameters = [
  965. {dialect._encoder(k)[0]: d[k] for k in d}
  966. for d in parameters
  967. ] or [{}]
  968. else:
  969. self.parameters = [
  970. dialect.execute_sequence_format(p) for p in parameters
  971. ]
  972. self.executemany = len(parameters) > 1
  973. if not dialect.supports_unicode_statements and isinstance(
  974. statement, util.text_type
  975. ):
  976. self.unicode_statement = statement
  977. self.statement = dialect._encoder(statement)[0]
  978. else:
  979. self.statement = self.unicode_statement = statement
  980. self.cursor = self.create_cursor()
  981. return self
  982. @classmethod
  983. def _init_default(
  984. cls, dialect, connection, dbapi_connection, execution_options
  985. ):
  986. """Initialize execution context for a ColumnDefault construct."""
  987. self = cls.__new__(cls)
  988. self.root_connection = connection
  989. self._dbapi_connection = dbapi_connection
  990. self.dialect = connection.dialect
  991. self.execution_options = execution_options
  992. self._is_future_result = (
  993. connection._is_future
  994. or self.execution_options.get("future_result", False)
  995. )
  996. self.cursor = self.create_cursor()
  997. return self
  998. def _get_cache_stats(self):
  999. if self.compiled is None:
  1000. return "raw sql"
  1001. now = util.perf_counter()
  1002. ch = self.cache_hit
  1003. if ch is NO_CACHE_KEY:
  1004. return "no key %.5fs" % (now - self.compiled._gen_time,)
  1005. elif ch is CACHE_HIT:
  1006. return "cached since %.4gs ago" % (now - self.compiled._gen_time,)
  1007. elif ch is CACHE_MISS:
  1008. return "generated in %.5fs" % (now - self.compiled._gen_time,)
  1009. elif ch is CACHING_DISABLED:
  1010. return "caching disabled %.5fs" % (now - self.compiled._gen_time,)
  1011. elif ch is NO_DIALECT_SUPPORT:
  1012. return "dialect %s+%s does not support caching %.5fs" % (
  1013. self.dialect.name,
  1014. self.dialect.driver,
  1015. now - self.compiled._gen_time,
  1016. )
  1017. else:
  1018. return "unknown"
  1019. @util.memoized_property
  1020. def identifier_preparer(self):
  1021. if self.compiled:
  1022. return self.compiled.preparer
  1023. elif "schema_translate_map" in self.execution_options:
  1024. return self.dialect.identifier_preparer._with_schema_translate(
  1025. self.execution_options["schema_translate_map"]
  1026. )
  1027. else:
  1028. return self.dialect.identifier_preparer
  1029. @util.memoized_property
  1030. def engine(self):
  1031. return self.root_connection.engine
  1032. @util.memoized_property
  1033. def postfetch_cols(self):
  1034. return self.compiled.postfetch
  1035. @util.memoized_property
  1036. def prefetch_cols(self):
  1037. if self.isinsert:
  1038. return self.compiled.insert_prefetch
  1039. elif self.isupdate:
  1040. return self.compiled.update_prefetch
  1041. else:
  1042. return ()
  1043. @util.memoized_property
  1044. def returning_cols(self):
  1045. self.compiled.returning
  1046. @util.memoized_property
  1047. def no_parameters(self):
  1048. return self.execution_options.get("no_parameters", False)
  1049. @util.memoized_property
  1050. def should_autocommit(self):
  1051. autocommit = self.execution_options.get(
  1052. "autocommit",
  1053. not self.compiled
  1054. and self.statement
  1055. and expression.PARSE_AUTOCOMMIT
  1056. or False,
  1057. )
  1058. if autocommit is expression.PARSE_AUTOCOMMIT:
  1059. return self.should_autocommit_text(self.unicode_statement)
  1060. else:
  1061. return autocommit
  1062. def _execute_scalar(self, stmt, type_, parameters=None):
  1063. """Execute a string statement on the current cursor, returning a
  1064. scalar result.
  1065. Used to fire off sequences, default phrases, and "select lastrowid"
  1066. types of statements individually or in the context of a parent INSERT
  1067. or UPDATE statement.
  1068. """
  1069. conn = self.root_connection
  1070. if (
  1071. isinstance(stmt, util.text_type)
  1072. and not self.dialect.supports_unicode_statements
  1073. ):
  1074. stmt = self.dialect._encoder(stmt)[0]
  1075. if "schema_translate_map" in self.execution_options:
  1076. schema_translate_map = self.execution_options.get(
  1077. "schema_translate_map", {}
  1078. )
  1079. rst = self.identifier_preparer._render_schema_translates
  1080. stmt = rst(stmt, schema_translate_map)
  1081. if not parameters:
  1082. if self.dialect.positional:
  1083. parameters = self.dialect.execute_sequence_format()
  1084. else:
  1085. parameters = {}
  1086. conn._cursor_execute(self.cursor, stmt, parameters, context=self)
  1087. r = self.cursor.fetchone()[0]
  1088. if type_ is not None:
  1089. # apply type post processors to the result
  1090. proc = type_._cached_result_processor(
  1091. self.dialect, self.cursor.description[0][1]
  1092. )
  1093. if proc:
  1094. return proc(r)
  1095. return r
  1096. @property
  1097. def connection(self):
  1098. conn = self.root_connection
  1099. if conn._is_future:
  1100. return conn
  1101. else:
  1102. return conn._branch()
  1103. def should_autocommit_text(self, statement):
  1104. return AUTOCOMMIT_REGEXP.match(statement)
  1105. def _use_server_side_cursor(self):
  1106. if not self.dialect.supports_server_side_cursors:
  1107. return False
  1108. if self.dialect.server_side_cursors:
  1109. # this is deprecated
  1110. use_server_side = self.execution_options.get(
  1111. "stream_results", True
  1112. ) and (
  1113. (
  1114. self.compiled
  1115. and isinstance(
  1116. self.compiled.statement, expression.Selectable
  1117. )
  1118. or (
  1119. (
  1120. not self.compiled
  1121. or isinstance(
  1122. self.compiled.statement, expression.TextClause
  1123. )
  1124. )
  1125. and self.unicode_statement
  1126. and SERVER_SIDE_CURSOR_RE.match(self.unicode_statement)
  1127. )
  1128. )
  1129. )
  1130. else:
  1131. use_server_side = self.execution_options.get(
  1132. "stream_results", False
  1133. )
  1134. return use_server_side
  1135. def create_cursor(self):
  1136. if (
  1137. # inlining initial preference checks for SS cursors
  1138. self.dialect.supports_server_side_cursors
  1139. and (
  1140. self.execution_options.get("stream_results", False)
  1141. or (
  1142. self.dialect.server_side_cursors
  1143. and self._use_server_side_cursor()
  1144. )
  1145. )
  1146. ):
  1147. self._is_server_side = True
  1148. return self.create_server_side_cursor()
  1149. else:
  1150. self._is_server_side = False
  1151. return self.create_default_cursor()
  1152. def create_default_cursor(self):
  1153. return self._dbapi_connection.cursor()
  1154. def create_server_side_cursor(self):
  1155. raise NotImplementedError()
  1156. def pre_exec(self):
  1157. pass
  1158. def get_out_parameter_values(self, names):
  1159. raise NotImplementedError(
  1160. "This dialect does not support OUT parameters"
  1161. )
  1162. def post_exec(self):
  1163. pass
  1164. def get_result_processor(self, type_, colname, coltype):
  1165. """Return a 'result processor' for a given type as present in
  1166. cursor.description.
  1167. This has a default implementation that dialects can override
  1168. for context-sensitive result type handling.
  1169. """
  1170. return type_._cached_result_processor(self.dialect, coltype)
  1171. def get_lastrowid(self):
  1172. """return self.cursor.lastrowid, or equivalent, after an INSERT.
  1173. This may involve calling special cursor functions, issuing a new SELECT
  1174. on the cursor (or a new one), or returning a stored value that was
  1175. calculated within post_exec().
  1176. This function will only be called for dialects which support "implicit"
  1177. primary key generation, keep preexecute_autoincrement_sequences set to
  1178. False, and when no explicit id value was bound to the statement.
  1179. The function is called once for an INSERT statement that would need to
  1180. return the last inserted primary key for those dialects that make use
  1181. of the lastrowid concept. In these cases, it is called directly after
  1182. :meth:`.ExecutionContext.post_exec`.
  1183. """
  1184. return self.cursor.lastrowid
  1185. def handle_dbapi_exception(self, e):
  1186. pass
  1187. @property
  1188. def rowcount(self):
  1189. return self.cursor.rowcount
  1190. def supports_sane_rowcount(self):
  1191. return self.dialect.supports_sane_rowcount
  1192. def supports_sane_multi_rowcount(self):
  1193. return self.dialect.supports_sane_multi_rowcount
  1194. def _setup_result_proxy(self):
  1195. exec_opt = self.execution_options
  1196. if self.is_crud or self.is_text:
  1197. result = self._setup_dml_or_text_result()
  1198. yp = sr = False
  1199. else:
  1200. yp = exec_opt.get("yield_per", None)
  1201. sr = self._is_server_side or exec_opt.get("stream_results", False)
  1202. strategy = self.cursor_fetch_strategy
  1203. if sr and strategy is _cursor._DEFAULT_FETCH:
  1204. strategy = _cursor.BufferedRowCursorFetchStrategy(
  1205. self.cursor, self.execution_options
  1206. )
  1207. cursor_description = (
  1208. strategy.alternate_cursor_description
  1209. or self.cursor.description
  1210. )
  1211. if cursor_description is None:
  1212. strategy = _cursor._NO_CURSOR_DQL
  1213. if self._is_future_result:
  1214. if self.root_connection.should_close_with_result:
  1215. raise exc.InvalidRequestError(
  1216. "can't use future_result=True with close_with_result"
  1217. )
  1218. result = _cursor.CursorResult(
  1219. self, strategy, cursor_description
  1220. )
  1221. else:
  1222. result = _cursor.LegacyCursorResult(
  1223. self, strategy, cursor_description
  1224. )
  1225. if (
  1226. self.compiled
  1227. and not self.isddl
  1228. and self.compiled.has_out_parameters
  1229. ):
  1230. self._setup_out_parameters(result)
  1231. self._soft_closed = result._soft_closed
  1232. if yp:
  1233. result = result.yield_per(yp)
  1234. return result
  1235. def _setup_out_parameters(self, result):
  1236. out_bindparams = [
  1237. (param, name)
  1238. for param, name in self.compiled.bind_names.items()
  1239. if param.isoutparam
  1240. ]
  1241. out_parameters = {}
  1242. for bindparam, raw_value in zip(
  1243. [param for param, name in out_bindparams],
  1244. self.get_out_parameter_values(
  1245. [name for param, name in out_bindparams]
  1246. ),
  1247. ):
  1248. type_ = bindparam.type
  1249. impl_type = type_.dialect_impl(self.dialect)
  1250. dbapi_type = impl_type.get_dbapi_type(self.dialect.dbapi)
  1251. result_processor = impl_type.result_processor(
  1252. self.dialect, dbapi_type
  1253. )
  1254. if result_processor is not None:
  1255. raw_value = result_processor(raw_value)
  1256. out_parameters[bindparam.key] = raw_value
  1257. result.out_parameters = out_parameters
  1258. def _setup_dml_or_text_result(self):
  1259. if self.isinsert:
  1260. if self.compiled.postfetch_lastrowid:
  1261. self.inserted_primary_key_rows = (
  1262. self._setup_ins_pk_from_lastrowid()
  1263. )
  1264. # else if not self._is_implicit_returning,
  1265. # the default inserted_primary_key_rows accessor will
  1266. # return an "empty" primary key collection when accessed.
  1267. strategy = self.cursor_fetch_strategy
  1268. if self._is_server_side and strategy is _cursor._DEFAULT_FETCH:
  1269. strategy = _cursor.BufferedRowCursorFetchStrategy(
  1270. self.cursor, self.execution_options
  1271. )
  1272. cursor_description = (
  1273. strategy.alternate_cursor_description or self.cursor.description
  1274. )
  1275. if cursor_description is None:
  1276. strategy = _cursor._NO_CURSOR_DML
  1277. if self._is_future_result:
  1278. result = _cursor.CursorResult(self, strategy, cursor_description)
  1279. else:
  1280. result = _cursor.LegacyCursorResult(
  1281. self, strategy, cursor_description
  1282. )
  1283. if self.isinsert:
  1284. if self._is_implicit_returning:
  1285. rows = result.all()
  1286. self.returned_default_rows = rows
  1287. self.inserted_primary_key_rows = (
  1288. self._setup_ins_pk_from_implicit_returning(result, rows)
  1289. )
  1290. # test that it has a cursor metadata that is accurate. the
  1291. # first row will have been fetched and current assumptions
  1292. # are that the result has only one row, until executemany()
  1293. # support is added here.
  1294. assert result._metadata.returns_rows
  1295. result._soft_close()
  1296. elif not self._is_explicit_returning:
  1297. result._soft_close()
  1298. # we assume here the result does not return any rows.
  1299. # *usually*, this will be true. However, some dialects
  1300. # such as that of MSSQL/pyodbc need to SELECT a post fetch
  1301. # function so this is not necessarily true.
  1302. # assert not result.returns_rows
  1303. elif self.isupdate and self._is_implicit_returning:
  1304. row = result.fetchone()
  1305. self.returned_default_rows = [row]
  1306. result._soft_close()
  1307. # test that it has a cursor metadata that is accurate.
  1308. # the rows have all been fetched however.
  1309. assert result._metadata.returns_rows
  1310. elif not result._metadata.returns_rows:
  1311. # no results, get rowcount
  1312. # (which requires open cursor on some drivers
  1313. # such as kintersbasdb, mxodbc)
  1314. result.rowcount
  1315. result._soft_close()
  1316. return result
  1317. @util.memoized_property
  1318. def inserted_primary_key_rows(self):
  1319. # if no specific "get primary key" strategy was set up
  1320. # during execution, return a "default" primary key based
  1321. # on what's in the compiled_parameters and nothing else.
  1322. return self._setup_ins_pk_from_empty()
  1323. def _setup_ins_pk_from_lastrowid(self):
  1324. getter = self.compiled._inserted_primary_key_from_lastrowid_getter
  1325. lastrowid = self.get_lastrowid()
  1326. return [getter(lastrowid, self.compiled_parameters[0])]
  1327. def _setup_ins_pk_from_empty(self):
  1328. getter = self.compiled._inserted_primary_key_from_lastrowid_getter
  1329. return [getter(None, param) for param in self.compiled_parameters]
  1330. def _setup_ins_pk_from_implicit_returning(self, result, rows):
  1331. if not rows:
  1332. return []
  1333. getter = self.compiled._inserted_primary_key_from_returning_getter
  1334. compiled_params = self.compiled_parameters
  1335. return [
  1336. getter(row, param) for row, param in zip(rows, compiled_params)
  1337. ]
  1338. def lastrow_has_defaults(self):
  1339. return (self.isinsert or self.isupdate) and bool(
  1340. self.compiled.postfetch
  1341. )
  1342. def _set_input_sizes(self):
  1343. """Given a cursor and ClauseParameters, call the appropriate
  1344. style of ``setinputsizes()`` on the cursor, using DB-API types
  1345. from the bind parameter's ``TypeEngine`` objects.
  1346. This method only called by those dialects which require it,
  1347. currently cx_oracle, asyncpg and pg8000.
  1348. """
  1349. if self.isddl or self.is_text:
  1350. return
  1351. inputsizes = self.compiled._get_set_input_sizes_lookup(
  1352. include_types=self.include_set_input_sizes,
  1353. exclude_types=self.exclude_set_input_sizes,
  1354. )
  1355. if inputsizes is None:
  1356. return
  1357. if self.dialect._has_events:
  1358. inputsizes = dict(inputsizes)
  1359. self.dialect.dispatch.do_setinputsizes(
  1360. inputsizes, self.cursor, self.statement, self.parameters, self
  1361. )
  1362. has_escaped_names = bool(self.compiled.escaped_bind_names)
  1363. if has_escaped_names:
  1364. escaped_bind_names = self.compiled.escaped_bind_names
  1365. if self.dialect.positional:
  1366. items = [
  1367. (key, self.compiled.binds[key])
  1368. for key in self.compiled.positiontup
  1369. ]
  1370. else:
  1371. items = [
  1372. (key, bindparam)
  1373. for bindparam, key in self.compiled.bind_names.items()
  1374. ]
  1375. generic_inputsizes = []
  1376. for key, bindparam in items:
  1377. if bindparam in self.compiled.literal_execute_params:
  1378. continue
  1379. if key in self._expanded_parameters:
  1380. if bindparam.type._is_tuple_type:
  1381. num = len(bindparam.type.types)
  1382. dbtypes = inputsizes[bindparam]
  1383. generic_inputsizes.extend(
  1384. (
  1385. (
  1386. escaped_bind_names.get(paramname, paramname)
  1387. if has_escaped_names
  1388. else paramname
  1389. ),
  1390. dbtypes[idx % num],
  1391. bindparam.type.types[idx % num],
  1392. )
  1393. for idx, paramname in enumerate(
  1394. self._expanded_parameters[key]
  1395. )
  1396. )
  1397. else:
  1398. dbtype = inputsizes.get(bindparam, None)
  1399. generic_inputsizes.extend(
  1400. (
  1401. (
  1402. escaped_bind_names.get(paramname, paramname)
  1403. if has_escaped_names
  1404. else paramname
  1405. ),
  1406. dbtype,
  1407. bindparam.type,
  1408. )
  1409. for paramname in self._expanded_parameters[key]
  1410. )
  1411. else:
  1412. dbtype = inputsizes.get(bindparam, None)
  1413. escaped_name = (
  1414. escaped_bind_names.get(key, key)
  1415. if has_escaped_names
  1416. else key
  1417. )
  1418. generic_inputsizes.append(
  1419. (escaped_name, dbtype, bindparam.type)
  1420. )
  1421. try:
  1422. self.dialect.do_set_input_sizes(
  1423. self.cursor, generic_inputsizes, self
  1424. )
  1425. except BaseException as e:
  1426. self.root_connection._handle_dbapi_exception(
  1427. e, None, None, None, self
  1428. )
  1429. def _exec_default(self, column, default, type_):
  1430. if default.is_sequence:
  1431. return self.fire_sequence(default, type_)
  1432. elif default.is_callable:
  1433. self.current_column = column
  1434. return default.arg(self)
  1435. elif default.is_clause_element:
  1436. return self._exec_default_clause_element(column, default, type_)
  1437. else:
  1438. return default.arg
  1439. def _exec_default_clause_element(self, column, default, type_):
  1440. # execute a default that's a complete clause element. Here, we have
  1441. # to re-implement a miniature version of the compile->parameters->
  1442. # cursor.execute() sequence, since we don't want to modify the state
  1443. # of the connection / result in progress or create new connection/
  1444. # result objects etc.
  1445. # .. versionchanged:: 1.4
  1446. if not default._arg_is_typed:
  1447. default_arg = expression.type_coerce(default.arg, type_)
  1448. else:
  1449. default_arg = default.arg
  1450. compiled = expression.select(default_arg).compile(dialect=self.dialect)
  1451. compiled_params = compiled.construct_params()
  1452. processors = compiled._bind_processors
  1453. if compiled.positional:
  1454. positiontup = compiled.positiontup
  1455. parameters = self.dialect.execute_sequence_format(
  1456. [
  1457. processors[key](compiled_params[key])
  1458. if key in processors
  1459. else compiled_params[key]
  1460. for key in positiontup
  1461. ]
  1462. )
  1463. else:
  1464. parameters = dict(
  1465. (
  1466. key,
  1467. processors[key](compiled_params[key])
  1468. if key in processors
  1469. else compiled_params[key],
  1470. )
  1471. for key in compiled_params
  1472. )
  1473. return self._execute_scalar(
  1474. util.text_type(compiled), type_, parameters=parameters
  1475. )
  1476. current_parameters = None
  1477. """A dictionary of parameters applied to the current row.
  1478. This attribute is only available in the context of a user-defined default
  1479. generation function, e.g. as described at :ref:`context_default_functions`.
  1480. It consists of a dictionary which includes entries for each column/value
  1481. pair that is to be part of the INSERT or UPDATE statement. The keys of the
  1482. dictionary will be the key value of each :class:`_schema.Column`,
  1483. which is usually
  1484. synonymous with the name.
  1485. Note that the :attr:`.DefaultExecutionContext.current_parameters` attribute
  1486. does not accommodate for the "multi-values" feature of the
  1487. :meth:`_expression.Insert.values` method. The
  1488. :meth:`.DefaultExecutionContext.get_current_parameters` method should be
  1489. preferred.
  1490. .. seealso::
  1491. :meth:`.DefaultExecutionContext.get_current_parameters`
  1492. :ref:`context_default_functions`
  1493. """
  1494. def get_current_parameters(self, isolate_multiinsert_groups=True):
  1495. """Return a dictionary of parameters applied to the current row.
  1496. This method can only be used in the context of a user-defined default
  1497. generation function, e.g. as described at
  1498. :ref:`context_default_functions`. When invoked, a dictionary is
  1499. returned which includes entries for each column/value pair that is part
  1500. of the INSERT or UPDATE statement. The keys of the dictionary will be
  1501. the key value of each :class:`_schema.Column`,
  1502. which is usually synonymous
  1503. with the name.
  1504. :param isolate_multiinsert_groups=True: indicates that multi-valued
  1505. INSERT constructs created using :meth:`_expression.Insert.values`
  1506. should be
  1507. handled by returning only the subset of parameters that are local
  1508. to the current column default invocation. When ``False``, the
  1509. raw parameters of the statement are returned including the
  1510. naming convention used in the case of multi-valued INSERT.
  1511. .. versionadded:: 1.2 added
  1512. :meth:`.DefaultExecutionContext.get_current_parameters`
  1513. which provides more functionality over the existing
  1514. :attr:`.DefaultExecutionContext.current_parameters`
  1515. attribute.
  1516. .. seealso::
  1517. :attr:`.DefaultExecutionContext.current_parameters`
  1518. :ref:`context_default_functions`
  1519. """
  1520. try:
  1521. parameters = self.current_parameters
  1522. column = self.current_column
  1523. except AttributeError:
  1524. raise exc.InvalidRequestError(
  1525. "get_current_parameters() can only be invoked in the "
  1526. "context of a Python side column default function"
  1527. )
  1528. compile_state = self.compiled.compile_state
  1529. if (
  1530. isolate_multiinsert_groups
  1531. and self.isinsert
  1532. and compile_state._has_multi_parameters
  1533. ):
  1534. if column._is_multiparam_column:
  1535. index = column.index + 1
  1536. d = {column.original.key: parameters[column.key]}
  1537. else:
  1538. d = {column.key: parameters[column.key]}
  1539. index = 0
  1540. keys = compile_state._dict_parameters.keys()
  1541. d.update(
  1542. (key, parameters["%s_m%d" % (key, index)]) for key in keys
  1543. )
  1544. return d
  1545. else:
  1546. return parameters
  1547. def get_insert_default(self, column):
  1548. if column.default is None:
  1549. return None
  1550. else:
  1551. return self._exec_default(column, column.default, column.type)
  1552. def get_update_default(self, column):
  1553. if column.onupdate is None:
  1554. return None
  1555. else:
  1556. return self._exec_default(column, column.onupdate, column.type)
  1557. def _process_executemany_defaults(self):
  1558. key_getter = self.compiled._within_exec_param_key_getter
  1559. scalar_defaults = {}
  1560. insert_prefetch = self.compiled.insert_prefetch
  1561. update_prefetch = self.compiled.update_prefetch
  1562. # pre-determine scalar Python-side defaults
  1563. # to avoid many calls of get_insert_default()/
  1564. # get_update_default()
  1565. for c in insert_prefetch:
  1566. if c.default and not c.default.is_sequence and c.default.is_scalar:
  1567. scalar_defaults[c] = c.default.arg
  1568. for c in update_prefetch:
  1569. if c.onupdate and c.onupdate.is_scalar:
  1570. scalar_defaults[c] = c.onupdate.arg
  1571. for param in self.compiled_parameters:
  1572. self.current_parameters = param
  1573. for c in insert_prefetch:
  1574. if c in scalar_defaults:
  1575. val = scalar_defaults[c]
  1576. else:
  1577. val = self.get_insert_default(c)
  1578. if val is not None:
  1579. param[key_getter(c)] = val
  1580. for c in update_prefetch:
  1581. if c in scalar_defaults:
  1582. val = scalar_defaults[c]
  1583. else:
  1584. val = self.get_update_default(c)
  1585. if val is not None:
  1586. param[key_getter(c)] = val
  1587. del self.current_parameters
  1588. def _process_executesingle_defaults(self):
  1589. key_getter = self.compiled._within_exec_param_key_getter
  1590. self.current_parameters = (
  1591. compiled_parameters
  1592. ) = self.compiled_parameters[0]
  1593. for c in self.compiled.insert_prefetch:
  1594. if c.default and not c.default.is_sequence and c.default.is_scalar:
  1595. val = c.default.arg
  1596. else:
  1597. val = self.get_insert_default(c)
  1598. if val is not None:
  1599. compiled_parameters[key_getter(c)] = val
  1600. for c in self.compiled.update_prefetch:
  1601. val = self.get_update_default(c)
  1602. if val is not None:
  1603. compiled_parameters[key_getter(c)] = val
  1604. del self.current_parameters
  1605. DefaultDialect.execution_ctx_cls = DefaultExecutionContext