You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1887 lines
63KB

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