Team Ai
Datasetpublic

codekingpro/portable-devtools

sourceHugging Faceupdated 5mo agoView on Hugging Face
1likes15kdownloads
default.py2395 linesDownload Raw Back to engine
1# engine/default.py
2# Copyright (C) 2005-2026 the SQLAlchemy authors and contributors
3# <see AUTHORS file>
4#
5# This module is part of SQLAlchemy and is released under
6# the MIT License: https://www.opensource.org/licenses/mit-license.php
7# mypy: allow-untyped-defs, allow-untyped-calls
8
9"""Default implementations of per-dialect sqlalchemy.engine classes.
10
11These are semi-private implementation classes which are only of importance
12to database dialect authors; dialects will usually use the classes here
13as the base class for their own corresponding classes.
14
15"""
16
17from __future__ import annotations
18
19import functools
20import operator
21import random
22import re
23from time import perf_counter
24import typing
25from typing import Any
26from typing import Callable
27from typing import cast
28from typing import Dict
29from typing import List
30from typing import Mapping
31from typing import MutableMapping
32from typing import MutableSequence
33from typing import Optional
34from typing import Sequence
35from typing import Set
36from typing import Tuple
37from typing import Type
38from typing import TYPE_CHECKING
39from typing import Union
40import weakref
41
42from . import characteristics
43from . import cursor as _cursor
44from . import interfaces
45from .base import Connection
46from .interfaces import CacheStats
47from .interfaces import DBAPICursor
48from .interfaces import Dialect
49from .interfaces import ExecuteStyle
50from .interfaces import ExecutionContext
51from .reflection import ObjectKind
52from .reflection import ObjectScope
53from .. import event
54from .. import exc
55from .. import pool
56from .. import util
57from ..sql import compiler
58from ..sql import dml
59from ..sql import expression
60from ..sql import type_api
61from ..sql import util as sql_util
62from ..sql._typing import is_tuple_type
63from ..sql.base import _NoArg
64from ..sql.compiler import DDLCompiler
65from ..sql.compiler import InsertmanyvaluesSentinelOpts
66from ..sql.compiler import SQLCompiler
67from ..sql.elements import quoted_name
68from ..util.typing import Final
69from ..util.typing import Literal
70
71if typing.TYPE_CHECKING:
72    from types import ModuleType
73
74    from .base import Engine
75    from .cursor import ResultFetchStrategy
76    from .interfaces import _CoreMultiExecuteParams
77    from .interfaces import _CoreSingleExecuteParams
78    from .interfaces import _DBAPICursorDescription
79    from .interfaces import _DBAPIMultiExecuteParams
80    from .interfaces import _DBAPISingleExecuteParams
81    from .interfaces import _ExecuteOptions
82    from .interfaces import _MutableCoreSingleExecuteParams
83    from .interfaces import _ParamStyle
84    from .interfaces import ConnectArgsType
85    from .interfaces import DBAPIConnection
86    from .interfaces import DBAPIModule
87    from .interfaces import DBAPIType
88    from .interfaces import IsolationLevel
89    from .row import Row
90    from .url import URL
91    from ..event import _ListenerFnType
92    from ..pool import Pool
93    from ..pool import PoolProxiedConnection
94    from ..sql import Executable
95    from ..sql.compiler import Compiled
96    from ..sql.compiler import Linting
97    from ..sql.compiler import ResultColumnsEntry
98    from ..sql.dml import DMLState
99    from ..sql.dml import UpdateBase
100    from ..sql.elements import BindParameter
101    from ..sql.schema import Column
102    from ..sql.type_api import _BindProcessorType
103    from ..sql.type_api import _ResultProcessorType
104    from ..sql.type_api import TypeEngine
105
106
107# When we're handed literal SQL, ensure it's a SELECT query
108SERVER_SIDE_CURSOR_RE = re.compile(r"\s*SELECT", re.I | re.UNICODE)
109
110
111(
112    CACHE_HIT,
113    CACHE_MISS,
114    CACHING_DISABLED,
115    NO_CACHE_KEY,
116    NO_DIALECT_SUPPORT,
117) = list(CacheStats)
118
119
120class DefaultDialect(Dialect):
121    """Default implementation of Dialect"""
122
123    statement_compiler = compiler.SQLCompiler
124    ddl_compiler = compiler.DDLCompiler
125    type_compiler_cls = compiler.GenericTypeCompiler
126
127    preparer = compiler.IdentifierPreparer
128    supports_alter = True
129    supports_comments = False
130    supports_constraint_comments = False
131    inline_comments = False
132    supports_statement_cache = True
133
134    div_is_floordiv = True
135
136    bind_typing = interfaces.BindTyping.NONE
137
138    include_set_input_sizes: Optional[Set[Any]] = None
139    exclude_set_input_sizes: Optional[Set[Any]] = None
140
141    # the first value we'd get for an autoincrement column.
142    default_sequence_base = 1
143
144    # most DBAPIs happy with this for execute().
145    # not cx_oracle.
146    execute_sequence_format = tuple
147
148    supports_schemas = True
149    supports_views = True
150    supports_sequences = False
151    sequences_optional = False
152    preexecute_autoincrement_sequences = False
153    supports_identity_columns = False
154    postfetch_lastrowid = True
155    favor_returning_over_lastrowid = False
156    insert_null_pk_still_autoincrements = False
157    update_returning = False
158    delete_returning = False
159    update_returning_multifrom = False
160    delete_returning_multifrom = False
161    insert_returning = False
162
163    cte_follows_insert = False
164
165    supports_native_enum = False
166    supports_native_boolean = False
167    supports_native_uuid = False
168    returns_native_bytes = False
169
170    non_native_boolean_check_constraint = True
171
172    supports_simple_order_by_label = True
173
174    tuple_in_values = False
175
176    connection_characteristics = util.immutabledict(
177        {
178            "isolation_level": characteristics.IsolationLevelCharacteristic(),
179            "logging_token": characteristics.LoggingTokenCharacteristic(),
180        }
181    )
182
183    engine_config_types: Mapping[str, Any] = util.immutabledict(
184        {
185            "pool_timeout": util.asint,
186            "echo": util.bool_or_str("debug"),
187            "echo_pool": util.bool_or_str("debug"),
188            "pool_recycle": util.asint,
189            "pool_size": util.asint,
190            "max_overflow": util.asint,
191            "future": util.asbool,
192        }
193    )
194
195    # if the NUMERIC type
196    # returns decimal.Decimal.
197    # *not* the FLOAT type however.
198    supports_native_decimal = False
199
200    name = "default"
201
202    # length at which to truncate
203    # any identifier.
204    max_identifier_length = 9999
205    _user_defined_max_identifier_length: Optional[int] = None
206
207    isolation_level: Optional[str] = None
208
209    # sub-categories of max_identifier_length.
210    # currently these accommodate for MySQL which allows alias names
211    # of 255 but DDL names only of 64.
212    max_index_name_length: Optional[int] = None
213    max_constraint_name_length: Optional[int] = None
214
215    supports_sane_rowcount = True
216    supports_sane_multi_rowcount = True
217    colspecs: MutableMapping[Type[TypeEngine[Any]], Type[TypeEngine[Any]]] = {}
218    default_paramstyle = "named"
219
220    supports_default_values = False
221    """dialect supports INSERT... DEFAULT VALUES syntax"""
222
223    supports_default_metavalue = False
224    """dialect supports INSERT... VALUES (DEFAULT) syntax"""
225
226    default_metavalue_token = "DEFAULT"
227    """for INSERT... VALUES (DEFAULT) syntax, the token to put in the
228    parenthesis."""
229
230    # not sure if this is a real thing but the compiler will deliver it
231    # if this is the only flag enabled.
232    supports_empty_insert = True
233    """dialect supports INSERT () VALUES ()"""
234
235    supports_multivalues_insert = False
236
237    use_insertmanyvalues: bool = False
238
239    use_insertmanyvalues_wo_returning: bool = False
240
241    insertmanyvalues_implicit_sentinel: InsertmanyvaluesSentinelOpts = (
242        InsertmanyvaluesSentinelOpts.NOT_SUPPORTED
243    )
244
245    insertmanyvalues_page_size: int = 1000
246    insertmanyvalues_max_parameters = 32700
247
248    supports_is_distinct_from = True
249
250    supports_server_side_cursors = False
251
252    server_side_cursors = False
253
254    # extra record-level locking features (#4860)
255    supports_for_update_of = False
256
257    server_version_info = None
258
259    default_schema_name: Optional[str] = None
260
261    # indicates symbol names are
262    # UPPERCASED if they are case insensitive
263    # within the database.
264    # if this is True, the methods normalize_name()
265    # and denormalize_name() must be provided.
266    requires_name_normalize = False
267
268    is_async = False
269
270    has_terminate = False
271
272    # TODO: this is not to be part of 2.0.  implement rudimentary binary
273    # literals for SQLite, PostgreSQL, MySQL only within
274    # _Binary.literal_processor
275    _legacy_binary_type_literal_encoding = "utf-8"
276
277    @util.deprecated_params(
278        empty_in_strategy=(
279            "1.4",
280            "The :paramref:`_sa.create_engine.empty_in_strategy` keyword is "
281            "deprecated, and no longer has any effect.  All IN expressions "
282            "are now rendered using "
283            'the "expanding parameter" strategy which renders a set of bound'
284            'expressions, or an "empty set" SELECT, at statement execution'
285            "time.",
286        ),
287        server_side_cursors=(
288            "1.4",
289            "The :paramref:`_sa.create_engine.server_side_cursors` parameter "
290            "is deprecated and will be removed in a future release.  Please "
291            "use the "
292            ":paramref:`_engine.Connection.execution_options.stream_results` "
293            "parameter.",
294        ),
295    )
296    def __init__(
297        self,
298        paramstyle: Optional[_ParamStyle] = None,
299        isolation_level: Optional[IsolationLevel] = None,
300        dbapi: Optional[ModuleType] = None,
301        implicit_returning: Literal[True] = True,
302        supports_native_boolean: Optional[bool] = None,
303        max_identifier_length: Optional[int] = None,
304        label_length: Optional[int] = None,
305        insertmanyvalues_page_size: Union[_NoArg, int] = _NoArg.NO_ARG,
306        use_insertmanyvalues: Optional[bool] = None,
307        # util.deprecated_params decorator cannot render the
308        # Linting.NO_LINTING constant
309        compiler_linting: Linting = int(compiler.NO_LINTING),  # type: ignore
310        server_side_cursors: bool = False,
311        skip_autocommit_rollback: bool = False,
312        **kwargs: Any,
313    ):
314        if server_side_cursors:
315            if not self.supports_server_side_cursors:
316                raise exc.ArgumentError(
317                    "Dialect %s does not support server side cursors" % self
318                )
319            else:
320                self.server_side_cursors = True
321
322        if getattr(self, "use_setinputsizes", False):
323            util.warn_deprecated(
324                "The dialect-level use_setinputsizes attribute is "
325                "deprecated.  Please use "
326                "bind_typing = BindTyping.SETINPUTSIZES",
327                "2.0",
328            )
329            self.bind_typing = interfaces.BindTyping.SETINPUTSIZES
330
331        self.positional = False
332        self._ischema = None
333
334        self.dbapi = dbapi
335
336        self.skip_autocommit_rollback = skip_autocommit_rollback
337
338        if paramstyle is not None:
339            self.paramstyle = paramstyle
340        elif self.dbapi is not None:
341            self.paramstyle = self.dbapi.paramstyle
342        else:
343            self.paramstyle = self.default_paramstyle
344        self.positional = self.paramstyle in (
345            "qmark",
346            "format",
347            "numeric",
348            "numeric_dollar",
349        )
350        self.identifier_preparer = self.preparer(self)
351        self._on_connect_isolation_level = isolation_level
352
353        legacy_tt_callable = getattr(self, "type_compiler", None)
354        if legacy_tt_callable is not None:
355            tt_callable = cast(
356                Type[compiler.GenericTypeCompiler],
357                self.type_compiler,
358            )
359        else:
360            tt_callable = self.type_compiler_cls
361
362        self.type_compiler_instance = self.type_compiler = tt_callable(self)
363
364        if supports_native_boolean is not None:
365            self.supports_native_boolean = supports_native_boolean
366
367        self._user_defined_max_identifier_length = max_identifier_length
368        if self._user_defined_max_identifier_length:
369            self.max_identifier_length = (
370                self._user_defined_max_identifier_length
371            )
372        self.label_length = label_length
373        self.compiler_linting = compiler_linting
374
375        if use_insertmanyvalues is not None:
376            self.use_insertmanyvalues = use_insertmanyvalues
377
378        if insertmanyvalues_page_size is not _NoArg.NO_ARG:
379            self.insertmanyvalues_page_size = insertmanyvalues_page_size
380
381    @property
382    @util.deprecated(
383        "2.0",
384        "full_returning is deprecated, please use insert_returning, "
385        "update_returning, delete_returning",
386    )
387    def full_returning(self):
388        return (
389            self.insert_returning
390            and self.update_returning
391            and self.delete_returning
392        )
393
394    @util.memoized_property
395    def insert_executemany_returning(self):
396        """Default implementation for insert_executemany_returning, if not
397        otherwise overridden by the specific dialect.
398
399        The default dialect determines "insert_executemany_returning" is
400        available if the dialect in use has opted into using the
401        "use_insertmanyvalues" feature. If they haven't opted into that, then
402        this attribute is False, unless the dialect in question overrides this
403        and provides some other implementation (such as the Oracle Database
404        dialects).
405
406        """
407        return self.insert_returning and self.use_insertmanyvalues
408
409    @util.memoized_property
410    def insert_executemany_returning_sort_by_parameter_order(self):
411        """Default implementation for
412        insert_executemany_returning_deterministic_order, if not otherwise
413        overridden by the specific dialect.
414
415        The default dialect determines "insert_executemany_returning" can have
416        deterministic order only if the dialect in use has opted into using the
417        "use_insertmanyvalues" feature, which implements deterministic ordering
418        using client side sentinel columns only by default.  The
419        "insertmanyvalues" feature also features alternate forms that can
420        use server-generated PK values as "sentinels", but those are only
421        used if the :attr:`.Dialect.insertmanyvalues_implicit_sentinel`
422        bitflag enables those alternate SQL forms, which are disabled
423        by default.
424
425        If the dialect in use hasn't opted into that, then this attribute is
426        False, unless the dialect in question overrides this and provides some
427        other implementation (such as the Oracle Database dialects).
428
429        """
430        return self.insert_returning and self.use_insertmanyvalues
431
432    update_executemany_returning = False
433    delete_executemany_returning = False
434
435    @util.memoized_property
436    def loaded_dbapi(self) -> DBAPIModule:
437        if self.dbapi is None:
438            raise exc.InvalidRequestError(
439                f"Dialect {self} does not have a Python DBAPI established "
440                "and cannot be used for actual database interaction"
441            )
442        return self.dbapi
443
444    @util.memoized_property
445    def _bind_typing_render_casts(self):
446        return self.bind_typing is interfaces.BindTyping.RENDER_CASTS
447
448    def _ensure_has_table_connection(self, arg: Connection) -> None:
449        if not isinstance(arg, Connection):
450            raise exc.ArgumentError(
451                "The argument passed to Dialect.has_table() should be a "
452                "%s, got %s. "
453                "Additionally, the Dialect.has_table() method is for "
454                "internal dialect "
455                "use only; please use "
456                "``inspect(some_engine).has_table(<tablename>>)`` "
457                "for public API use." % (Connection, type(arg))
458            )
459
460    @util.memoized_property
461    def _supports_statement_cache(self):
462        ssc = self.__class__.__dict__.get("supports_statement_cache", None)
463        if ssc is None:
464            util.warn(
465                "Dialect %s:%s will not make use of SQL compilation caching "
466                "as it does not set the 'supports_statement_cache' attribute "
467                "to ``True``.  This can have "
468                "significant performance implications including some "
469                "performance degradations in comparison to prior SQLAlchemy "
470                "versions.  Dialect maintainers should seek to set this "
471                "attribute to True after appropriate development and testing "
472                "for SQLAlchemy 1.4 caching support.   Alternatively, this "
473                "attribute may be set to False which will disable this "
474                "warning." % (self.name, self.driver),
475                code="cprf",
476            )
477
478        return bool(ssc)
479
480    @util.memoized_property
481    def _type_memos(self):
482        return weakref.WeakKeyDictionary()
483
484    @property
485    def dialect_description(self):  # type: ignore[override]
486        return self.name + "+" + self.driver
487
488    @property
489    def supports_sane_rowcount_returning(self):
490        """True if this dialect supports sane rowcount even if RETURNING is
491        in use.
492
493        For dialects that don't support RETURNING, this is synonymous with
494        ``supports_sane_rowcount``.
495
496        """
497        return self.supports_sane_rowcount
498
499    @classmethod
500    def get_pool_class(cls, url: URL) -> Type[Pool]:
501        return getattr(cls, "poolclass", pool.QueuePool)
502
503    def get_dialect_pool_class(self, url: URL) -> Type[Pool]:
504        return self.get_pool_class(url)
505
506    @classmethod
507    def load_provisioning(cls):
508        package = ".".join(cls.__module__.split(".")[0:-1])
509        try:
510            __import__(package + ".provision")
511        except ImportError:
512            pass
513
514    def _builtin_onconnect(self) -> Optional[_ListenerFnType]:
515        if self._on_connect_isolation_level is not None:
516
517            def builtin_connect(dbapi_conn, conn_rec):
518                self._assert_and_set_isolation_level(
519                    dbapi_conn, self._on_connect_isolation_level
520                )
521
522            return builtin_connect
523        else:
524            return None
525
526    def initialize(self, connection: Connection) -> None:
527        try:
528            self.server_version_info = self._get_server_version_info(
529                connection
530            )
531        except NotImplementedError:
532            self.server_version_info = None
533        try:
534            self.default_schema_name = self._get_default_schema_name(
535                connection
536            )
537        except NotImplementedError:
538            self.default_schema_name = None
539
540        try:
541            self.default_isolation_level = self.get_default_isolation_level(
542                connection.connection.dbapi_connection
543            )
544        except NotImplementedError:
545            self.default_isolation_level = None
546
547        if not self._user_defined_max_identifier_length:
548            max_ident_length = self._check_max_identifier_length(connection)
549            if max_ident_length:
550                self.max_identifier_length = max_ident_length
551
552        if (
553            self.label_length
554            and self.label_length > self.max_identifier_length
555        ):
556            raise exc.ArgumentError(
557                "Label length of %d is greater than this dialect's"
558                " maximum identifier length of %d"
559                % (self.label_length, self.max_identifier_length)
560            )
561
562    def on_connect(self) -> Optional[Callable[[Any], None]]:
563        # inherits the docstring from interfaces.Dialect.on_connect
564        return None
565
566    def _check_max_identifier_length(self, connection):
567        """Perform a connection / server version specific check to determine
568        the max_identifier_length.
569
570        If the dialect's class level max_identifier_length should be used,
571        can return None.
572
573        .. versionadded:: 1.3.9
574
575        """
576        return None
577
578    def get_default_isolation_level(self, dbapi_conn):
579        """Given a DBAPI connection, return its isolation level, or
580        a default isolation level if one cannot be retrieved.
581
582        May be overridden by subclasses in order to provide a
583        "fallback" isolation level for databases that cannot reliably
584        retrieve the actual isolation level.
585
586        By default, calls the :meth:`_engine.Interfaces.get_isolation_level`
587        method, propagating any exceptions raised.
588
589        .. versionadded:: 1.3.22
590
591        """
592        return self.get_isolation_level(dbapi_conn)
593
594    def type_descriptor(self, typeobj):
595        """Provide a database-specific :class:`.TypeEngine` object, given
596        the generic object which comes from the types module.
597
598        This method looks for a dictionary called
599        ``colspecs`` as a class or instance-level variable,
600        and passes on to :func:`_types.adapt_type`.
601
602        """
603        return type_api.adapt_type(typeobj, self.colspecs)
604
605    def has_index(self, connection, table_name, index_name, schema=None, **kw):
606        if not self.has_table(connection, table_name, schema=schema, **kw):
607            return False
608        for idx in self.get_indexes(
609            connection, table_name, schema=schema, **kw
610        ):
611            if idx["name"] == index_name:
612                return True
613        else:
614            return False
615
616    def has_schema(
617        self, connection: Connection, schema_name: str, **kw: Any
618    ) -> bool:
619        return schema_name in self.get_schema_names(connection, **kw)
620
621    def validate_identifier(self, ident: str) -> None:
622        if len(ident) > self.max_identifier_length:
623            raise exc.IdentifierError(
624                "Identifier '%s' exceeds maximum length of %d characters"
625                % (ident, self.max_identifier_length)
626            )
627
628    def connect(self, *cargs: Any, **cparams: Any) -> DBAPIConnection:
629        # inherits the docstring from interfaces.Dialect.connect
630        return self.loaded_dbapi.connect(*cargs, **cparams)  # type: ignore[no-any-return]  # NOQA: E501
631
632    def create_connect_args(self, url: URL) -> ConnectArgsType:
633        # inherits the docstring from interfaces.Dialect.create_connect_args
634        opts = url.translate_connect_args()
635        opts.update(url.query)
636        return ([], opts)
637
638    def set_engine_execution_options(
639        self, engine: Engine, opts: Mapping[str, Any]
640    ) -> None:
641        supported_names = set(self.connection_characteristics).intersection(
642            opts
643        )
644        if supported_names:
645            characteristics: Mapping[str, Any] = util.immutabledict(
646                (name, opts[name]) for name in supported_names
647            )
648
649            @event.listens_for(engine, "engine_connect")
650            def set_connection_characteristics(connection):
651                self._set_connection_characteristics(
652                    connection, characteristics
653                )
654
655    def set_connection_execution_options(
656        self, connection: Connection, opts: Mapping[str, Any]
657    ) -> None:
658        supported_names = set(self.connection_characteristics).intersection(
659            opts
660        )
661        if supported_names:
662            characteristics: Mapping[str, Any] = util.immutabledict(
663                (name, opts[name]) for name in supported_names
664            )
665            self._set_connection_characteristics(connection, characteristics)
666
667    def _set_connection_characteristics(self, connection, characteristics):
668        characteristic_values = [
669            (name, self.connection_characteristics[name], value)
670            for name, value in characteristics.items()
671        ]
672
673        if connection.in_transaction():
674            trans_objs = [
675                (name, obj)
676                for name, obj, _ in characteristic_values
677                if obj.transactional
678            ]
679            if trans_objs:
680                raise exc.InvalidRequestError(
681                    "This connection has already initialized a SQLAlchemy "
682                    "Transaction() object via begin() or autobegin; "
683                    "%s may not be altered unless rollback() or commit() "
684                    "is called first."
685                    % (", ".join(name for name, obj in trans_objs))
686                )
687
688        dbapi_connection = connection.connection.dbapi_connection
689        for _, characteristic, value in characteristic_values:
690            characteristic.set_connection_characteristic(
691                self, connection, dbapi_connection, value
692            )
693        connection.connection._connection_record.finalize_callback.append(
694            functools.partial(self._reset_characteristics, characteristics)
695        )
696
697    def _reset_characteristics(self, characteristics, dbapi_connection):
698        for characteristic_name in characteristics:
699            characteristic = self.connection_characteristics[
700                characteristic_name
701            ]
702            characteristic.reset_characteristic(self, dbapi_connection)
703
704    def do_begin(self, dbapi_connection):
705        pass
706
707    def do_rollback(self, dbapi_connection):
708        if self.skip_autocommit_rollback and self.detect_autocommit_setting(
709            dbapi_connection
710        ):
711            return
712        dbapi_connection.rollback()
713
714    def do_commit(self, dbapi_connection):
715        dbapi_connection.commit()
716
717    def do_terminate(self, dbapi_connection):
718        self.do_close(dbapi_connection)
719
720    def do_close(self, dbapi_connection):
721        dbapi_connection.close()
722
723    @util.memoized_property
724    def _dialect_specific_select_one(self):
725        return str(expression.select(1).compile(dialect=self))
726
727    def _do_ping_w_event(self, dbapi_connection: DBAPIConnection) -> bool:
728        try:
729            return self.do_ping(dbapi_connection)
730        except self.loaded_dbapi.Error as err:
731            is_disconnect = self.is_disconnect(err, dbapi_connection, None)
732
733            if self._has_events:
734                try:
735                    Connection._handle_dbapi_exception_noconnection(
736                        err,
737                        self,
738                        is_disconnect=is_disconnect,
739                        invalidate_pool_on_disconnect=False,
740                        is_pre_ping=True,
741                    )
742                except exc.StatementError as new_err:
743                    is_disconnect = new_err.connection_invalidated
744
745            if is_disconnect:
746                return False
747            else:
748                raise
749
750    def do_ping(self, dbapi_connection: DBAPIConnection) -> bool:
751        cursor = dbapi_connection.cursor()
752        try:
753            cursor.execute(self._dialect_specific_select_one)
754        finally:
755            cursor.close()
756        return True
757
758    def create_xid(self):
759        """Create a random two-phase transaction ID.
760
761        This id will be passed to do_begin_twophase(), do_rollback_twophase(),
762        do_commit_twophase().  Its format is unspecified.
763        """
764
765        return "_sa_%032x" % random.randint(0, 2**128)
766
767    def do_savepoint(self, connection, name):
768        connection.execute(expression.SavepointClause(name))
769
770    def do_rollback_to_savepoint(self, connection, name):
771        connection.execute(expression.RollbackToSavepointClause(name))
772
773    def do_release_savepoint(self, connection, name):
774        connection.execute(expression.ReleaseSavepointClause(name))
775
776    def _deliver_insertmanyvalues_batches(
777        self,
778        connection,
779        cursor,
780        statement,
781        parameters,
782        generic_setinputsizes,
783        context,
784    ):
785        context = cast(DefaultExecutionContext, context)
786        compiled = cast(SQLCompiler, context.compiled)
787
788        _composite_sentinel_proc: Sequence[
789            Optional[_ResultProcessorType[Any]]
790        ] = ()
791        _scalar_sentinel_proc: Optional[_ResultProcessorType[Any]] = None
792        _sentinel_proc_initialized: bool = False
793
794        compiled_parameters = context.compiled_parameters
795
796        imv = compiled._insertmanyvalues
797        assert imv is not None
798
799        is_returning: Final[bool] = bool(compiled.effective_returning)
800        batch_size = context.execution_options.get(
801            "insertmanyvalues_page_size", self.insertmanyvalues_page_size
802        )
803
804        if compiled.schema_translate_map:
805            schema_translate_map = context.execution_options.get(
806                "schema_translate_map", {}
807            )
808        else:
809            schema_translate_map = None
810
811        if is_returning:
812            result: Optional[List[Any]] = []
813            context._insertmanyvalues_rows = result
814
815            sort_by_parameter_order = imv.sort_by_parameter_order
816
817        else:
818            sort_by_parameter_order = False
819            result = None
820
821        for imv_batch in compiled._deliver_insertmanyvalues_batches(
822            statement,
823            parameters,
824            compiled_parameters,
825            generic_setinputsizes,
826            batch_size,
827            sort_by_parameter_order,
828            schema_translate_map,
829        ):
830            yield imv_batch
831
832            if is_returning:
833
834                try:
835                    rows = context.fetchall_for_returning(cursor)
836                except BaseException as be:
837                    connection._handle_dbapi_exception(
838                        be,
839                        sql_util._long_statement(imv_batch.replaced_statement),
840                        imv_batch.replaced_parameters,
841                        None,
842                        context,
843                        is_sub_exec=True,
844                    )
845
846                # I would have thought "is_returning: Final[bool]"
847                # would have assured this but pylance thinks not
848                assert result is not None
849
850                if imv.num_sentinel_columns and not imv_batch.is_downgraded:
851                    composite_sentinel = imv.num_sentinel_columns > 1
852                    if imv.implicit_sentinel:
853                        # for implicit sentinel, which is currently single-col
854                        # integer autoincrement, do a simple sort.
855                        assert not composite_sentinel
856                        result.extend(
857                            sorted(rows, key=operator.itemgetter(-1))
858                        )
859                        continue
860
861                    # otherwise, create dictionaries to match up batches
862                    # with parameters
863                    assert imv.sentinel_param_keys
864                    assert imv.sentinel_columns
865
866                    _nsc = imv.num_sentinel_columns
867
868                    if not _sentinel_proc_initialized:
869                        if composite_sentinel:
870                            _composite_sentinel_proc = [
871                                col.type._cached_result_processor(
872                                    self, cursor_desc[1]
873                                )
874                                for col, cursor_desc in zip(
875                                    imv.sentinel_columns,
876                                    cursor.description[-_nsc:],
877                                )
878                            ]
879                        else:
880                            _scalar_sentinel_proc = (
881                                imv.sentinel_columns[0]
882                            ).type._cached_result_processor(
883                                self, cursor.description[-1][1]
884                            )
885                        _sentinel_proc_initialized = True
886
887                    rows_by_sentinel: Union[
888                        Dict[Tuple[Any, ...], Any],
889                        Dict[Any, Any],
890                    ]
891                    if composite_sentinel:
892                        rows_by_sentinel = {
893                            tuple(
894                                (proc(val) if proc else val)
895                                for val, proc in zip(
896                                    row[-_nsc:], _composite_sentinel_proc
897                                )
898                            ): row
899                            for row in rows
900                        }
901                    elif _scalar_sentinel_proc:
902                        rows_by_sentinel = {
903                            _scalar_sentinel_proc(row[-1]): row for row in rows
904                        }
905                    else:
906                        rows_by_sentinel = {row[-1]: row for row in rows}
907
908                    if len(rows_by_sentinel) != len(imv_batch.batch):
909                        # see test_insert_exec.py::
910                        # IMVSentinelTest::test_sentinel_incorrect_rowcount
911                        # for coverage / demonstration
912                        raise exc.InvalidRequestError(
913                            f"Sentinel-keyed result set did not produce "
914                            f"correct number of rows {len(imv_batch.batch)}; "
915                            "produced "
916                            f"{len(rows_by_sentinel)}.  Please ensure the "
917                            "sentinel column is fully unique and populated in "
918                            "all cases."
919                        )
920
921                    try:
922                        ordered_rows = [
923                            rows_by_sentinel[sentinel_keys]
924                            for sentinel_keys in imv_batch.sentinel_values
925                        ]
926                    except KeyError as ke:
927                        # see test_insert_exec.py::
928                        # IMVSentinelTest::test_sentinel_cant_match_keys
929                        # for coverage / demonstration
930                        raise exc.InvalidRequestError(
931                            f"Can't match sentinel values in result set to "
932                            f"parameter sets; key {ke.args[0]!r} was not "
933                            "found. "
934                            "There may be a mismatch between the datatype "
935                            "passed to the DBAPI driver vs. that which it "
936                            "returns in a result row.  Ensure the given "
937                            "Python value matches the expected result type "
938                            "*exactly*, taking care to not rely upon implicit "
939                            "conversions which may occur such as when using "
940                            "strings in place of UUID or integer values, etc. "
941                        ) from ke
942
943                    result.extend(ordered_rows)
944
945                else:
946                    result.extend(rows)
947
948    def do_executemany(self, cursor, statement, parameters, context=None):
949        cursor.executemany(statement, parameters)
950
951    def do_execute(self, cursor, statement, parameters, context=None):
952        cursor.execute(statement, parameters)
953
954    def do_execute_no_params(self, cursor, statement, context=None):
955        cursor.execute(statement)
956
957    def is_disconnect(
958        self,
959        e: DBAPIModule.Error,
960        connection: Union[
961            pool.PoolProxiedConnection, interfaces.DBAPIConnection, None
962        ],
963        cursor: Optional[interfaces.DBAPICursor],
964    ) -> bool:
965        return False
966
967    @util.memoized_instancemethod
968    def _gen_allowed_isolation_levels(self, dbapi_conn):
969        try:
970            raw_levels = list(self.get_isolation_level_values(dbapi_conn))
971        except NotImplementedError:
972            return None
973        else:
974            normalized_levels = [
975                level.replace("_", " ").upper() for level in raw_levels
976            ]
977            if raw_levels != normalized_levels:
978                raise ValueError(
979                    f"Dialect {self.name!r} get_isolation_level_values() "
980                    f"method should return names as UPPERCASE using spaces, "
981                    f"not underscores; got "
982                    f"{sorted(set(raw_levels).difference(normalized_levels))}"
983                )
984            return tuple(normalized_levels)
985
986    def _assert_and_set_isolation_level(self, dbapi_conn, level):
987        level = level.replace("_", " ").upper()
988
989        _allowed_isolation_levels = self._gen_allowed_isolation_levels(
990            dbapi_conn
991        )
992        if (
993            _allowed_isolation_levels
994            and level not in _allowed_isolation_levels
995        ):
996            raise exc.ArgumentError(
997                f"Invalid value {level!r} for isolation_level. "
998                f"Valid isolation levels for {self.name!r} are "
999                f"{', '.join(_allowed_isolation_levels)}"
1000            )
1001
1002        self.set_isolation_level(dbapi_conn, level)
1003
1004    def reset_isolation_level(self, dbapi_conn):
1005        if self._on_connect_isolation_level is not None:
1006            assert (
1007                self._on_connect_isolation_level == "AUTOCOMMIT"
1008                or self._on_connect_isolation_level
1009                == self.default_isolation_level
1010            )
1011            self._assert_and_set_isolation_level(
1012                dbapi_conn, self._on_connect_isolation_level
1013            )
1014        else:
1015            assert self.default_isolation_level is not None
1016            self._assert_and_set_isolation_level(
1017                dbapi_conn,
1018                self.default_isolation_level,
1019            )
1020
1021    def normalize_name(self, name):
1022        if name is None:
1023            return None
1024
1025        name_lower = name.lower()
1026        name_upper = name.upper()
1027
1028        if name_upper == name_lower:
1029            # name has no upper/lower conversion, e.g. non-european characters.
1030            # return unchanged
1031            return name
1032        elif name_upper == name and not (
1033            self.identifier_preparer._requires_quotes
1034        )(name_lower):
1035            # name is all uppercase and doesn't require quoting; normalize
1036            # to all lower case
1037            return name_lower
1038        elif name_lower == name:
1039            # name is all lower case, which if denormalized means we need to
1040            # force quoting on it
1041            return quoted_name(name, quote=True)
1042        else:
1043            # name is mixed case, means it will be quoted in SQL when used
1044            # later, no normalizes
1045            return name
1046
1047    def denormalize_name(self, name):
1048        if name is None:
1049            return None
1050
1051        name_lower = name.lower()
1052        name_upper = name.upper()
1053
1054        if name_upper == name_lower:
1055            # name has no upper/lower conversion, e.g. non-european characters.
1056            # return unchanged
1057            return name
1058        elif name_lower == name and not (
1059            self.identifier_preparer._requires_quotes
1060        )(name_lower):
1061            name = name_upper
1062        return name
1063
1064    def get_driver_connection(self, connection: DBAPIConnection) -> Any:
1065        return connection
1066
1067    def _overrides_default(self, method):
1068        return (
1069            getattr(type(self), method).__code__
1070            is not getattr(DefaultDialect, method).__code__
1071        )
1072
1073    def _default_multi_reflect(
1074        self,
1075        single_tbl_method,
1076        connection,
1077        kind,
1078        schema,
1079        filter_names,
1080        scope,
1081        **kw,
1082    ):
1083        names_fns = []
1084        temp_names_fns = []
1085        if ObjectKind.TABLE in kind:
1086            names_fns.append(self.get_table_names)
1087            temp_names_fns.append(self.get_temp_table_names)
1088        if ObjectKind.VIEW in kind:
1089            names_fns.append(self.get_view_names)
1090            temp_names_fns.append(self.get_temp_view_names)
1091        if ObjectKind.MATERIALIZED_VIEW in kind:
1092            names_fns.append(self.get_materialized_view_names)
1093            # no temp materialized view at the moment
1094            # temp_names_fns.append(self.get_temp_materialized_view_names)
1095
1096        unreflectable = kw.pop("unreflectable", {})
1097
1098        if (
1099            filter_names
1100            and scope is ObjectScope.ANY
1101            and kind is ObjectKind.ANY
1102        ):
1103            # if names are given and no qualification on type of table
1104            # (i.e. the Table(..., autoload) case), take the names as given,
1105            # don't run names queries. If a table does not exit
1106            # NoSuchTableError is raised and it's skipped
1107
1108            # this also suits the case for mssql where we can reflect
1109            # individual temp tables but there's no temp_names_fn
1110            names = filter_names
1111        else:
1112            names = []
1113            name_kw = {"schema": schema, **kw}
1114            fns = []
1115            if ObjectScope.DEFAULT in scope:
1116                fns.extend(names_fns)
1117            if ObjectScope.TEMPORARY in scope:
1118                fns.extend(temp_names_fns)
1119
1120            for fn in fns:
1121                try:
1122                    names.extend(fn(connection, **name_kw))
1123                except NotImplementedError:
1124                    pass
1125
1126        if filter_names:
1127            filter_names = set(filter_names)
1128
1129        # iterate over all the tables/views and call the single table method
1130        for table in names:
1131            if not filter_names or table in filter_names:
1132                key = (schema, table)
1133                try:
1134                    yield (
1135                        key,
1136                        single_tbl_method(
1137                            connection, table, schema=schema, **kw
1138                        ),
1139                    )
1140                except exc.UnreflectableTableError as err:
1141                    if key not in unreflectable:
1142                        unreflectable[key] = err
1143                except exc.NoSuchTableError:
1144                    pass
1145
1146    def get_multi_table_options(self, connection, **kw):
1147        return self._default_multi_reflect(
1148            self.get_table_options, connection, **kw
1149        )
1150
1151    def get_multi_columns(self, connection, **kw):
1152        return self._default_multi_reflect(self.get_columns, connection, **kw)
1153
1154    def get_multi_pk_constraint(self, connection, **kw):
1155        return self._default_multi_reflect(
1156            self.get_pk_constraint, connection, **kw
1157        )
1158
1159    def get_multi_foreign_keys(self, connection, **kw):
1160        return self._default_multi_reflect(
1161            self.get_foreign_keys, connection, **kw
1162        )
1163
1164    def get_multi_indexes(self, connection, **kw):
1165        return self._default_multi_reflect(self.get_indexes, connection, **kw)
1166
1167    def get_multi_unique_constraints(self, connection, **kw):
1168        return self._default_multi_reflect(
1169            self.get_unique_constraints, connection, **kw
1170        )
1171
1172    def get_multi_check_constraints(self, connection, **kw):
1173        return self._default_multi_reflect(
1174            self.get_check_constraints, connection, **kw
1175        )
1176
1177    def get_multi_table_comment(self, connection, **kw):
1178        return self._default_multi_reflect(
1179            self.get_table_comment, connection, **kw
1180        )
1181
1182
1183class StrCompileDialect(DefaultDialect):
1184    statement_compiler = compiler.StrSQLCompiler
1185    ddl_compiler = compiler.DDLCompiler
1186    type_compiler_cls = compiler.StrSQLTypeCompiler
1187    preparer = compiler.IdentifierPreparer
1188
1189    insert_returning = True
1190    update_returning = True
1191    delete_returning = True
1192
1193    supports_statement_cache = True
1194
1195    supports_identity_columns = True
1196
1197    supports_sequences = True
1198    sequences_optional = True
1199    preexecute_autoincrement_sequences = False
1200

Showing the first 1,200 of 2395 lines. Download the file for the rest.

codekingpro/portable-devtools · Team Ai