default.py 66 KB

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