1# sql/base.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: https://www.opensource.org/licenses/mit-license.php
7
8"""Foundational utilities common to many sql modules.
9
10"""
11
12
13import itertools
14import operator
15import re
16
17from . import roles
18from . import visitors
19from .traversals import HasCacheKey  # noqa
20from .traversals import HasCopyInternals  # noqa
21from .traversals import MemoizedHasCacheKey  # noqa
22from .visitors import ClauseVisitor
23from .visitors import ExtendedInternalTraversal
24from .visitors import InternalTraversal
25from .. import exc
26from .. import util
27from ..util import HasMemoized
28from ..util import hybridmethod
29
30
31coercions = None
32elements = None
33type_api = None
34
35PARSE_AUTOCOMMIT = util.symbol("PARSE_AUTOCOMMIT")
36NO_ARG = util.symbol("NO_ARG")
37
38
39class Immutable(object):
40    """mark a ClauseElement as 'immutable' when expressions are cloned."""
41
42    _is_immutable = True
43
44    def unique_params(self, *optionaldict, **kwargs):
45        raise NotImplementedError("Immutable objects do not support copying")
46
47    def params(self, *optionaldict, **kwargs):
48        raise NotImplementedError("Immutable objects do not support copying")
49
50    def _clone(self, **kw):
51        return self
52
53    def _copy_internals(self, **kw):
54        pass
55
56
57class SingletonConstant(Immutable):
58    """Represent SQL constants like NULL, TRUE, FALSE"""
59
60    _is_singleton_constant = True
61
62    def __new__(cls, *arg, **kw):
63        return cls._singleton
64
65    @classmethod
66    def _create_singleton(cls):
67        obj = object.__new__(cls)
68        obj.__init__()
69
70        # for a long time this was an empty frozenset, meaning
71        # a SingletonConstant would never be a "corresponding column" in
72        # a statement.  This referred to #6259.  However, in #7154 we see
73        # that we do in fact need "correspondence" to work when matching cols
74        # in result sets, so the non-correspondence was moved to a more
75        # specific level when we are actually adapting expressions for SQL
76        # render only.
77        obj.proxy_set = frozenset([obj])
78        cls._singleton = obj
79
80
81def _from_objects(*elements):
82    return itertools.chain.from_iterable(
83        [element._from_objects for element in elements]
84    )
85
86
87def _select_iterables(elements):
88    """expand tables into individual columns in the
89    given list of column expressions.
90
91    """
92    return itertools.chain.from_iterable(
93        [c._select_iterable for c in elements]
94    )
95
96
97def _generative(fn):
98    """non-caching _generative() decorator.
99
100    This is basically the legacy decorator that copies the object and
101    runs a method on the new copy.
102
103    """
104
105    @util.decorator
106    def _generative(fn, self, *args, **kw):
107        """Mark a method as generative."""
108
109        self = self._generate()
110        x = fn(self, *args, **kw)
111        assert x is None, "generative methods must have no return value"
112        return self
113
114    decorated = _generative(fn)
115    decorated.non_generative = fn
116    return decorated
117
118
119def _exclusive_against(*names, **kw):
120    msgs = kw.pop("msgs", {})
121
122    defaults = kw.pop("defaults", {})
123
124    getters = [
125        (name, operator.attrgetter(name), defaults.get(name, None))
126        for name in names
127    ]
128
129    @util.decorator
130    def check(fn, *args, **kw):
131        # make pylance happy by not including "self" in the argument
132        # list
133        self = args[0]
134        args = args[1:]
135        for name, getter, default_ in getters:
136            if getter(self) is not default_:
137                msg = msgs.get(
138                    name,
139                    "Method %s() has already been invoked on this %s construct"
140                    % (fn.__name__, self.__class__),
141                )
142                raise exc.InvalidRequestError(msg)
143        return fn(self, *args, **kw)
144
145    return check
146
147
148def _clone(element, **kw):
149    return element._clone(**kw)
150
151
152def _expand_cloned(elements):
153    """expand the given set of ClauseElements to be the set of all 'cloned'
154    predecessors.
155
156    """
157    return itertools.chain(*[x._cloned_set for x in elements])
158
159
160def _cloned_intersection(a, b):
161    """return the intersection of sets a and b, counting
162    any overlap between 'cloned' predecessors.
163
164    The returned set is in terms of the entities present within 'a'.
165
166    """
167    all_overlap = set(_expand_cloned(a)).intersection(_expand_cloned(b))
168    return set(
169        elem for elem in a if all_overlap.intersection(elem._cloned_set)
170    )
171
172
173def _cloned_difference(a, b):
174    all_overlap = set(_expand_cloned(a)).intersection(_expand_cloned(b))
175    return set(
176        elem for elem in a if not all_overlap.intersection(elem._cloned_set)
177    )
178
179
180class _DialectArgView(util.collections_abc.MutableMapping):
181    """A dictionary view of dialect-level arguments in the form
182    <dialectname>_<argument_name>.
183
184    """
185
186    def __init__(self, obj):
187        self.obj = obj
188
189    def _key(self, key):
190        try:
191            dialect, value_key = key.split("_", 1)
192        except ValueError as err:
193            util.raise_(KeyError(key), replace_context=err)
194        else:
195            return dialect, value_key
196
197    def __getitem__(self, key):
198        dialect, value_key = self._key(key)
199
200        try:
201            opt = self.obj.dialect_options[dialect]
202        except exc.NoSuchModuleError as err:
203            util.raise_(KeyError(key), replace_context=err)
204        else:
205            return opt[value_key]
206
207    def __setitem__(self, key, value):
208        try:
209            dialect, value_key = self._key(key)
210        except KeyError as err:
211            util.raise_(
212                exc.ArgumentError(
213                    "Keys must be of the form <dialectname>_<argname>"
214                ),
215                replace_context=err,
216            )
217        else:
218            self.obj.dialect_options[dialect][value_key] = value
219
220    def __delitem__(self, key):
221        dialect, value_key = self._key(key)
222        del self.obj.dialect_options[dialect][value_key]
223
224    def __len__(self):
225        return sum(
226            len(args._non_defaults)
227            for args in self.obj.dialect_options.values()
228        )
229
230    def __iter__(self):
231        return (
232            "%s_%s" % (dialect_name, value_name)
233            for dialect_name in self.obj.dialect_options
234            for value_name in self.obj.dialect_options[
235                dialect_name
236            ]._non_defaults
237        )
238
239
240class _DialectArgDict(util.collections_abc.MutableMapping):
241    """A dictionary view of dialect-level arguments for a specific
242    dialect.
243
244    Maintains a separate collection of user-specified arguments
245    and dialect-specified default arguments.
246
247    """
248
249    def __init__(self):
250        self._non_defaults = {}
251        self._defaults = {}
252
253    def __len__(self):
254        return len(set(self._non_defaults).union(self._defaults))
255
256    def __iter__(self):
257        return iter(set(self._non_defaults).union(self._defaults))
258
259    def __getitem__(self, key):
260        if key in self._non_defaults:
261            return self._non_defaults[key]
262        else:
263            return self._defaults[key]
264
265    def __setitem__(self, key, value):
266        self._non_defaults[key] = value
267
268    def __delitem__(self, key):
269        del self._non_defaults[key]
270
271
272@util.preload_module("sqlalchemy.dialects")
273def _kw_reg_for_dialect(dialect_name):
274    dialect_cls = util.preloaded.dialects.registry.load(dialect_name)
275    if dialect_cls.construct_arguments is None:
276        return None
277    return dict(dialect_cls.construct_arguments)
278
279
280class DialectKWArgs(object):
281    """Establish the ability for a class to have dialect-specific arguments
282    with defaults and constructor validation.
283
284    The :class:`.DialectKWArgs` interacts with the
285    :attr:`.DefaultDialect.construct_arguments` present on a dialect.
286
287    .. seealso::
288
289        :attr:`.DefaultDialect.construct_arguments`
290
291    """
292
293    _dialect_kwargs_traverse_internals = [
294        ("dialect_options", InternalTraversal.dp_dialect_options)
295    ]
296
297    @classmethod
298    def argument_for(cls, dialect_name, argument_name, default):
299        """Add a new kind of dialect-specific keyword argument for this class.
300
301        E.g.::
302
303            Index.argument_for("mydialect", "length", None)
304
305            some_index = Index('a', 'b', mydialect_length=5)
306
307        The :meth:`.DialectKWArgs.argument_for` method is a per-argument
308        way adding extra arguments to the
309        :attr:`.DefaultDialect.construct_arguments` dictionary. This
310        dictionary provides a list of argument names accepted by various
311        schema-level constructs on behalf of a dialect.
312
313        New dialects should typically specify this dictionary all at once as a
314        data member of the dialect class.  The use case for ad-hoc addition of
315        argument names is typically for end-user code that is also using
316        a custom compilation scheme which consumes the additional arguments.
317
318        :param dialect_name: name of a dialect.  The dialect must be
319         locatable, else a :class:`.NoSuchModuleError` is raised.   The
320         dialect must also include an existing
321         :attr:`.DefaultDialect.construct_arguments` collection, indicating
322         that it participates in the keyword-argument validation and default
323         system, else :class:`.ArgumentError` is raised.  If the dialect does
324         not include this collection, then any keyword argument can be
325         specified on behalf of this dialect already.  All dialects packaged
326         within SQLAlchemy include this collection, however for third party
327         dialects, support may vary.
328
329        :param argument_name: name of the parameter.
330
331        :param default: default value of the parameter.
332
333        .. versionadded:: 0.9.4
334
335        """
336
337        construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name]
338        if construct_arg_dictionary is None:
339            raise exc.ArgumentError(
340                "Dialect '%s' does have keyword-argument "
341                "validation and defaults enabled configured" % dialect_name
342            )
343        if cls not in construct_arg_dictionary:
344            construct_arg_dictionary[cls] = {}
345        construct_arg_dictionary[cls][argument_name] = default
346
347    @util.memoized_property
348    def dialect_kwargs(self):
349        """A collection of keyword arguments specified as dialect-specific
350        options to this construct.
351
352        The arguments are present here in their original ``<dialect>_<kwarg>``
353        format.  Only arguments that were actually passed are included;
354        unlike the :attr:`.DialectKWArgs.dialect_options` collection, which
355        contains all options known by this dialect including defaults.
356
357        The collection is also writable; keys are accepted of the
358        form ``<dialect>_<kwarg>`` where the value will be assembled
359        into the list of options.
360
361        .. versionadded:: 0.9.2
362
363        .. versionchanged:: 0.9.4 The :attr:`.DialectKWArgs.dialect_kwargs`
364           collection is now writable.
365
366        .. seealso::
367
368            :attr:`.DialectKWArgs.dialect_options` - nested dictionary form
369
370        """
371        return _DialectArgView(self)
372
373    @property
374    def kwargs(self):
375        """A synonym for :attr:`.DialectKWArgs.dialect_kwargs`."""
376        return self.dialect_kwargs
377
378    _kw_registry = util.PopulateDict(_kw_reg_for_dialect)
379
380    def _kw_reg_for_dialect_cls(self, dialect_name):
381        construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name]
382        d = _DialectArgDict()
383
384        if construct_arg_dictionary is None:
385            d._defaults.update({"*": None})
386        else:
387            for cls in reversed(self.__class__.__mro__):
388                if cls in construct_arg_dictionary:
389                    d._defaults.update(construct_arg_dictionary[cls])
390        return d
391
392    @util.memoized_property
393    def dialect_options(self):
394        """A collection of keyword arguments specified as dialect-specific
395        options to this construct.
396
397        This is a two-level nested registry, keyed to ``<dialect_name>``
398        and ``<argument_name>``.  For example, the ``postgresql_where``
399        argument would be locatable as::
400
401            arg = my_object.dialect_options['postgresql']['where']
402
403        .. versionadded:: 0.9.2
404
405        .. seealso::
406
407            :attr:`.DialectKWArgs.dialect_kwargs` - flat dictionary form
408
409        """
410
411        return util.PopulateDict(
412            util.portable_instancemethod(self._kw_reg_for_dialect_cls)
413        )
414
415    def _validate_dialect_kwargs(self, kwargs):
416        # validate remaining kwargs that they all specify DB prefixes
417
418        if not kwargs:
419            return
420
421        for k in kwargs:
422            m = re.match("^(.+?)_(.+)$", k)
423            if not m:
424                raise TypeError(
425                    "Additional arguments should be "
426                    "named <dialectname>_<argument>, got '%s'" % k
427                )
428            dialect_name, arg_name = m.group(1, 2)
429
430            try:
431                construct_arg_dictionary = self.dialect_options[dialect_name]
432            except exc.NoSuchModuleError:
433                util.warn(
434                    "Can't validate argument %r; can't "
435                    "locate any SQLAlchemy dialect named %r"
436                    % (k, dialect_name)
437                )
438                self.dialect_options[dialect_name] = d = _DialectArgDict()
439                d._defaults.update({"*": None})
440                d._non_defaults[arg_name] = kwargs[k]
441            else:
442                if (
443                    "*" not in construct_arg_dictionary
444                    and arg_name not in construct_arg_dictionary
445                ):
446                    raise exc.ArgumentError(
447                        "Argument %r is not accepted by "
448                        "dialect %r on behalf of %r"
449                        % (k, dialect_name, self.__class__)
450                    )
451                else:
452                    construct_arg_dictionary[arg_name] = kwargs[k]
453
454
455class CompileState(object):
456    """Produces additional object state necessary for a statement to be
457    compiled.
458
459    the :class:`.CompileState` class is at the base of classes that assemble
460    state for a particular statement object that is then used by the
461    compiler.   This process is essentially an extension of the process that
462    the SQLCompiler.visit_XYZ() method takes, however there is an emphasis
463    on converting raw user intent into more organized structures rather than
464    producing string output.   The top-level :class:`.CompileState` for the
465    statement being executed is also accessible when the execution context
466    works with invoking the statement and collecting results.
467
468    The production of :class:`.CompileState` is specific to the compiler,  such
469    as within the :meth:`.SQLCompiler.visit_insert`,
470    :meth:`.SQLCompiler.visit_select` etc. methods.  These methods are also
471    responsible for associating the :class:`.CompileState` with the
472    :class:`.SQLCompiler` itself, if the statement is the "toplevel" statement,
473    i.e. the outermost SQL statement that's actually being executed.
474    There can be other :class:`.CompileState` objects that are not the
475    toplevel, such as when a SELECT subquery or CTE-nested
476    INSERT/UPDATE/DELETE is generated.
477
478    .. versionadded:: 1.4
479
480    """
481
482    __slots__ = ("statement",)
483
484    plugins = {}
485
486    @classmethod
487    def create_for_statement(cls, statement, compiler, **kw):
488        # factory construction.
489
490        if statement._propagate_attrs:
491            plugin_name = statement._propagate_attrs.get(
492                "compile_state_plugin", "default"
493            )
494            klass = cls.plugins.get(
495                (plugin_name, statement._effective_plugin_target), None
496            )
497            if klass is None:
498                klass = cls.plugins[
499                    ("default", statement._effective_plugin_target)
500                ]
501
502        else:
503            klass = cls.plugins[
504                ("default", statement._effective_plugin_target)
505            ]
506
507        if klass is cls:
508            return cls(statement, compiler, **kw)
509        else:
510            return klass.create_for_statement(statement, compiler, **kw)
511
512    def __init__(self, statement, compiler, **kw):
513        self.statement = statement
514
515    @classmethod
516    def get_plugin_class(cls, statement):
517        plugin_name = statement._propagate_attrs.get(
518            "compile_state_plugin", None
519        )
520
521        if plugin_name:
522            key = (plugin_name, statement._effective_plugin_target)
523            if key in cls.plugins:
524                return cls.plugins[key]
525
526        # there's no case where we call upon get_plugin_class() and want
527        # to get None back, there should always be a default.  return that
528        # if there was no plugin-specific class  (e.g. Insert with "orm"
529        # plugin)
530        try:
531            return cls.plugins[("default", statement._effective_plugin_target)]
532        except KeyError:
533            return None
534
535    @classmethod
536    def _get_plugin_class_for_plugin(cls, statement, plugin_name):
537        try:
538            return cls.plugins[
539                (plugin_name, statement._effective_plugin_target)
540            ]
541        except KeyError:
542            return None
543
544    @classmethod
545    def plugin_for(cls, plugin_name, visit_name):
546        def decorate(cls_to_decorate):
547            cls.plugins[(plugin_name, visit_name)] = cls_to_decorate
548            return cls_to_decorate
549
550        return decorate
551
552
553class Generative(HasMemoized):
554    """Provide a method-chaining pattern in conjunction with the
555    @_generative decorator."""
556
557    def _generate(self):
558        skip = self._memoized_keys
559        cls = self.__class__
560        s = cls.__new__(cls)
561        if skip:
562            s.__dict__ = {
563                k: v for k, v in self.__dict__.items() if k not in skip
564            }
565        else:
566            s.__dict__ = self.__dict__.copy()
567        return s
568
569
570class InPlaceGenerative(HasMemoized):
571    """Provide a method-chaining pattern in conjunction with the
572    @_generative decorator that mutates in place."""
573
574    def _generate(self):
575        skip = self._memoized_keys
576        for k in skip:
577            self.__dict__.pop(k, None)
578        return self
579
580
581class HasCompileState(Generative):
582    """A class that has a :class:`.CompileState` associated with it."""
583
584    _compile_state_plugin = None
585
586    _attributes = util.immutabledict()
587
588    _compile_state_factory = CompileState.create_for_statement
589
590
591class _MetaOptions(type):
592    """metaclass for the Options class."""
593
594    def __init__(cls, classname, bases, dict_):
595        cls._cache_attrs = tuple(
596            sorted(
597                d
598                for d in dict_
599                if not d.startswith("__")
600                and d not in ("_cache_key_traversal",)
601            )
602        )
603        type.__init__(cls, classname, bases, dict_)
604
605    def __add__(self, other):
606        o1 = self()
607
608        if set(other).difference(self._cache_attrs):
609            raise TypeError(
610                "dictionary contains attributes not covered by "
611                "Options class %s: %r"
612                % (self, set(other).difference(self._cache_attrs))
613            )
614
615        o1.__dict__.update(other)
616        return o1
617
618
619class Options(util.with_metaclass(_MetaOptions)):
620    """A cacheable option dictionary with defaults."""
621
622    def __init__(self, **kw):
623        self.__dict__.update(kw)
624
625    def __add__(self, other):
626        o1 = self.__class__.__new__(self.__class__)
627        o1.__dict__.update(self.__dict__)
628
629        if set(other).difference(self._cache_attrs):
630            raise TypeError(
631                "dictionary contains attributes not covered by "
632                "Options class %s: %r"
633                % (self, set(other).difference(self._cache_attrs))
634            )
635
636        o1.__dict__.update(other)
637        return o1
638
639    def __eq__(self, other):
640        # TODO: very inefficient.  This is used only in test suites
641        # right now.
642        for a, b in util.zip_longest(self._cache_attrs, other._cache_attrs):
643            if getattr(self, a) != getattr(other, b):
644                return False
645        return True
646
647    def __repr__(self):
648        # TODO: fairly inefficient, used only in debugging right now.
649
650        return "%s(%s)" % (
651            self.__class__.__name__,
652            ", ".join(
653                "%s=%r" % (k, self.__dict__[k])
654                for k in self._cache_attrs
655                if k in self.__dict__
656            ),
657        )
658
659    @classmethod
660    def isinstance(cls, klass):
661        return issubclass(cls, klass)
662
663    @hybridmethod
664    def add_to_element(self, name, value):
665        return self + {name: getattr(self, name) + value}
666
667    @hybridmethod
668    def _state_dict(self):
669        return self.__dict__
670
671    _state_dict_const = util.immutabledict()
672
673    @_state_dict.classlevel
674    def _state_dict(cls):
675        return cls._state_dict_const
676
677    @classmethod
678    def safe_merge(cls, other):
679        d = other._state_dict()
680
681        # only support a merge with another object of our class
682        # and which does not have attrs that we don't.   otherwise
683        # we risk having state that might not be part of our cache
684        # key strategy
685
686        if (
687            cls is not other.__class__
688            and other._cache_attrs
689            and set(other._cache_attrs).difference(cls._cache_attrs)
690        ):
691            raise TypeError(
692                "other element %r is not empty, is not of type %s, "
693                "and contains attributes not covered here %r"
694                % (
695                    other,
696                    cls,
697                    set(other._cache_attrs).difference(cls._cache_attrs),
698                )
699            )
700        return cls + d
701
702    @classmethod
703    def from_execution_options(
704        cls, key, attrs, exec_options, statement_exec_options
705    ):
706        """process Options argument in terms of execution options.
707
708
709        e.g.::
710
711            (
712                load_options,
713                execution_options,
714            ) = QueryContext.default_load_options.from_execution_options(
715                "_sa_orm_load_options",
716                {
717                    "populate_existing",
718                    "autoflush",
719                    "yield_per"
720                },
721                execution_options,
722                statement._execution_options,
723            )
724
725        get back the Options and refresh "_sa_orm_load_options" in the
726        exec options dict w/ the Options as well
727
728        """
729
730        # common case is that no options we are looking for are
731        # in either dictionary, so cancel for that first
732        check_argnames = attrs.intersection(
733            set(exec_options).union(statement_exec_options)
734        )
735
736        existing_options = exec_options.get(key, cls)
737
738        if check_argnames:
739            result = {}
740            for argname in check_argnames:
741                local = "_" + argname
742                if argname in exec_options:
743                    result[local] = exec_options[argname]
744                elif argname in statement_exec_options:
745                    result[local] = statement_exec_options[argname]
746
747            new_options = existing_options + result
748            exec_options = util.immutabledict().merge_with(
749                exec_options, {key: new_options}
750            )
751            return new_options, exec_options
752
753        else:
754            return existing_options, exec_options
755
756
757class CacheableOptions(Options, HasCacheKey):
758    @hybridmethod
759    def _gen_cache_key(self, anon_map, bindparams):
760        return HasCacheKey._gen_cache_key(self, anon_map, bindparams)
761
762    @_gen_cache_key.classlevel
763    def _gen_cache_key(cls, anon_map, bindparams):
764        return (cls, ())
765
766    @hybridmethod
767    def _generate_cache_key(self):
768        return HasCacheKey._generate_cache_key_for_object(self)
769
770
771class ExecutableOption(HasCopyInternals, HasCacheKey):
772    _annotations = util.EMPTY_DICT
773
774    __visit_name__ = "executable_option"
775
776    def _clone(self, **kw):
777        """Create a shallow copy of this ExecutableOption."""
778        c = self.__class__.__new__(self.__class__)
779        c.__dict__ = dict(self.__dict__)
780        return c
781
782
783class Executable(roles.StatementRole, Generative):
784    """Mark a :class:`_expression.ClauseElement` as supporting execution.
785
786    :class:`.Executable` is a superclass for all "statement" types
787    of objects, including :func:`select`, :func:`delete`, :func:`update`,
788    :func:`insert`, :func:`text`.
789
790    """
791
792    supports_execution = True
793    _execution_options = util.immutabledict()
794    _bind = None
795    _with_options = ()
796    _with_context_options = ()
797
798    _executable_traverse_internals = [
799        ("_with_options", InternalTraversal.dp_executable_options),
800        (
801            "_with_context_options",
802            ExtendedInternalTraversal.dp_with_context_options,
803        ),
804        ("_propagate_attrs", ExtendedInternalTraversal.dp_propagate_attrs),
805    ]
806
807    is_select = False
808    is_update = False
809    is_insert = False
810    is_text = False
811    is_delete = False
812    is_dml = False
813
814    @property
815    def _effective_plugin_target(self):
816        return self.__visit_name__
817
818    @_generative
819    def options(self, *options):
820        """Apply options to this statement.
821
822        In the general sense, options are any kind of Python object
823        that can be interpreted by the SQL compiler for the statement.
824        These options can be consumed by specific dialects or specific kinds
825        of compilers.
826
827        The most commonly known kind of option are the ORM level options
828        that apply "eager load" and other loading behaviors to an ORM
829        query.   However, options can theoretically be used for many other
830        purposes.
831
832        For background on specific kinds of options for specific kinds of
833        statements, refer to the documentation for those option objects.
834
835        .. versionchanged:: 1.4 - added :meth:`.Generative.options` to
836           Core statement objects towards the goal of allowing unified
837           Core / ORM querying capabilities.
838
839        .. seealso::
840
841            :ref:`deferred_options` - refers to options specific to the usage
842            of ORM queries
843
844            :ref:`relationship_loader_options` - refers to options specific
845            to the usage of ORM queries
846
847        """
848        self._with_options += tuple(
849            coercions.expect(roles.HasCacheKeyRole, opt) for opt in options
850        )
851
852    @_generative
853    def _set_compile_options(self, compile_options):
854        """Assign the compile options to a new value.
855
856        :param compile_options: appropriate CacheableOptions structure
857
858        """
859
860        self._compile_options = compile_options
861
862    @_generative
863    def _update_compile_options(self, options):
864        """update the _compile_options with new keys."""
865
866        self._compile_options += options
867
868    @_generative
869    def _add_context_option(self, callable_, cache_args):
870        """Add a context option to this statement.
871
872        These are callable functions that will
873        be given the CompileState object upon compilation.
874
875        A second argument cache_args is required, which will be combined with
876        the ``__code__`` identity of the function itself in order to produce a
877        cache key.
878
879        """
880        self._with_context_options += ((callable_, cache_args),)
881
882    @_generative
883    def execution_options(self, **kw):
884        """Set non-SQL options for the statement which take effect during
885        execution.
886
887        Execution options can be set on a per-statement or
888        per :class:`_engine.Connection` basis.   Additionally, the
889        :class:`_engine.Engine` and ORM :class:`~.orm.query.Query`
890        objects provide
891        access to execution options which they in turn configure upon
892        connections.
893
894        The :meth:`execution_options` method is generative.  A new
895        instance of this statement is returned that contains the options::
896
897            statement = select(table.c.x, table.c.y)
898            statement = statement.execution_options(autocommit=True)
899
900        Note that only a subset of possible execution options can be applied
901        to a statement - these include "autocommit" and "stream_results",
902        but not "isolation_level" or "compiled_cache".
903        See :meth:`_engine.Connection.execution_options` for a full list of
904        possible options.
905
906        .. seealso::
907
908            :meth:`_engine.Connection.execution_options`
909
910            :meth:`_query.Query.execution_options`
911
912            :meth:`.Executable.get_execution_options`
913
914        """
915        if "isolation_level" in kw:
916            raise exc.ArgumentError(
917                "'isolation_level' execution option may only be specified "
918                "on Connection.execution_options(), or "
919                "per-engine using the isolation_level "
920                "argument to create_engine()."
921            )
922        if "compiled_cache" in kw:
923            raise exc.ArgumentError(
924                "'compiled_cache' execution option may only be specified "
925                "on Connection.execution_options(), not per statement."
926            )
927        self._execution_options = self._execution_options.union(kw)
928
929    def get_execution_options(self):
930        """Get the non-SQL options which will take effect during execution.
931
932        .. versionadded:: 1.3
933
934        .. seealso::
935
936            :meth:`.Executable.execution_options`
937        """
938        return self._execution_options
939
940    @util.deprecated_20(
941        ":meth:`.Executable.execute`",
942        alternative="All statement execution in SQLAlchemy 2.0 is performed "
943        "by the :meth:`_engine.Connection.execute` method of "
944        ":class:`_engine.Connection`, "
945        "or in the ORM by the :meth:`.Session.execute` method of "
946        ":class:`.Session`.",
947    )
948    def execute(self, *multiparams, **params):
949        """Compile and execute this :class:`.Executable`."""
950        e = self.bind
951        if e is None:
952            label = (
953                getattr(self, "description", None) or self.__class__.__name__
954            )
955            msg = (
956                "This %s is not directly bound to a Connection or Engine. "
957                "Use the .execute() method of a Connection or Engine "
958                "to execute this construct." % label
959            )
960            raise exc.UnboundExecutionError(msg)
961        return e._execute_clauseelement(
962            self, multiparams, params, util.immutabledict()
963        )
964
965    @util.deprecated_20(
966        ":meth:`.Executable.scalar`",
967        alternative="Scalar execution in SQLAlchemy 2.0 is performed "
968        "by the :meth:`_engine.Connection.scalar` method of "
969        ":class:`_engine.Connection`, "
970        "or in the ORM by the :meth:`.Session.scalar` method of "
971        ":class:`.Session`.",
972    )
973    def scalar(self, *multiparams, **params):
974        """Compile and execute this :class:`.Executable`, returning the
975        result's scalar representation.
976
977        """
978        return self.execute(*multiparams, **params).scalar()
979
980    @property
981    @util.deprecated_20(
982        ":attr:`.Executable.bind`",
983        alternative="Bound metadata is being removed as of SQLAlchemy 2.0.",
984        enable_warnings=False,
985    )
986    def bind(self):
987        """Returns the :class:`_engine.Engine` or :class:`_engine.Connection`
988        to
989        which this :class:`.Executable` is bound, or None if none found.
990
991        This is a traversal which checks locally, then
992        checks among the "from" clauses of associated objects
993        until a bound engine or connection is found.
994
995        """
996        if self._bind is not None:
997            return self._bind
998
999        for f in _from_objects(self):
1000            if f is self:
1001                continue
1002            engine = f.bind
1003            if engine is not None:
1004                return engine
1005        else:
1006            return None
1007
1008
1009class prefix_anon_map(dict):
1010    """A map that creates new keys for missing key access.
1011
1012    Considers keys of the form "<ident> <name>" to produce
1013    new symbols "<name>_<index>", where "index" is an incrementing integer
1014    corresponding to <name>.
1015
1016    Inlines the approach taken by :class:`sqlalchemy.util.PopulateDict` which
1017    is otherwise usually used for this type of operation.
1018
1019    """
1020
1021    def __missing__(self, key):
1022        (ident, derived) = key.split(" ", 1)
1023        anonymous_counter = self.get(derived, 1)
1024        self[derived] = anonymous_counter + 1
1025        value = derived + "_" + str(anonymous_counter)
1026        self[key] = value
1027        return value
1028
1029
1030class SchemaEventTarget(object):
1031    """Base class for elements that are the targets of :class:`.DDLEvents`
1032    events.
1033
1034    This includes :class:`.SchemaItem` as well as :class:`.SchemaType`.
1035
1036    """
1037
1038    def _set_parent(self, parent, **kw):
1039        """Associate with this SchemaEvent's parent object."""
1040
1041    def _set_parent_with_dispatch(self, parent, **kw):
1042        self.dispatch.before_parent_attach(self, parent)
1043        self._set_parent(parent, **kw)
1044        self.dispatch.after_parent_attach(self, parent)
1045
1046
1047class SchemaVisitor(ClauseVisitor):
1048    """Define the visiting for ``SchemaItem`` objects."""
1049
1050    __traverse_options__ = {"schema_visitor": True}
1051
1052
1053class ColumnCollection(object):
1054    """Collection of :class:`_expression.ColumnElement` instances,
1055    typically for
1056    :class:`_sql.FromClause` objects.
1057
1058    The :class:`_sql.ColumnCollection` object is most commonly available
1059    as the :attr:`_schema.Table.c` or :attr:`_schema.Table.columns` collection
1060    on the :class:`_schema.Table` object, introduced at
1061    :ref:`metadata_tables_and_columns`.
1062
1063    The :class:`_expression.ColumnCollection` has both mapping- and sequence-
1064    like behaviors. A :class:`_expression.ColumnCollection` usually stores
1065    :class:`_schema.Column` objects, which are then accessible both via mapping
1066    style access as well as attribute access style.
1067
1068    To access :class:`_schema.Column` objects using ordinary attribute-style
1069    access, specify the name like any other object attribute, such as below
1070    a column named ``employee_name`` is accessed::
1071
1072        >>> employee_table.c.employee_name
1073
1074    To access columns that have names with special characters or spaces,
1075    index-style access is used, such as below which illustrates a column named
1076    ``employee ' payment`` is accessed::
1077
1078        >>> employee_table.c["employee ' payment"]
1079
1080    As the :class:`_sql.ColumnCollection` object provides a Python dictionary
1081    interface, common dictionary method names like
1082    :meth:`_sql.ColumnCollection.keys`, :meth:`_sql.ColumnCollection.values`,
1083    and :meth:`_sql.ColumnCollection.items` are available, which means that
1084    database columns that are keyed under these names also need to use indexed
1085    access::
1086
1087        >>> employee_table.c["values"]
1088
1089
1090    The name for which a :class:`_schema.Column` would be present is normally
1091    that of the :paramref:`_schema.Column.key` parameter.  In some contexts,
1092    such as a :class:`_sql.Select` object that uses a label style set
1093    using the :meth:`_sql.Select.set_label_style` method, a column of a certain
1094    key may instead be represented under a particular label name such
1095    as ``tablename_columnname``::
1096
1097        >>> from sqlalchemy import select, column, table
1098        >>> from sqlalchemy import LABEL_STYLE_TABLENAME_PLUS_COL
1099        >>> t = table("t", column("c"))
1100        >>> stmt = select(t).set_label_style(LABEL_STYLE_TABLENAME_PLUS_COL)
1101        >>> subq = stmt.subquery()
1102        >>> subq.c.t_c
1103        <sqlalchemy.sql.elements.ColumnClause at 0x7f59dcf04fa0; t_c>
1104
1105    :class:`.ColumnCollection` also indexes the columns in order and allows
1106    them to be accessible by their integer position::
1107
1108        >>> cc[0]
1109        Column('x', Integer(), table=None)
1110        >>> cc[1]
1111        Column('y', Integer(), table=None)
1112
1113    .. versionadded:: 1.4 :class:`_expression.ColumnCollection`
1114       allows integer-based
1115       index access to the collection.
1116
1117    Iterating the collection yields the column expressions in order::
1118
1119        >>> list(cc)
1120        [Column('x', Integer(), table=None),
1121         Column('y', Integer(), table=None)]
1122
1123    The base :class:`_expression.ColumnCollection` object can store
1124    duplicates, which can
1125    mean either two columns with the same key, in which case the column
1126    returned by key  access is **arbitrary**::
1127
1128        >>> x1, x2 = Column('x', Integer), Column('x', Integer)
1129        >>> cc = ColumnCollection(columns=[(x1.name, x1), (x2.name, x2)])
1130        >>> list(cc)
1131        [Column('x', Integer(), table=None),
1132         Column('x', Integer(), table=None)]
1133        >>> cc['x'] is x1
1134        False
1135        >>> cc['x'] is x2
1136        True
1137
1138    Or it can also mean the same column multiple times.   These cases are
1139    supported as :class:`_expression.ColumnCollection`
1140    is used to represent the columns in
1141    a SELECT statement which may include duplicates.
1142
1143    A special subclass :class:`.DedupeColumnCollection` exists which instead
1144    maintains SQLAlchemy's older behavior of not allowing duplicates; this
1145    collection is used for schema level objects like :class:`_schema.Table`
1146    and
1147    :class:`.PrimaryKeyConstraint` where this deduping is helpful.  The
1148    :class:`.DedupeColumnCollection` class also has additional mutation methods
1149    as the schema constructs have more use cases that require removal and
1150    replacement of columns.
1151
1152    .. versionchanged:: 1.4 :class:`_expression.ColumnCollection`
1153       now stores duplicate
1154       column keys as well as the same column in multiple positions.  The
1155       :class:`.DedupeColumnCollection` class is added to maintain the
1156       former behavior in those cases where deduplication as well as
1157       additional replace/remove operations are needed.
1158
1159
1160    """
1161
1162    __slots__ = "_collection", "_index", "_colset"
1163
1164    def __init__(self, columns=None):
1165        object.__setattr__(self, "_colset", set())
1166        object.__setattr__(self, "_index", {})
1167        object.__setattr__(self, "_collection", [])
1168        if columns:
1169            self._initial_populate(columns)
1170
1171    def _initial_populate(self, iter_):
1172        self._populate_separate_keys(iter_)
1173
1174    @property
1175    def _all_columns(self):
1176        return [col for (k, col) in self._collection]
1177
1178    def keys(self):
1179        """Return a sequence of string key names for all columns in this
1180        collection."""
1181        return [k for (k, col) in self._collection]
1182
1183    def values(self):
1184        """Return a sequence of :class:`_sql.ColumnClause` or
1185        :class:`_schema.Column` objects for all columns in this
1186        collection."""
1187        return [col for (k, col) in self._collection]
1188
1189    def items(self):
1190        """Return a sequence of (key, column) tuples for all columns in this
1191        collection each consisting of a string key name and a
1192        :class:`_sql.ColumnClause` or
1193        :class:`_schema.Column` object.
1194        """
1195
1196        return list(self._collection)
1197
1198    def __bool__(self):
1199        return bool(self._collection)
1200
1201    def __len__(self):
1202        return len(self._collection)
1203
1204    def __iter__(self):
1205        # turn to a list first to maintain over a course of changes
1206        return iter([col for k, col in self._collection])
1207
1208    def __getitem__(self, key):
1209        try:
1210            return self._index[key]
1211        except KeyError as err:
1212            if isinstance(key, util.int_types):
1213                util.raise_(IndexError(key), replace_context=err)
1214            else:
1215                raise
1216
1217    def __getattr__(self, key):
1218        try:
1219            return self._index[key]
1220        except KeyError as err:
1221            util.raise_(AttributeError(key), replace_context=err)
1222
1223    def __contains__(self, key):
1224        if key not in self._index:
1225            if not isinstance(key, util.string_types):
1226                raise exc.ArgumentError(
1227                    "__contains__ requires a string argument"
1228                )
1229            return False
1230        else:
1231            return True
1232
1233    def compare(self, other):
1234        """Compare this :class:`_expression.ColumnCollection` to another
1235        based on the names of the keys"""
1236
1237        for l, r in util.zip_longest(self, other):
1238            if l is not r:
1239                return False
1240        else:
1241            return True
1242
1243    def __eq__(self, other):
1244        return self.compare(other)
1245
1246    def get(self, key, default=None):
1247        """Get a :class:`_sql.ColumnClause` or :class:`_schema.Column` object
1248        based on a string key name from this
1249        :class:`_expression.ColumnCollection`."""
1250
1251        if key in self._index:
1252            return self._index[key]
1253        else:
1254            return default
1255
1256    def __str__(self):
1257        return "%s(%s)" % (
1258            self.__class__.__name__,
1259            ", ".join(str(c) for c in self),
1260        )
1261
1262    def __setitem__(self, key, value):
1263        raise NotImplementedError()
1264
1265    def __delitem__(self, key):
1266        raise NotImplementedError()
1267
1268    def __setattr__(self, key, obj):
1269        raise NotImplementedError()
1270
1271    def clear(self):
1272        """Dictionary clear() is not implemented for
1273        :class:`_sql.ColumnCollection`."""
1274        raise NotImplementedError()
1275
1276    def remove(self, column):
1277        """Dictionary remove() is not implemented for
1278        :class:`_sql.ColumnCollection`."""
1279        raise NotImplementedError()
1280
1281    def update(self, iter_):
1282        """Dictionary update() is not implemented for
1283        :class:`_sql.ColumnCollection`."""
1284        raise NotImplementedError()
1285
1286    __hash__ = None
1287
1288    def _populate_separate_keys(self, iter_):
1289        """populate from an iterator of (key, column)"""
1290        cols = list(iter_)
1291        self._collection[:] = cols
1292        self._colset.update(c for k, c in self._collection)
1293        self._index.update(
1294            (idx, c) for idx, (k, c) in enumerate(self._collection)
1295        )
1296        self._index.update({k: col for k, col in reversed(self._collection)})
1297
1298    def add(self, column, key=None):
1299        """Add a column to this :class:`_sql.ColumnCollection`.
1300
1301        .. note::
1302
1303            This method is **not normally used by user-facing code**, as the
1304            :class:`_sql.ColumnCollection` is usually part of an existing
1305            object such as a :class:`_schema.Table`. To add a
1306            :class:`_schema.Column` to an existing :class:`_schema.Table`
1307            object, use the :meth:`_schema.Table.append_column` method.
1308
1309        """
1310        if key is None:
1311            key = column.key
1312
1313        l = len(self._collection)
1314        self._collection.append((key, column))
1315        self._colset.add(column)
1316        self._index[l] = column
1317        if key not in self._index:
1318            self._index[key] = column
1319
1320    def __getstate__(self):
1321        return {"_collection": self._collection, "_index": self._index}
1322
1323    def __setstate__(self, state):
1324        object.__setattr__(self, "_index", state["_index"])
1325        object.__setattr__(self, "_collection", state["_collection"])
1326        object.__setattr__(
1327            self, "_colset", {col for k, col in self._collection}
1328        )
1329
1330    def contains_column(self, col):
1331        """Checks if a column object exists in this collection"""
1332        if col not in self._colset:
1333            if isinstance(col, util.string_types):
1334                raise exc.ArgumentError(
1335                    "contains_column cannot be used with string arguments. "
1336                    "Use ``col_name in table.c`` instead."
1337                )
1338            return False
1339        else:
1340            return True
1341
1342    def as_immutable(self):
1343        """Return an "immutable" form of this
1344        :class:`_sql.ColumnCollection`."""
1345
1346        return ImmutableColumnCollection(self)
1347
1348    def corresponding_column(self, column, require_embedded=False):
1349        """Given a :class:`_expression.ColumnElement`, return the exported
1350        :class:`_expression.ColumnElement` object from this
1351        :class:`_expression.ColumnCollection`
1352        which corresponds to that original :class:`_expression.ColumnElement`
1353        via a common
1354        ancestor column.
1355
1356        :param column: the target :class:`_expression.ColumnElement`
1357                      to be matched.
1358
1359        :param require_embedded: only return corresponding columns for
1360         the given :class:`_expression.ColumnElement`, if the given
1361         :class:`_expression.ColumnElement`
1362         is actually present within a sub-element
1363         of this :class:`_expression.Selectable`.
1364         Normally the column will match if
1365         it merely shares a common ancestor with one of the exported
1366         columns of this :class:`_expression.Selectable`.
1367
1368        .. seealso::
1369
1370            :meth:`_expression.Selectable.corresponding_column`
1371            - invokes this method
1372            against the collection returned by
1373            :attr:`_expression.Selectable.exported_columns`.
1374
1375        .. versionchanged:: 1.4 the implementation for ``corresponding_column``
1376           was moved onto the :class:`_expression.ColumnCollection` itself.
1377
1378        """
1379
1380        def embedded(expanded_proxy_set, target_set):
1381            for t in target_set.difference(expanded_proxy_set):
1382                if not set(_expand_cloned([t])).intersection(
1383                    expanded_proxy_set
1384                ):
1385                    return False
1386            return True
1387
1388        # don't dig around if the column is locally present
1389        if column in self._colset:
1390            return column
1391        col, intersect = None, None
1392        target_set = column.proxy_set
1393        cols = [c for (k, c) in self._collection]
1394        for c in cols:
1395            expanded_proxy_set = set(_expand_cloned(c.proxy_set))
1396            i = target_set.intersection(expanded_proxy_set)
1397            if i and (
1398                not require_embedded
1399                or embedded(expanded_proxy_set, target_set)
1400            ):
1401                if col is None:
1402
1403                    # no corresponding column yet, pick this one.
1404
1405                    col, intersect = c, i
1406                elif len(i) > len(intersect):
1407
1408                    # 'c' has a larger field of correspondence than
1409                    # 'col'. i.e. selectable.c.a1_x->a1.c.x->table.c.x
1410                    # matches a1.c.x->table.c.x better than
1411                    # selectable.c.x->table.c.x does.
1412
1413                    col, intersect = c, i
1414                elif i == intersect:
1415                    # they have the same field of correspondence. see
1416                    # which proxy_set has fewer columns in it, which
1417                    # indicates a closer relationship with the root
1418                    # column. Also take into account the "weight"
1419                    # attribute which CompoundSelect() uses to give
1420                    # higher precedence to columns based on vertical
1421                    # position in the compound statement, and discard
1422                    # columns that have no reference to the target
1423                    # column (also occurs with CompoundSelect)
1424
1425                    col_distance = util.reduce(
1426                        operator.add,
1427                        [
1428                            sc._annotations.get("weight", 1)
1429                            for sc in col._uncached_proxy_set()
1430                            if sc.shares_lineage(column)
1431                        ],
1432                    )
1433                    c_distance = util.reduce(
1434                        operator.add,
1435                        [
1436                            sc._annotations.get("weight", 1)
1437                            for sc in c._uncached_proxy_set()
1438                            if sc.shares_lineage(column)
1439                        ],
1440                    )
1441                    if c_distance < col_distance:
1442                        col, intersect = c, i
1443        return col
1444
1445
1446class DedupeColumnCollection(ColumnCollection):
1447    """A :class:`_expression.ColumnCollection`
1448    that maintains deduplicating behavior.
1449
1450    This is useful by schema level objects such as :class:`_schema.Table` and
1451    :class:`.PrimaryKeyConstraint`.    The collection includes more
1452    sophisticated mutator methods as well to suit schema objects which
1453    require mutable column collections.
1454
1455    .. versionadded:: 1.4
1456
1457    """
1458
1459    def add(self, column, key=None):
1460
1461        if key is not None and column.key != key:
1462            raise exc.ArgumentError(
1463                "DedupeColumnCollection requires columns be under "
1464                "the same key as their .key"
1465            )
1466        key = column.key
1467
1468        if key is None:
1469            raise exc.ArgumentError(
1470                "Can't add unnamed column to column collection"
1471            )
1472
1473        if key in self._index:
1474
1475            existing = self._index[key]
1476
1477            if existing is column:
1478                return
1479
1480            self.replace(column)
1481
1482            # pop out memoized proxy_set as this
1483            # operation may very well be occurring
1484            # in a _make_proxy operation
1485            util.memoized_property.reset(column, "proxy_set")
1486        else:
1487            l = len(self._collection)
1488            self._collection.append((key, column))
1489            self._colset.add(column)
1490            self._index[l] = column
1491            self._index[key] = column
1492
1493    def _populate_separate_keys(self, iter_):
1494        """populate from an iterator of (key, column)"""
1495        cols = list(iter_)
1496
1497        replace_col = []
1498        for k, col in cols:
1499            if col.key != k:
1500                raise exc.ArgumentError(
1501                    "DedupeColumnCollection requires columns be under "
1502                    "the same key as their .key"
1503                )
1504            if col.name in self._index and col.key != col.name:
1505                replace_col.append(col)
1506            elif col.key in self._index:
1507                replace_col.append(col)
1508            else:
1509                self._index[k] = col
1510                self._collection.append((k, col))
1511        self._colset.update(c for (k, c) in self._collection)
1512        self._index.update(
1513            (idx, c) for idx, (k, c) in enumerate(self._collection)
1514        )
1515        for col in replace_col:
1516            self.replace(col)
1517
1518    def extend(self, iter_):
1519        self._populate_separate_keys((col.key, col) for col in iter_)
1520
1521    def remove(self, column):
1522        if column not in self._colset:
1523            raise ValueError(
1524                "Can't remove column %r; column is not in this collection"
1525                % column
1526            )
1527        del self._index[column.key]
1528        self._colset.remove(column)
1529        self._collection[:] = [
1530            (k, c) for (k, c) in self._collection if c is not column
1531        ]
1532        self._index.update(
1533            {idx: col for idx, (k, col) in enumerate(self._collection)}
1534        )
1535        # delete higher index
1536        del self._index[len(self._collection)]
1537
1538    def replace(self, column):
1539        """add the given column to this collection, removing unaliased
1540        versions of this column  as well as existing columns with the
1541        same key.
1542
1543        e.g.::
1544
1545            t = Table('sometable', metadata, Column('col1', Integer))
1546            t.columns.replace(Column('col1', Integer, key='columnone'))
1547
1548        will remove the original 'col1' from the collection, and add
1549        the new column under the name 'columnname'.
1550
1551        Used by schema.Column to override columns during table reflection.
1552
1553        """
1554
1555        remove_col = set()
1556        # remove up to two columns based on matches of name as well as key
1557        if column.name in self._index and column.key != column.name:
1558            other = self._index[column.name]
1559            if other.name == other.key:
1560                remove_col.add(other)
1561
1562        if column.key in self._index:
1563            remove_col.add(self._index[column.key])
1564
1565        new_cols = []
1566        replaced = False
1567        for k, col in self._collection:
1568            if col in remove_col:
1569                if not replaced:
1570                    replaced = True
1571                    new_cols.append((column.key, column))
1572            else:
1573                new_cols.append((k, col))
1574
1575        if remove_col:
1576            self._colset.difference_update(remove_col)
1577
1578        if not replaced:
1579            new_cols.append((column.key, column))
1580
1581        self._colset.add(column)
1582        self._collection[:] = new_cols
1583
1584        self._index.clear()
1585        self._index.update(
1586            {idx: col for idx, (k, col) in enumerate(self._collection)}
1587        )
1588        self._index.update(self._collection)
1589
1590
1591class ImmutableColumnCollection(util.ImmutableContainer, ColumnCollection):
1592    __slots__ = ("_parent",)
1593
1594    def __init__(self, collection):
1595        object.__setattr__(self, "_parent", collection)
1596        object.__setattr__(self, "_colset", collection._colset)
1597        object.__setattr__(self, "_index", collection._index)
1598        object.__setattr__(self, "_collection", collection._collection)
1599
1600    def __getstate__(self):
1601        return {"_parent": self._parent}
1602
1603    def __setstate__(self, state):
1604        parent = state["_parent"]
1605        self.__init__(parent)
1606
1607    add = extend = remove = util.ImmutableContainer._immutable
1608
1609
1610class ColumnSet(util.ordered_column_set):
1611    def contains_column(self, col):
1612        return col in self
1613
1614    def extend(self, cols):
1615        for col in cols:
1616            self.add(col)
1617
1618    def __add__(self, other):
1619        return list(self) + list(other)
1620
1621    def __eq__(self, other):
1622        l = []
1623        for c in other:
1624            for local in self:
1625                if c.shares_lineage(local):
1626                    l.append(c == local)
1627        return elements.and_(*l)
1628
1629    def __hash__(self):
1630        return hash(tuple(x for x in self))
1631
1632
1633def _bind_or_error(schemaitem, msg=None):
1634
1635    util.warn_deprecated_20(
1636        "The ``bind`` argument for schema methods that invoke SQL "
1637        "against an engine or connection will be required in SQLAlchemy 2.0."
1638    )
1639    bind = schemaitem.bind
1640    if not bind:
1641        name = schemaitem.__class__.__name__
1642        label = getattr(
1643            schemaitem, "fullname", getattr(schemaitem, "name", None)
1644        )
1645        if label:
1646            item = "%s object %r" % (name, label)
1647        else:
1648            item = "%s object" % name
1649        if msg is None:
1650            msg = (
1651                "%s is not bound to an Engine or Connection.  "
1652                "Execution can not proceed without a database to execute "
1653                "against." % item
1654            )
1655        raise exc.UnboundExecutionError(msg)
1656    return bind
1657
1658
1659def _entity_namespace(entity):
1660    """Return the nearest .entity_namespace for the given entity.
1661
1662    If not immediately available, does an iterate to find a sub-element
1663    that has one, if any.
1664
1665    """
1666    try:
1667        return entity.entity_namespace
1668    except AttributeError:
1669        for elem in visitors.iterate(entity):
1670            if hasattr(elem, "entity_namespace"):
1671                return elem.entity_namespace
1672        else:
1673            raise
1674
1675
1676def _entity_namespace_key(entity, key, default=NO_ARG):
1677    """Return an entry from an entity_namespace.
1678
1679
1680    Raises :class:`_exc.InvalidRequestError` rather than attribute error
1681    on not found.
1682
1683    """
1684
1685    try:
1686        ns = _entity_namespace(entity)
1687        if default is not NO_ARG:
1688            return getattr(ns, key, default)
1689        else:
1690            return getattr(ns, key)
1691    except AttributeError as err:
1692        util.raise_(
1693            exc.InvalidRequestError(
1694                'Entity namespace for "%s" has no property "%s"'
1695                % (entity, key)
1696            ),
1697            replace_context=err,
1698        )
1699