split platform
This commit is contained in:
commit
8c9b09577d
2261 changed files with 676163 additions and 0 deletions
91
lib/python3.5/site-packages/sqlalchemy/sql/__init__.py
Normal file
91
lib/python3.5/site-packages/sqlalchemy/sql/__init__.py
Normal file
|
|
@ -0,0 +1,91 @@
|
|||
# sql/__init__.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
from .expression import (
|
||||
Alias,
|
||||
ClauseElement,
|
||||
ColumnCollection,
|
||||
ColumnElement,
|
||||
CompoundSelect,
|
||||
Delete,
|
||||
FromClause,
|
||||
Insert,
|
||||
Join,
|
||||
Select,
|
||||
Selectable,
|
||||
TableClause,
|
||||
Update,
|
||||
alias,
|
||||
and_,
|
||||
asc,
|
||||
between,
|
||||
bindparam,
|
||||
case,
|
||||
cast,
|
||||
collate,
|
||||
column,
|
||||
delete,
|
||||
desc,
|
||||
distinct,
|
||||
except_,
|
||||
except_all,
|
||||
exists,
|
||||
extract,
|
||||
false,
|
||||
False_,
|
||||
func,
|
||||
insert,
|
||||
intersect,
|
||||
intersect_all,
|
||||
join,
|
||||
label,
|
||||
literal,
|
||||
literal_column,
|
||||
modifier,
|
||||
not_,
|
||||
null,
|
||||
or_,
|
||||
outerjoin,
|
||||
outparam,
|
||||
over,
|
||||
select,
|
||||
subquery,
|
||||
table,
|
||||
text,
|
||||
true,
|
||||
True_,
|
||||
tuple_,
|
||||
type_coerce,
|
||||
union,
|
||||
union_all,
|
||||
update,
|
||||
)
|
||||
|
||||
from .visitors import ClauseVisitor
|
||||
|
||||
|
||||
def __go(lcls):
|
||||
global __all__
|
||||
from .. import util as _sa_util
|
||||
|
||||
import inspect as _inspect
|
||||
|
||||
__all__ = sorted(name for name, obj in lcls.items()
|
||||
if not (name.startswith('_') or _inspect.ismodule(obj)))
|
||||
|
||||
from .annotation import _prepare_annotations, Annotated
|
||||
from .elements import AnnotatedColumnElement, ClauseList
|
||||
from .selectable import AnnotatedFromClause
|
||||
_prepare_annotations(ColumnElement, AnnotatedColumnElement)
|
||||
_prepare_annotations(FromClause, AnnotatedFromClause)
|
||||
_prepare_annotations(ClauseList, Annotated)
|
||||
|
||||
_sa_util.dependencies.resolve_all("sqlalchemy.sql")
|
||||
|
||||
from . import naming
|
||||
|
||||
__go(locals())
|
||||
195
lib/python3.5/site-packages/sqlalchemy/sql/annotation.py
Normal file
195
lib/python3.5/site-packages/sqlalchemy/sql/annotation.py
Normal file
|
|
@ -0,0 +1,195 @@
|
|||
# sql/annotation.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""The :class:`.Annotated` class and related routines; creates hash-equivalent
|
||||
copies of SQL constructs which contain context-specific markers and
|
||||
associations.
|
||||
|
||||
"""
|
||||
|
||||
from .. import util
|
||||
from . import operators
|
||||
|
||||
|
||||
class Annotated(object):
|
||||
"""clones a ClauseElement and applies an 'annotations' dictionary.
|
||||
|
||||
Unlike regular clones, this clone also mimics __hash__() and
|
||||
__cmp__() of the original element so that it takes its place
|
||||
in hashed collections.
|
||||
|
||||
A reference to the original element is maintained, for the important
|
||||
reason of keeping its hash value current. When GC'ed, the
|
||||
hash value may be reused, causing conflicts.
|
||||
|
||||
"""
|
||||
|
||||
def __new__(cls, *args):
|
||||
if not args:
|
||||
# clone constructor
|
||||
return object.__new__(cls)
|
||||
else:
|
||||
element, values = args
|
||||
# pull appropriate subclass from registry of annotated
|
||||
# classes
|
||||
try:
|
||||
cls = annotated_classes[element.__class__]
|
||||
except KeyError:
|
||||
cls = _new_annotation_type(element.__class__, cls)
|
||||
return object.__new__(cls)
|
||||
|
||||
def __init__(self, element, values):
|
||||
self.__dict__ = element.__dict__.copy()
|
||||
self.__element = element
|
||||
self._annotations = values
|
||||
|
||||
def _annotate(self, values):
|
||||
_values = self._annotations.copy()
|
||||
_values.update(values)
|
||||
return self._with_annotations(_values)
|
||||
|
||||
def _with_annotations(self, values):
|
||||
clone = self.__class__.__new__(self.__class__)
|
||||
clone.__dict__ = self.__dict__.copy()
|
||||
clone._annotations = values
|
||||
return clone
|
||||
|
||||
def _deannotate(self, values=None, clone=True):
|
||||
if values is None:
|
||||
return self.__element
|
||||
else:
|
||||
_values = self._annotations.copy()
|
||||
for v in values:
|
||||
_values.pop(v, None)
|
||||
return self._with_annotations(_values)
|
||||
|
||||
def _compiler_dispatch(self, visitor, **kw):
|
||||
return self.__element.__class__._compiler_dispatch(
|
||||
self, visitor, **kw)
|
||||
|
||||
@property
|
||||
def _constructor(self):
|
||||
return self.__element._constructor
|
||||
|
||||
def _clone(self):
|
||||
clone = self.__element._clone()
|
||||
if clone is self.__element:
|
||||
# detect immutable, don't change anything
|
||||
return self
|
||||
else:
|
||||
# update the clone with any changes that have occurred
|
||||
# to this object's __dict__.
|
||||
clone.__dict__.update(self.__dict__)
|
||||
return self.__class__(clone, self._annotations)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(self.__element)
|
||||
|
||||
def __eq__(self, other):
|
||||
if isinstance(self.__element, operators.ColumnOperators):
|
||||
return self.__element.__class__.__eq__(self, other)
|
||||
else:
|
||||
return hash(other) == hash(self)
|
||||
|
||||
|
||||
# hard-generate Annotated subclasses. this technique
|
||||
# is used instead of on-the-fly types (i.e. type.__new__())
|
||||
# so that the resulting objects are pickleable.
|
||||
annotated_classes = {}
|
||||
|
||||
|
||||
def _deep_annotate(element, annotations, exclude=None):
|
||||
"""Deep copy the given ClauseElement, annotating each element
|
||||
with the given annotations dictionary.
|
||||
|
||||
Elements within the exclude collection will be cloned but not annotated.
|
||||
|
||||
"""
|
||||
def clone(elem):
|
||||
if exclude and \
|
||||
hasattr(elem, 'proxy_set') and \
|
||||
elem.proxy_set.intersection(exclude):
|
||||
newelem = elem._clone()
|
||||
elif annotations != elem._annotations:
|
||||
newelem = elem._annotate(annotations)
|
||||
else:
|
||||
newelem = elem
|
||||
newelem._copy_internals(clone=clone)
|
||||
return newelem
|
||||
|
||||
if element is not None:
|
||||
element = clone(element)
|
||||
return element
|
||||
|
||||
|
||||
def _deep_deannotate(element, values=None):
|
||||
"""Deep copy the given element, removing annotations."""
|
||||
|
||||
cloned = util.column_dict()
|
||||
|
||||
def clone(elem):
|
||||
# if a values dict is given,
|
||||
# the elem must be cloned each time it appears,
|
||||
# as there may be different annotations in source
|
||||
# elements that are remaining. if totally
|
||||
# removing all annotations, can assume the same
|
||||
# slate...
|
||||
if values or elem not in cloned:
|
||||
newelem = elem._deannotate(values=values, clone=True)
|
||||
newelem._copy_internals(clone=clone)
|
||||
if not values:
|
||||
cloned[elem] = newelem
|
||||
return newelem
|
||||
else:
|
||||
return cloned[elem]
|
||||
|
||||
if element is not None:
|
||||
element = clone(element)
|
||||
return element
|
||||
|
||||
|
||||
def _shallow_annotate(element, annotations):
|
||||
"""Annotate the given ClauseElement and copy its internals so that
|
||||
internal objects refer to the new annotated object.
|
||||
|
||||
Basically used to apply a "dont traverse" annotation to a
|
||||
selectable, without digging throughout the whole
|
||||
structure wasting time.
|
||||
"""
|
||||
element = element._annotate(annotations)
|
||||
element._copy_internals()
|
||||
return element
|
||||
|
||||
|
||||
def _new_annotation_type(cls, base_cls):
|
||||
if issubclass(cls, Annotated):
|
||||
return cls
|
||||
elif cls in annotated_classes:
|
||||
return annotated_classes[cls]
|
||||
|
||||
for super_ in cls.__mro__:
|
||||
# check if an Annotated subclass more specific than
|
||||
# the given base_cls is already registered, such
|
||||
# as AnnotatedColumnElement.
|
||||
if super_ in annotated_classes:
|
||||
base_cls = annotated_classes[super_]
|
||||
break
|
||||
|
||||
annotated_classes[cls] = anno_cls = type(
|
||||
"Annotated%s" % cls.__name__,
|
||||
(base_cls, cls), {})
|
||||
globals()["Annotated%s" % cls.__name__] = anno_cls
|
||||
return anno_cls
|
||||
|
||||
|
||||
def _prepare_annotations(target_hierarchy, base_cls):
|
||||
stack = [target_hierarchy]
|
||||
while stack:
|
||||
cls = stack.pop()
|
||||
stack.extend(cls.__subclasses__())
|
||||
|
||||
_new_annotation_type(cls, base_cls)
|
||||
642
lib/python3.5/site-packages/sqlalchemy/sql/base.py
Normal file
642
lib/python3.5/site-packages/sqlalchemy/sql/base.py
Normal file
|
|
@ -0,0 +1,642 @@
|
|||
# sql/base.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Foundational utilities common to many sql modules.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
from .. import util, exc
|
||||
import itertools
|
||||
from .visitors import ClauseVisitor
|
||||
import re
|
||||
import collections
|
||||
|
||||
PARSE_AUTOCOMMIT = util.symbol('PARSE_AUTOCOMMIT')
|
||||
NO_ARG = util.symbol('NO_ARG')
|
||||
|
||||
|
||||
class Immutable(object):
|
||||
"""mark a ClauseElement as 'immutable' when expressions are cloned."""
|
||||
|
||||
def unique_params(self, *optionaldict, **kwargs):
|
||||
raise NotImplementedError("Immutable objects do not support copying")
|
||||
|
||||
def params(self, *optionaldict, **kwargs):
|
||||
raise NotImplementedError("Immutable objects do not support copying")
|
||||
|
||||
def _clone(self):
|
||||
return self
|
||||
|
||||
|
||||
def _from_objects(*elements):
|
||||
return itertools.chain(*[element._from_objects for element in elements])
|
||||
|
||||
|
||||
@util.decorator
|
||||
def _generative(fn, *args, **kw):
|
||||
"""Mark a method as generative."""
|
||||
|
||||
self = args[0]._generate()
|
||||
fn(self, *args[1:], **kw)
|
||||
return self
|
||||
|
||||
|
||||
class _DialectArgView(collections.MutableMapping):
|
||||
"""A dictionary view of dialect-level arguments in the form
|
||||
<dialectname>_<argument_name>.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, obj):
|
||||
self.obj = obj
|
||||
|
||||
def _key(self, key):
|
||||
try:
|
||||
dialect, value_key = key.split("_", 1)
|
||||
except ValueError:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
return dialect, value_key
|
||||
|
||||
def __getitem__(self, key):
|
||||
dialect, value_key = self._key(key)
|
||||
|
||||
try:
|
||||
opt = self.obj.dialect_options[dialect]
|
||||
except exc.NoSuchModuleError:
|
||||
raise KeyError(key)
|
||||
else:
|
||||
return opt[value_key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
try:
|
||||
dialect, value_key = self._key(key)
|
||||
except KeyError:
|
||||
raise exc.ArgumentError(
|
||||
"Keys must be of the form <dialectname>_<argname>")
|
||||
else:
|
||||
self.obj.dialect_options[dialect][value_key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
dialect, value_key = self._key(key)
|
||||
del self.obj.dialect_options[dialect][value_key]
|
||||
|
||||
def __len__(self):
|
||||
return sum(len(args._non_defaults) for args in
|
||||
self.obj.dialect_options.values())
|
||||
|
||||
def __iter__(self):
|
||||
return (
|
||||
util.safe_kwarg("%s_%s" % (dialect_name, value_name))
|
||||
for dialect_name in self.obj.dialect_options
|
||||
for value_name in
|
||||
self.obj.dialect_options[dialect_name]._non_defaults
|
||||
)
|
||||
|
||||
|
||||
class _DialectArgDict(collections.MutableMapping):
|
||||
"""A dictionary view of dialect-level arguments for a specific
|
||||
dialect.
|
||||
|
||||
Maintains a separate collection of user-specified arguments
|
||||
and dialect-specified default arguments.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
self._non_defaults = {}
|
||||
self._defaults = {}
|
||||
|
||||
def __len__(self):
|
||||
return len(set(self._non_defaults).union(self._defaults))
|
||||
|
||||
def __iter__(self):
|
||||
return iter(set(self._non_defaults).union(self._defaults))
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key in self._non_defaults:
|
||||
return self._non_defaults[key]
|
||||
else:
|
||||
return self._defaults[key]
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
self._non_defaults[key] = value
|
||||
|
||||
def __delitem__(self, key):
|
||||
del self._non_defaults[key]
|
||||
|
||||
|
||||
class DialectKWArgs(object):
|
||||
"""Establish the ability for a class to have dialect-specific arguments
|
||||
with defaults and constructor validation.
|
||||
|
||||
The :class:`.DialectKWArgs` interacts with the
|
||||
:attr:`.DefaultDialect.construct_arguments` present on a dialect.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:attr:`.DefaultDialect.construct_arguments`
|
||||
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def argument_for(cls, dialect_name, argument_name, default):
|
||||
"""Add a new kind of dialect-specific keyword argument for this class.
|
||||
|
||||
E.g.::
|
||||
|
||||
Index.argument_for("mydialect", "length", None)
|
||||
|
||||
some_index = Index('a', 'b', mydialect_length=5)
|
||||
|
||||
The :meth:`.DialectKWArgs.argument_for` method is a per-argument
|
||||
way adding extra arguments to the
|
||||
:attr:`.DefaultDialect.construct_arguments` dictionary. This
|
||||
dictionary provides a list of argument names accepted by various
|
||||
schema-level constructs on behalf of a dialect.
|
||||
|
||||
New dialects should typically specify this dictionary all at once as a
|
||||
data member of the dialect class. The use case for ad-hoc addition of
|
||||
argument names is typically for end-user code that is also using
|
||||
a custom compilation scheme which consumes the additional arguments.
|
||||
|
||||
:param dialect_name: name of a dialect. The dialect must be
|
||||
locatable, else a :class:`.NoSuchModuleError` is raised. The
|
||||
dialect must also include an existing
|
||||
:attr:`.DefaultDialect.construct_arguments` collection, indicating
|
||||
that it participates in the keyword-argument validation and default
|
||||
system, else :class:`.ArgumentError` is raised. If the dialect does
|
||||
not include this collection, then any keyword argument can be
|
||||
specified on behalf of this dialect already. All dialects packaged
|
||||
within SQLAlchemy include this collection, however for third party
|
||||
dialects, support may vary.
|
||||
|
||||
:param argument_name: name of the parameter.
|
||||
|
||||
:param default: default value of the parameter.
|
||||
|
||||
.. versionadded:: 0.9.4
|
||||
|
||||
"""
|
||||
|
||||
construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name]
|
||||
if construct_arg_dictionary is None:
|
||||
raise exc.ArgumentError(
|
||||
"Dialect '%s' does have keyword-argument "
|
||||
"validation and defaults enabled configured" %
|
||||
dialect_name)
|
||||
if cls not in construct_arg_dictionary:
|
||||
construct_arg_dictionary[cls] = {}
|
||||
construct_arg_dictionary[cls][argument_name] = default
|
||||
|
||||
@util.memoized_property
|
||||
def dialect_kwargs(self):
|
||||
"""A collection of keyword arguments specified as dialect-specific
|
||||
options to this construct.
|
||||
|
||||
The arguments are present here in their original ``<dialect>_<kwarg>``
|
||||
format. Only arguments that were actually passed are included;
|
||||
unlike the :attr:`.DialectKWArgs.dialect_options` collection, which
|
||||
contains all options known by this dialect including defaults.
|
||||
|
||||
The collection is also writable; keys are accepted of the
|
||||
form ``<dialect>_<kwarg>`` where the value will be assembled
|
||||
into the list of options.
|
||||
|
||||
.. versionadded:: 0.9.2
|
||||
|
||||
.. versionchanged:: 0.9.4 The :attr:`.DialectKWArgs.dialect_kwargs`
|
||||
collection is now writable.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:attr:`.DialectKWArgs.dialect_options` - nested dictionary form
|
||||
|
||||
"""
|
||||
return _DialectArgView(self)
|
||||
|
||||
@property
|
||||
def kwargs(self):
|
||||
"""A synonym for :attr:`.DialectKWArgs.dialect_kwargs`."""
|
||||
return self.dialect_kwargs
|
||||
|
||||
@util.dependencies("sqlalchemy.dialects")
|
||||
def _kw_reg_for_dialect(dialects, dialect_name):
|
||||
dialect_cls = dialects.registry.load(dialect_name)
|
||||
if dialect_cls.construct_arguments is None:
|
||||
return None
|
||||
return dict(dialect_cls.construct_arguments)
|
||||
_kw_registry = util.PopulateDict(_kw_reg_for_dialect)
|
||||
|
||||
def _kw_reg_for_dialect_cls(self, dialect_name):
|
||||
construct_arg_dictionary = DialectKWArgs._kw_registry[dialect_name]
|
||||
d = _DialectArgDict()
|
||||
|
||||
if construct_arg_dictionary is None:
|
||||
d._defaults.update({"*": None})
|
||||
else:
|
||||
for cls in reversed(self.__class__.__mro__):
|
||||
if cls in construct_arg_dictionary:
|
||||
d._defaults.update(construct_arg_dictionary[cls])
|
||||
return d
|
||||
|
||||
@util.memoized_property
|
||||
def dialect_options(self):
|
||||
"""A collection of keyword arguments specified as dialect-specific
|
||||
options to this construct.
|
||||
|
||||
This is a two-level nested registry, keyed to ``<dialect_name>``
|
||||
and ``<argument_name>``. For example, the ``postgresql_where``
|
||||
argument would be locatable as::
|
||||
|
||||
arg = my_object.dialect_options['postgresql']['where']
|
||||
|
||||
.. versionadded:: 0.9.2
|
||||
|
||||
.. seealso::
|
||||
|
||||
:attr:`.DialectKWArgs.dialect_kwargs` - flat dictionary form
|
||||
|
||||
"""
|
||||
|
||||
return util.PopulateDict(
|
||||
util.portable_instancemethod(self._kw_reg_for_dialect_cls)
|
||||
)
|
||||
|
||||
def _validate_dialect_kwargs(self, kwargs):
|
||||
# validate remaining kwargs that they all specify DB prefixes
|
||||
|
||||
if not kwargs:
|
||||
return
|
||||
|
||||
for k in kwargs:
|
||||
m = re.match('^(.+?)_(.+)$', k)
|
||||
if not m:
|
||||
raise TypeError(
|
||||
"Additional arguments should be "
|
||||
"named <dialectname>_<argument>, got '%s'" % k)
|
||||
dialect_name, arg_name = m.group(1, 2)
|
||||
|
||||
try:
|
||||
construct_arg_dictionary = self.dialect_options[dialect_name]
|
||||
except exc.NoSuchModuleError:
|
||||
util.warn(
|
||||
"Can't validate argument %r; can't "
|
||||
"locate any SQLAlchemy dialect named %r" %
|
||||
(k, dialect_name))
|
||||
self.dialect_options[dialect_name] = d = _DialectArgDict()
|
||||
d._defaults.update({"*": None})
|
||||
d._non_defaults[arg_name] = kwargs[k]
|
||||
else:
|
||||
if "*" not in construct_arg_dictionary and \
|
||||
arg_name not in construct_arg_dictionary:
|
||||
raise exc.ArgumentError(
|
||||
"Argument %r is not accepted by "
|
||||
"dialect %r on behalf of %r" % (
|
||||
k,
|
||||
dialect_name, self.__class__
|
||||
))
|
||||
else:
|
||||
construct_arg_dictionary[arg_name] = kwargs[k]
|
||||
|
||||
|
||||
class Generative(object):
|
||||
"""Allow a ClauseElement to generate itself via the
|
||||
@_generative decorator.
|
||||
|
||||
"""
|
||||
|
||||
def _generate(self):
|
||||
s = self.__class__.__new__(self.__class__)
|
||||
s.__dict__ = self.__dict__.copy()
|
||||
return s
|
||||
|
||||
|
||||
class Executable(Generative):
|
||||
"""Mark a ClauseElement as supporting execution.
|
||||
|
||||
:class:`.Executable` is a superclass for all "statement" types
|
||||
of objects, including :func:`select`, :func:`delete`, :func:`update`,
|
||||
:func:`insert`, :func:`text`.
|
||||
|
||||
"""
|
||||
|
||||
supports_execution = True
|
||||
_execution_options = util.immutabledict()
|
||||
_bind = None
|
||||
|
||||
@_generative
|
||||
def execution_options(self, **kw):
|
||||
""" Set non-SQL options for the statement which take effect during
|
||||
execution.
|
||||
|
||||
Execution options can be set on a per-statement or
|
||||
per :class:`.Connection` basis. Additionally, the
|
||||
:class:`.Engine` and ORM :class:`~.orm.query.Query` objects provide
|
||||
access to execution options which they in turn configure upon
|
||||
connections.
|
||||
|
||||
The :meth:`execution_options` method is generative. A new
|
||||
instance of this statement is returned that contains the options::
|
||||
|
||||
statement = select([table.c.x, table.c.y])
|
||||
statement = statement.execution_options(autocommit=True)
|
||||
|
||||
Note that only a subset of possible execution options can be applied
|
||||
to a statement - these include "autocommit" and "stream_results",
|
||||
but not "isolation_level" or "compiled_cache".
|
||||
See :meth:`.Connection.execution_options` for a full list of
|
||||
possible options.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.Connection.execution_options()`
|
||||
|
||||
:meth:`.Query.execution_options()`
|
||||
|
||||
"""
|
||||
if 'isolation_level' in kw:
|
||||
raise exc.ArgumentError(
|
||||
"'isolation_level' execution option may only be specified "
|
||||
"on Connection.execution_options(), or "
|
||||
"per-engine using the isolation_level "
|
||||
"argument to create_engine()."
|
||||
)
|
||||
if 'compiled_cache' in kw:
|
||||
raise exc.ArgumentError(
|
||||
"'compiled_cache' execution option may only be specified "
|
||||
"on Connection.execution_options(), not per statement."
|
||||
)
|
||||
self._execution_options = self._execution_options.union(kw)
|
||||
|
||||
def execute(self, *multiparams, **params):
|
||||
"""Compile and execute this :class:`.Executable`."""
|
||||
e = self.bind
|
||||
if e is None:
|
||||
label = getattr(self, 'description', self.__class__.__name__)
|
||||
msg = ('This %s is not directly bound to a Connection or Engine.'
|
||||
'Use the .execute() method of a Connection or Engine '
|
||||
'to execute this construct.' % label)
|
||||
raise exc.UnboundExecutionError(msg)
|
||||
return e._execute_clauseelement(self, multiparams, params)
|
||||
|
||||
def scalar(self, *multiparams, **params):
|
||||
"""Compile and execute this :class:`.Executable`, returning the
|
||||
result's scalar representation.
|
||||
|
||||
"""
|
||||
return self.execute(*multiparams, **params).scalar()
|
||||
|
||||
@property
|
||||
def bind(self):
|
||||
"""Returns the :class:`.Engine` or :class:`.Connection` to
|
||||
which this :class:`.Executable` is bound, or None if none found.
|
||||
|
||||
This is a traversal which checks locally, then
|
||||
checks among the "from" clauses of associated objects
|
||||
until a bound engine or connection is found.
|
||||
|
||||
"""
|
||||
if self._bind is not None:
|
||||
return self._bind
|
||||
|
||||
for f in _from_objects(self):
|
||||
if f is self:
|
||||
continue
|
||||
engine = f.bind
|
||||
if engine is not None:
|
||||
return engine
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
class SchemaEventTarget(object):
|
||||
"""Base class for elements that are the targets of :class:`.DDLEvents`
|
||||
events.
|
||||
|
||||
This includes :class:`.SchemaItem` as well as :class:`.SchemaType`.
|
||||
|
||||
"""
|
||||
|
||||
def _set_parent(self, parent):
|
||||
"""Associate with this SchemaEvent's parent object."""
|
||||
|
||||
raise NotImplementedError()
|
||||
|
||||
def _set_parent_with_dispatch(self, parent):
|
||||
self.dispatch.before_parent_attach(self, parent)
|
||||
self._set_parent(parent)
|
||||
self.dispatch.after_parent_attach(self, parent)
|
||||
|
||||
|
||||
class SchemaVisitor(ClauseVisitor):
|
||||
"""Define the visiting for ``SchemaItem`` objects."""
|
||||
|
||||
__traverse_options__ = {'schema_visitor': True}
|
||||
|
||||
|
||||
class ColumnCollection(util.OrderedProperties):
|
||||
"""An ordered dictionary that stores a list of ColumnElement
|
||||
instances.
|
||||
|
||||
Overrides the ``__eq__()`` method to produce SQL clauses between
|
||||
sets of correlated columns.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self):
|
||||
super(ColumnCollection, self).__init__()
|
||||
self.__dict__['_all_col_set'] = util.column_set()
|
||||
self.__dict__['_all_columns'] = []
|
||||
|
||||
def __str__(self):
|
||||
return repr([str(c) for c in self])
|
||||
|
||||
def replace(self, column):
|
||||
"""add the given column to this collection, removing unaliased
|
||||
versions of this column as well as existing columns with the
|
||||
same key.
|
||||
|
||||
e.g.::
|
||||
|
||||
t = Table('sometable', metadata, Column('col1', Integer))
|
||||
t.columns.replace(Column('col1', Integer, key='columnone'))
|
||||
|
||||
will remove the original 'col1' from the collection, and add
|
||||
the new column under the name 'columnname'.
|
||||
|
||||
Used by schema.Column to override columns during table reflection.
|
||||
|
||||
"""
|
||||
remove_col = None
|
||||
if column.name in self and column.key != column.name:
|
||||
other = self[column.name]
|
||||
if other.name == other.key:
|
||||
remove_col = other
|
||||
self._all_col_set.remove(other)
|
||||
del self._data[other.key]
|
||||
|
||||
if column.key in self._data:
|
||||
remove_col = self._data[column.key]
|
||||
self._all_col_set.remove(remove_col)
|
||||
|
||||
self._all_col_set.add(column)
|
||||
self._data[column.key] = column
|
||||
if remove_col is not None:
|
||||
self._all_columns[:] = [column if c is remove_col
|
||||
else c for c in self._all_columns]
|
||||
else:
|
||||
self._all_columns.append(column)
|
||||
|
||||
def add(self, column):
|
||||
"""Add a column to this collection.
|
||||
|
||||
The key attribute of the column will be used as the hash key
|
||||
for this dictionary.
|
||||
|
||||
"""
|
||||
if not column.key:
|
||||
raise exc.ArgumentError(
|
||||
"Can't add unnamed column to column collection")
|
||||
self[column.key] = column
|
||||
|
||||
def __delitem__(self, key):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __setattr__(self, key, object):
|
||||
raise NotImplementedError()
|
||||
|
||||
def __setitem__(self, key, value):
|
||||
if key in self:
|
||||
|
||||
# this warning is primarily to catch select() statements
|
||||
# which have conflicting column names in their exported
|
||||
# columns collection
|
||||
|
||||
existing = self[key]
|
||||
if not existing.shares_lineage(value):
|
||||
util.warn('Column %r on table %r being replaced by '
|
||||
'%r, which has the same key. Consider '
|
||||
'use_labels for select() statements.' %
|
||||
(key, getattr(existing, 'table', None), value))
|
||||
|
||||
# pop out memoized proxy_set as this
|
||||
# operation may very well be occurring
|
||||
# in a _make_proxy operation
|
||||
util.memoized_property.reset(value, "proxy_set")
|
||||
|
||||
self._all_col_set.add(value)
|
||||
self._all_columns.append(value)
|
||||
self._data[key] = value
|
||||
|
||||
def clear(self):
|
||||
raise NotImplementedError()
|
||||
|
||||
def remove(self, column):
|
||||
del self._data[column.key]
|
||||
self._all_col_set.remove(column)
|
||||
self._all_columns[:] = [
|
||||
c for c in self._all_columns if c is not column]
|
||||
|
||||
def update(self, iter):
|
||||
cols = list(iter)
|
||||
self._all_columns.extend(
|
||||
c for label, c in cols if c not in self._all_col_set)
|
||||
self._all_col_set.update(c for label, c in cols)
|
||||
self._data.update((label, c) for label, c in cols)
|
||||
|
||||
def extend(self, iter):
|
||||
cols = list(iter)
|
||||
self._all_columns.extend(c for c in cols if c not in
|
||||
self._all_col_set)
|
||||
self._all_col_set.update(cols)
|
||||
self._data.update((c.key, c) for c in cols)
|
||||
|
||||
__hash__ = None
|
||||
|
||||
@util.dependencies("sqlalchemy.sql.elements")
|
||||
def __eq__(self, elements, other):
|
||||
l = []
|
||||
for c in getattr(other, "_all_columns", other):
|
||||
for local in self._all_columns:
|
||||
if c.shares_lineage(local):
|
||||
l.append(c == local)
|
||||
return elements.and_(*l)
|
||||
|
||||
def __contains__(self, other):
|
||||
if not isinstance(other, util.string_types):
|
||||
raise exc.ArgumentError("__contains__ requires a string argument")
|
||||
return util.OrderedProperties.__contains__(self, other)
|
||||
|
||||
def __getstate__(self):
|
||||
return {'_data': self.__dict__['_data'],
|
||||
'_all_columns': self.__dict__['_all_columns']}
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__['_data'] = state['_data']
|
||||
self.__dict__['_all_columns'] = state['_all_columns']
|
||||
self.__dict__['_all_col_set'] = util.column_set(state['_all_columns'])
|
||||
|
||||
def contains_column(self, col):
|
||||
# this has to be done via set() membership
|
||||
return col in self._all_col_set
|
||||
|
||||
def as_immutable(self):
|
||||
return ImmutableColumnCollection(
|
||||
self._data, self._all_col_set, self._all_columns)
|
||||
|
||||
|
||||
class ImmutableColumnCollection(util.ImmutableProperties, ColumnCollection):
|
||||
def __init__(self, data, colset, all_columns):
|
||||
util.ImmutableProperties.__init__(self, data)
|
||||
self.__dict__['_all_col_set'] = colset
|
||||
self.__dict__['_all_columns'] = all_columns
|
||||
|
||||
extend = remove = util.ImmutableProperties._immutable
|
||||
|
||||
|
||||
class ColumnSet(util.ordered_column_set):
|
||||
def contains_column(self, col):
|
||||
return col in self
|
||||
|
||||
def extend(self, cols):
|
||||
for col in cols:
|
||||
self.add(col)
|
||||
|
||||
def __add__(self, other):
|
||||
return list(self) + list(other)
|
||||
|
||||
@util.dependencies("sqlalchemy.sql.elements")
|
||||
def __eq__(self, elements, other):
|
||||
l = []
|
||||
for c in other:
|
||||
for local in self:
|
||||
if c.shares_lineage(local):
|
||||
l.append(c == local)
|
||||
return elements.and_(*l)
|
||||
|
||||
def __hash__(self):
|
||||
return hash(tuple(x for x in self))
|
||||
|
||||
|
||||
def _bind_or_error(schemaitem, msg=None):
|
||||
bind = schemaitem.bind
|
||||
if not bind:
|
||||
name = schemaitem.__class__.__name__
|
||||
label = getattr(schemaitem, 'fullname',
|
||||
getattr(schemaitem, 'name', None))
|
||||
if label:
|
||||
item = '%s object %r' % (name, label)
|
||||
else:
|
||||
item = '%s object' % name
|
||||
if msg is None:
|
||||
msg = "%s is not bound to an Engine or Connection. "\
|
||||
"Execution can not proceed without a database to execute "\
|
||||
"against." % item
|
||||
raise exc.UnboundExecutionError(msg)
|
||||
return bind
|
||||
3004
lib/python3.5/site-packages/sqlalchemy/sql/compiler.py
Normal file
3004
lib/python3.5/site-packages/sqlalchemy/sql/compiler.py
Normal file
File diff suppressed because it is too large
Load diff
868
lib/python3.5/site-packages/sqlalchemy/sql/ddl.py
Normal file
868
lib/python3.5/site-packages/sqlalchemy/sql/ddl.py
Normal file
|
|
@ -0,0 +1,868 @@
|
|||
# sql/ddl.py
|
||||
# Copyright (C) 2009-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
"""
|
||||
Provides the hierarchy of DDL-defining schema items as well as routines
|
||||
to invoke them for a create/drop call.
|
||||
|
||||
"""
|
||||
|
||||
from .. import util
|
||||
from .elements import ClauseElement
|
||||
from .visitors import traverse
|
||||
from .base import Executable, _generative, SchemaVisitor, _bind_or_error
|
||||
from ..util import topological
|
||||
from .. import event
|
||||
from .. import exc
|
||||
|
||||
|
||||
class _DDLCompiles(ClauseElement):
|
||||
def _compiler(self, dialect, **kw):
|
||||
"""Return a compiler appropriate for this ClauseElement, given a
|
||||
Dialect."""
|
||||
|
||||
return dialect.ddl_compiler(dialect, self, **kw)
|
||||
|
||||
|
||||
class DDLElement(Executable, _DDLCompiles):
|
||||
"""Base class for DDL expression constructs.
|
||||
|
||||
This class is the base for the general purpose :class:`.DDL` class,
|
||||
as well as the various create/drop clause constructs such as
|
||||
:class:`.CreateTable`, :class:`.DropTable`, :class:`.AddConstraint`,
|
||||
etc.
|
||||
|
||||
:class:`.DDLElement` integrates closely with SQLAlchemy events,
|
||||
introduced in :ref:`event_toplevel`. An instance of one is
|
||||
itself an event receiving callable::
|
||||
|
||||
event.listen(
|
||||
users,
|
||||
'after_create',
|
||||
AddConstraint(constraint).execute_if(dialect='postgresql')
|
||||
)
|
||||
|
||||
.. seealso::
|
||||
|
||||
:class:`.DDL`
|
||||
|
||||
:class:`.DDLEvents`
|
||||
|
||||
:ref:`event_toplevel`
|
||||
|
||||
:ref:`schema_ddl_sequences`
|
||||
|
||||
"""
|
||||
|
||||
_execution_options = Executable.\
|
||||
_execution_options.union({'autocommit': True})
|
||||
|
||||
target = None
|
||||
on = None
|
||||
dialect = None
|
||||
callable_ = None
|
||||
|
||||
def _execute_on_connection(self, connection, multiparams, params):
|
||||
return connection._execute_ddl(self, multiparams, params)
|
||||
|
||||
def execute(self, bind=None, target=None):
|
||||
"""Execute this DDL immediately.
|
||||
|
||||
Executes the DDL statement in isolation using the supplied
|
||||
:class:`.Connectable` or
|
||||
:class:`.Connectable` assigned to the ``.bind``
|
||||
property, if not supplied. If the DDL has a conditional ``on``
|
||||
criteria, it will be invoked with None as the event.
|
||||
|
||||
:param bind:
|
||||
Optional, an ``Engine`` or ``Connection``. If not supplied, a valid
|
||||
:class:`.Connectable` must be present in the
|
||||
``.bind`` property.
|
||||
|
||||
:param target:
|
||||
Optional, defaults to None. The target SchemaItem for the
|
||||
execute call. Will be passed to the ``on`` callable if any,
|
||||
and may also provide string expansion data for the
|
||||
statement. See ``execute_at`` for more information.
|
||||
|
||||
"""
|
||||
|
||||
if bind is None:
|
||||
bind = _bind_or_error(self)
|
||||
|
||||
if self._should_execute(target, bind):
|
||||
return bind.execute(self.against(target))
|
||||
else:
|
||||
bind.engine.logger.info(
|
||||
"DDL execution skipped, criteria not met.")
|
||||
|
||||
@util.deprecated("0.7", "See :class:`.DDLEvents`, as well as "
|
||||
":meth:`.DDLElement.execute_if`.")
|
||||
def execute_at(self, event_name, target):
|
||||
"""Link execution of this DDL to the DDL lifecycle of a SchemaItem.
|
||||
|
||||
Links this ``DDLElement`` to a ``Table`` or ``MetaData`` instance,
|
||||
executing it when that schema item is created or dropped. The DDL
|
||||
statement will be executed using the same Connection and transactional
|
||||
context as the Table create/drop itself. The ``.bind`` property of
|
||||
this statement is ignored.
|
||||
|
||||
:param event:
|
||||
One of the events defined in the schema item's ``.ddl_events``;
|
||||
e.g. 'before-create', 'after-create', 'before-drop' or 'after-drop'
|
||||
|
||||
:param target:
|
||||
The Table or MetaData instance for which this DDLElement will
|
||||
be associated with.
|
||||
|
||||
A DDLElement instance can be linked to any number of schema items.
|
||||
|
||||
``execute_at`` builds on the ``append_ddl_listener`` interface of
|
||||
:class:`.MetaData` and :class:`.Table` objects.
|
||||
|
||||
Caveat: Creating or dropping a Table in isolation will also trigger
|
||||
any DDL set to ``execute_at`` that Table's MetaData. This may change
|
||||
in a future release.
|
||||
|
||||
"""
|
||||
|
||||
def call_event(target, connection, **kw):
|
||||
if self._should_execute_deprecated(event_name,
|
||||
target, connection, **kw):
|
||||
return connection.execute(self.against(target))
|
||||
|
||||
event.listen(target, "" + event_name.replace('-', '_'), call_event)
|
||||
|
||||
@_generative
|
||||
def against(self, target):
|
||||
"""Return a copy of this DDL against a specific schema item."""
|
||||
|
||||
self.target = target
|
||||
|
||||
@_generative
|
||||
def execute_if(self, dialect=None, callable_=None, state=None):
|
||||
"""Return a callable that will execute this
|
||||
DDLElement conditionally.
|
||||
|
||||
Used to provide a wrapper for event listening::
|
||||
|
||||
event.listen(
|
||||
metadata,
|
||||
'before_create',
|
||||
DDL("my_ddl").execute_if(dialect='postgresql')
|
||||
)
|
||||
|
||||
:param dialect: May be a string, tuple or a callable
|
||||
predicate. If a string, it will be compared to the name of the
|
||||
executing database dialect::
|
||||
|
||||
DDL('something').execute_if(dialect='postgresql')
|
||||
|
||||
If a tuple, specifies multiple dialect names::
|
||||
|
||||
DDL('something').execute_if(dialect=('postgresql', 'mysql'))
|
||||
|
||||
:param callable_: A callable, which will be invoked with
|
||||
four positional arguments as well as optional keyword
|
||||
arguments:
|
||||
|
||||
:ddl:
|
||||
This DDL element.
|
||||
|
||||
:target:
|
||||
The :class:`.Table` or :class:`.MetaData` object which is the
|
||||
target of this event. May be None if the DDL is executed
|
||||
explicitly.
|
||||
|
||||
:bind:
|
||||
The :class:`.Connection` being used for DDL execution
|
||||
|
||||
:tables:
|
||||
Optional keyword argument - a list of Table objects which are to
|
||||
be created/ dropped within a MetaData.create_all() or drop_all()
|
||||
method call.
|
||||
|
||||
:state:
|
||||
Optional keyword argument - will be the ``state`` argument
|
||||
passed to this function.
|
||||
|
||||
:checkfirst:
|
||||
Keyword argument, will be True if the 'checkfirst' flag was
|
||||
set during the call to ``create()``, ``create_all()``,
|
||||
``drop()``, ``drop_all()``.
|
||||
|
||||
If the callable returns a true value, the DDL statement will be
|
||||
executed.
|
||||
|
||||
:param state: any value which will be passed to the callable\_
|
||||
as the ``state`` keyword argument.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:class:`.DDLEvents`
|
||||
|
||||
:ref:`event_toplevel`
|
||||
|
||||
"""
|
||||
self.dialect = dialect
|
||||
self.callable_ = callable_
|
||||
self.state = state
|
||||
|
||||
def _should_execute(self, target, bind, **kw):
|
||||
if self.on is not None and \
|
||||
not self._should_execute_deprecated(None, target, bind, **kw):
|
||||
return False
|
||||
|
||||
if isinstance(self.dialect, util.string_types):
|
||||
if self.dialect != bind.engine.name:
|
||||
return False
|
||||
elif isinstance(self.dialect, (tuple, list, set)):
|
||||
if bind.engine.name not in self.dialect:
|
||||
return False
|
||||
if (self.callable_ is not None and
|
||||
not self.callable_(self, target, bind,
|
||||
state=self.state, **kw)):
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
def _should_execute_deprecated(self, event, target, bind, **kw):
|
||||
if self.on is None:
|
||||
return True
|
||||
elif isinstance(self.on, util.string_types):
|
||||
return self.on == bind.engine.name
|
||||
elif isinstance(self.on, (tuple, list, set)):
|
||||
return bind.engine.name in self.on
|
||||
else:
|
||||
return self.on(self, event, target, bind, **kw)
|
||||
|
||||
def __call__(self, target, bind, **kw):
|
||||
"""Execute the DDL as a ddl_listener."""
|
||||
|
||||
if self._should_execute(target, bind, **kw):
|
||||
return bind.execute(self.against(target))
|
||||
|
||||
def _check_ddl_on(self, on):
|
||||
if (on is not None and
|
||||
(not isinstance(on, util.string_types + (tuple, list, set)) and
|
||||
not util.callable(on))):
|
||||
raise exc.ArgumentError(
|
||||
"Expected the name of a database dialect, a tuple "
|
||||
"of names, or a callable for "
|
||||
"'on' criteria, got type '%s'." % type(on).__name__)
|
||||
|
||||
def bind(self):
|
||||
if self._bind:
|
||||
return self._bind
|
||||
|
||||
def _set_bind(self, bind):
|
||||
self._bind = bind
|
||||
bind = property(bind, _set_bind)
|
||||
|
||||
def _generate(self):
|
||||
s = self.__class__.__new__(self.__class__)
|
||||
s.__dict__ = self.__dict__.copy()
|
||||
return s
|
||||
|
||||
|
||||
class DDL(DDLElement):
|
||||
"""A literal DDL statement.
|
||||
|
||||
Specifies literal SQL DDL to be executed by the database. DDL objects
|
||||
function as DDL event listeners, and can be subscribed to those events
|
||||
listed in :class:`.DDLEvents`, using either :class:`.Table` or
|
||||
:class:`.MetaData` objects as targets. Basic templating support allows
|
||||
a single DDL instance to handle repetitive tasks for multiple tables.
|
||||
|
||||
Examples::
|
||||
|
||||
from sqlalchemy import event, DDL
|
||||
|
||||
tbl = Table('users', metadata, Column('uid', Integer))
|
||||
event.listen(tbl, 'before_create', DDL('DROP TRIGGER users_trigger'))
|
||||
|
||||
spow = DDL('ALTER TABLE %(table)s SET secretpowers TRUE')
|
||||
event.listen(tbl, 'after_create', spow.execute_if(dialect='somedb'))
|
||||
|
||||
drop_spow = DDL('ALTER TABLE users SET secretpowers FALSE')
|
||||
connection.execute(drop_spow)
|
||||
|
||||
When operating on Table events, the following ``statement``
|
||||
string substitions are available::
|
||||
|
||||
%(table)s - the Table name, with any required quoting applied
|
||||
%(schema)s - the schema name, with any required quoting applied
|
||||
%(fullname)s - the Table name including schema, quoted if needed
|
||||
|
||||
The DDL's "context", if any, will be combined with the standard
|
||||
substitutions noted above. Keys present in the context will override
|
||||
the standard substitutions.
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = "ddl"
|
||||
|
||||
def __init__(self, statement, on=None, context=None, bind=None):
|
||||
"""Create a DDL statement.
|
||||
|
||||
:param statement:
|
||||
A string or unicode string to be executed. Statements will be
|
||||
processed with Python's string formatting operator. See the
|
||||
``context`` argument and the ``execute_at`` method.
|
||||
|
||||
A literal '%' in a statement must be escaped as '%%'.
|
||||
|
||||
SQL bind parameters are not available in DDL statements.
|
||||
|
||||
:param on:
|
||||
.. deprecated:: 0.7
|
||||
See :meth:`.DDLElement.execute_if`.
|
||||
|
||||
Optional filtering criteria. May be a string, tuple or a callable
|
||||
predicate. If a string, it will be compared to the name of the
|
||||
executing database dialect::
|
||||
|
||||
DDL('something', on='postgresql')
|
||||
|
||||
If a tuple, specifies multiple dialect names::
|
||||
|
||||
DDL('something', on=('postgresql', 'mysql'))
|
||||
|
||||
If a callable, it will be invoked with four positional arguments
|
||||
as well as optional keyword arguments:
|
||||
|
||||
:ddl:
|
||||
This DDL element.
|
||||
|
||||
:event:
|
||||
The name of the event that has triggered this DDL, such as
|
||||
'after-create' Will be None if the DDL is executed explicitly.
|
||||
|
||||
:target:
|
||||
The ``Table`` or ``MetaData`` object which is the target of
|
||||
this event. May be None if the DDL is executed explicitly.
|
||||
|
||||
:connection:
|
||||
The ``Connection`` being used for DDL execution
|
||||
|
||||
:tables:
|
||||
Optional keyword argument - a list of Table objects which are to
|
||||
be created/ dropped within a MetaData.create_all() or drop_all()
|
||||
method call.
|
||||
|
||||
|
||||
If the callable returns a true value, the DDL statement will be
|
||||
executed.
|
||||
|
||||
:param context:
|
||||
Optional dictionary, defaults to None. These values will be
|
||||
available for use in string substitutions on the DDL statement.
|
||||
|
||||
:param bind:
|
||||
Optional. A :class:`.Connectable`, used by
|
||||
default when ``execute()`` is invoked without a bind argument.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
:class:`.DDLEvents`
|
||||
|
||||
:mod:`sqlalchemy.event`
|
||||
|
||||
"""
|
||||
|
||||
if not isinstance(statement, util.string_types):
|
||||
raise exc.ArgumentError(
|
||||
"Expected a string or unicode SQL statement, got '%r'" %
|
||||
statement)
|
||||
|
||||
self.statement = statement
|
||||
self.context = context or {}
|
||||
|
||||
self._check_ddl_on(on)
|
||||
self.on = on
|
||||
self._bind = bind
|
||||
|
||||
def __repr__(self):
|
||||
return '<%s@%s; %s>' % (
|
||||
type(self).__name__, id(self),
|
||||
', '.join([repr(self.statement)] +
|
||||
['%s=%r' % (key, getattr(self, key))
|
||||
for key in ('on', 'context')
|
||||
if getattr(self, key)]))
|
||||
|
||||
|
||||
class _CreateDropBase(DDLElement):
|
||||
"""Base class for DDL constructs that represent CREATE and DROP or
|
||||
equivalents.
|
||||
|
||||
The common theme of _CreateDropBase is a single
|
||||
``element`` attribute which refers to the element
|
||||
to be created or dropped.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, element, on=None, bind=None):
|
||||
self.element = element
|
||||
self._check_ddl_on(on)
|
||||
self.on = on
|
||||
self.bind = bind
|
||||
|
||||
def _create_rule_disable(self, compiler):
|
||||
"""Allow disable of _create_rule using a callable.
|
||||
|
||||
Pass to _create_rule using
|
||||
util.portable_instancemethod(self._create_rule_disable)
|
||||
to retain serializability.
|
||||
|
||||
"""
|
||||
return False
|
||||
|
||||
|
||||
class CreateSchema(_CreateDropBase):
|
||||
"""Represent a CREATE SCHEMA statement.
|
||||
|
||||
.. versionadded:: 0.7.4
|
||||
|
||||
The argument here is the string name of the schema.
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = "create_schema"
|
||||
|
||||
def __init__(self, name, quote=None, **kw):
|
||||
"""Create a new :class:`.CreateSchema` construct."""
|
||||
|
||||
self.quote = quote
|
||||
super(CreateSchema, self).__init__(name, **kw)
|
||||
|
||||
|
||||
class DropSchema(_CreateDropBase):
|
||||
"""Represent a DROP SCHEMA statement.
|
||||
|
||||
The argument here is the string name of the schema.
|
||||
|
||||
.. versionadded:: 0.7.4
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = "drop_schema"
|
||||
|
||||
def __init__(self, name, quote=None, cascade=False, **kw):
|
||||
"""Create a new :class:`.DropSchema` construct."""
|
||||
|
||||
self.quote = quote
|
||||
self.cascade = cascade
|
||||
super(DropSchema, self).__init__(name, **kw)
|
||||
|
||||
|
||||
class CreateTable(_CreateDropBase):
|
||||
"""Represent a CREATE TABLE statement."""
|
||||
|
||||
__visit_name__ = "create_table"
|
||||
|
||||
def __init__(self, element, on=None, bind=None):
|
||||
"""Create a :class:`.CreateTable` construct.
|
||||
|
||||
:param element: a :class:`.Table` that's the subject
|
||||
of the CREATE
|
||||
:param on: See the description for 'on' in :class:`.DDL`.
|
||||
:param bind: See the description for 'bind' in :class:`.DDL`.
|
||||
|
||||
"""
|
||||
super(CreateTable, self).__init__(element, on=on, bind=bind)
|
||||
self.columns = [CreateColumn(column)
|
||||
for column in element.columns
|
||||
]
|
||||
|
||||
|
||||
class _DropView(_CreateDropBase):
|
||||
"""Semi-public 'DROP VIEW' construct.
|
||||
|
||||
Used by the test suite for dialect-agnostic drops of views.
|
||||
This object will eventually be part of a public "view" API.
|
||||
|
||||
"""
|
||||
__visit_name__ = "drop_view"
|
||||
|
||||
|
||||
class CreateColumn(_DDLCompiles):
|
||||
"""Represent a :class:`.Column` as rendered in a CREATE TABLE statement,
|
||||
via the :class:`.CreateTable` construct.
|
||||
|
||||
This is provided to support custom column DDL within the generation
|
||||
of CREATE TABLE statements, by using the
|
||||
compiler extension documented in :ref:`sqlalchemy.ext.compiler_toplevel`
|
||||
to extend :class:`.CreateColumn`.
|
||||
|
||||
Typical integration is to examine the incoming :class:`.Column`
|
||||
object, and to redirect compilation if a particular flag or condition
|
||||
is found::
|
||||
|
||||
from sqlalchemy import schema
|
||||
from sqlalchemy.ext.compiler import compiles
|
||||
|
||||
@compiles(schema.CreateColumn)
|
||||
def compile(element, compiler, **kw):
|
||||
column = element.element
|
||||
|
||||
if "special" not in column.info:
|
||||
return compiler.visit_create_column(element, **kw)
|
||||
|
||||
text = "%s SPECIAL DIRECTIVE %s" % (
|
||||
column.name,
|
||||
compiler.type_compiler.process(column.type)
|
||||
)
|
||||
default = compiler.get_column_default_string(column)
|
||||
if default is not None:
|
||||
text += " DEFAULT " + default
|
||||
|
||||
if not column.nullable:
|
||||
text += " NOT NULL"
|
||||
|
||||
if column.constraints:
|
||||
text += " ".join(
|
||||
compiler.process(const)
|
||||
for const in column.constraints)
|
||||
return text
|
||||
|
||||
The above construct can be applied to a :class:`.Table` as follows::
|
||||
|
||||
from sqlalchemy import Table, Metadata, Column, Integer, String
|
||||
from sqlalchemy import schema
|
||||
|
||||
metadata = MetaData()
|
||||
|
||||
table = Table('mytable', MetaData(),
|
||||
Column('x', Integer, info={"special":True}, primary_key=True),
|
||||
Column('y', String(50)),
|
||||
Column('z', String(20), info={"special":True})
|
||||
)
|
||||
|
||||
metadata.create_all(conn)
|
||||
|
||||
Above, the directives we've added to the :attr:`.Column.info` collection
|
||||
will be detected by our custom compilation scheme::
|
||||
|
||||
CREATE TABLE mytable (
|
||||
x SPECIAL DIRECTIVE INTEGER NOT NULL,
|
||||
y VARCHAR(50),
|
||||
z SPECIAL DIRECTIVE VARCHAR(20),
|
||||
PRIMARY KEY (x)
|
||||
)
|
||||
|
||||
The :class:`.CreateColumn` construct can also be used to skip certain
|
||||
columns when producing a ``CREATE TABLE``. This is accomplished by
|
||||
creating a compilation rule that conditionally returns ``None``.
|
||||
This is essentially how to produce the same effect as using the
|
||||
``system=True`` argument on :class:`.Column`, which marks a column
|
||||
as an implicitly-present "system" column.
|
||||
|
||||
For example, suppose we wish to produce a :class:`.Table` which skips
|
||||
rendering of the Postgresql ``xmin`` column against the Postgresql
|
||||
backend, but on other backends does render it, in anticipation of a
|
||||
triggered rule. A conditional compilation rule could skip this name only
|
||||
on Postgresql::
|
||||
|
||||
from sqlalchemy.schema import CreateColumn
|
||||
|
||||
@compiles(CreateColumn, "postgresql")
|
||||
def skip_xmin(element, compiler, **kw):
|
||||
if element.element.name == 'xmin':
|
||||
return None
|
||||
else:
|
||||
return compiler.visit_create_column(element, **kw)
|
||||
|
||||
|
||||
my_table = Table('mytable', metadata,
|
||||
Column('id', Integer, primary_key=True),
|
||||
Column('xmin', Integer)
|
||||
)
|
||||
|
||||
Above, a :class:`.CreateTable` construct will generate a ``CREATE TABLE``
|
||||
which only includes the ``id`` column in the string; the ``xmin`` column
|
||||
will be omitted, but only against the Postgresql backend.
|
||||
|
||||
.. versionadded:: 0.8.3 The :class:`.CreateColumn` construct supports
|
||||
skipping of columns by returning ``None`` from a custom compilation
|
||||
rule.
|
||||
|
||||
.. versionadded:: 0.8 The :class:`.CreateColumn` construct was added
|
||||
to support custom column creation styles.
|
||||
|
||||
"""
|
||||
__visit_name__ = 'create_column'
|
||||
|
||||
def __init__(self, element):
|
||||
self.element = element
|
||||
|
||||
|
||||
class DropTable(_CreateDropBase):
|
||||
"""Represent a DROP TABLE statement."""
|
||||
|
||||
__visit_name__ = "drop_table"
|
||||
|
||||
|
||||
class CreateSequence(_CreateDropBase):
|
||||
"""Represent a CREATE SEQUENCE statement."""
|
||||
|
||||
__visit_name__ = "create_sequence"
|
||||
|
||||
|
||||
class DropSequence(_CreateDropBase):
|
||||
"""Represent a DROP SEQUENCE statement."""
|
||||
|
||||
__visit_name__ = "drop_sequence"
|
||||
|
||||
|
||||
class CreateIndex(_CreateDropBase):
|
||||
"""Represent a CREATE INDEX statement."""
|
||||
|
||||
__visit_name__ = "create_index"
|
||||
|
||||
|
||||
class DropIndex(_CreateDropBase):
|
||||
"""Represent a DROP INDEX statement."""
|
||||
|
||||
__visit_name__ = "drop_index"
|
||||
|
||||
|
||||
class AddConstraint(_CreateDropBase):
|
||||
"""Represent an ALTER TABLE ADD CONSTRAINT statement."""
|
||||
|
||||
__visit_name__ = "add_constraint"
|
||||
|
||||
def __init__(self, element, *args, **kw):
|
||||
super(AddConstraint, self).__init__(element, *args, **kw)
|
||||
element._create_rule = util.portable_instancemethod(
|
||||
self._create_rule_disable)
|
||||
|
||||
|
||||
class DropConstraint(_CreateDropBase):
|
||||
"""Represent an ALTER TABLE DROP CONSTRAINT statement."""
|
||||
|
||||
__visit_name__ = "drop_constraint"
|
||||
|
||||
def __init__(self, element, cascade=False, **kw):
|
||||
self.cascade = cascade
|
||||
super(DropConstraint, self).__init__(element, **kw)
|
||||
element._create_rule = util.portable_instancemethod(
|
||||
self._create_rule_disable)
|
||||
|
||||
|
||||
class DDLBase(SchemaVisitor):
|
||||
def __init__(self, connection):
|
||||
self.connection = connection
|
||||
|
||||
|
||||
class SchemaGenerator(DDLBase):
|
||||
|
||||
def __init__(self, dialect, connection, checkfirst=False,
|
||||
tables=None, **kwargs):
|
||||
super(SchemaGenerator, self).__init__(connection, **kwargs)
|
||||
self.checkfirst = checkfirst
|
||||
self.tables = tables
|
||||
self.preparer = dialect.identifier_preparer
|
||||
self.dialect = dialect
|
||||
self.memo = {}
|
||||
|
||||
def _can_create_table(self, table):
|
||||
self.dialect.validate_identifier(table.name)
|
||||
if table.schema:
|
||||
self.dialect.validate_identifier(table.schema)
|
||||
return not self.checkfirst or \
|
||||
not self.dialect.has_table(self.connection,
|
||||
table.name, schema=table.schema)
|
||||
|
||||
def _can_create_sequence(self, sequence):
|
||||
return self.dialect.supports_sequences and \
|
||||
(
|
||||
(not self.dialect.sequences_optional or
|
||||
not sequence.optional) and
|
||||
(
|
||||
not self.checkfirst or
|
||||
not self.dialect.has_sequence(
|
||||
self.connection,
|
||||
sequence.name,
|
||||
schema=sequence.schema)
|
||||
)
|
||||
)
|
||||
|
||||
def visit_metadata(self, metadata):
|
||||
if self.tables is not None:
|
||||
tables = self.tables
|
||||
else:
|
||||
tables = list(metadata.tables.values())
|
||||
collection = [t for t in sort_tables(tables)
|
||||
if self._can_create_table(t)]
|
||||
seq_coll = [s for s in metadata._sequences.values()
|
||||
if s.column is None and self._can_create_sequence(s)]
|
||||
|
||||
metadata.dispatch.before_create(metadata, self.connection,
|
||||
tables=collection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
for seq in seq_coll:
|
||||
self.traverse_single(seq, create_ok=True)
|
||||
|
||||
for table in collection:
|
||||
self.traverse_single(table, create_ok=True)
|
||||
|
||||
metadata.dispatch.after_create(metadata, self.connection,
|
||||
tables=collection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
def visit_table(self, table, create_ok=False):
|
||||
if not create_ok and not self._can_create_table(table):
|
||||
return
|
||||
|
||||
table.dispatch.before_create(table, self.connection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
for column in table.columns:
|
||||
if column.default is not None:
|
||||
self.traverse_single(column.default)
|
||||
|
||||
self.connection.execute(CreateTable(table))
|
||||
|
||||
if hasattr(table, 'indexes'):
|
||||
for index in table.indexes:
|
||||
self.traverse_single(index)
|
||||
|
||||
table.dispatch.after_create(table, self.connection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
def visit_sequence(self, sequence, create_ok=False):
|
||||
if not create_ok and not self._can_create_sequence(sequence):
|
||||
return
|
||||
self.connection.execute(CreateSequence(sequence))
|
||||
|
||||
def visit_index(self, index):
|
||||
self.connection.execute(CreateIndex(index))
|
||||
|
||||
|
||||
class SchemaDropper(DDLBase):
|
||||
|
||||
def __init__(self, dialect, connection, checkfirst=False,
|
||||
tables=None, **kwargs):
|
||||
super(SchemaDropper, self).__init__(connection, **kwargs)
|
||||
self.checkfirst = checkfirst
|
||||
self.tables = tables
|
||||
self.preparer = dialect.identifier_preparer
|
||||
self.dialect = dialect
|
||||
self.memo = {}
|
||||
|
||||
def visit_metadata(self, metadata):
|
||||
if self.tables is not None:
|
||||
tables = self.tables
|
||||
else:
|
||||
tables = list(metadata.tables.values())
|
||||
|
||||
collection = [
|
||||
t
|
||||
for t in reversed(sort_tables(tables))
|
||||
if self._can_drop_table(t)
|
||||
]
|
||||
|
||||
seq_coll = [
|
||||
s
|
||||
for s in metadata._sequences.values()
|
||||
if s.column is None and self._can_drop_sequence(s)
|
||||
]
|
||||
|
||||
metadata.dispatch.before_drop(
|
||||
metadata, self.connection, tables=collection,
|
||||
checkfirst=self.checkfirst, _ddl_runner=self)
|
||||
|
||||
for table in collection:
|
||||
self.traverse_single(table, drop_ok=True)
|
||||
|
||||
for seq in seq_coll:
|
||||
self.traverse_single(seq, drop_ok=True)
|
||||
|
||||
metadata.dispatch.after_drop(
|
||||
metadata, self.connection, tables=collection,
|
||||
checkfirst=self.checkfirst, _ddl_runner=self)
|
||||
|
||||
def _can_drop_table(self, table):
|
||||
self.dialect.validate_identifier(table.name)
|
||||
if table.schema:
|
||||
self.dialect.validate_identifier(table.schema)
|
||||
return not self.checkfirst or self.dialect.has_table(
|
||||
self.connection, table.name, schema=table.schema)
|
||||
|
||||
def _can_drop_sequence(self, sequence):
|
||||
return self.dialect.supports_sequences and \
|
||||
((not self.dialect.sequences_optional or
|
||||
not sequence.optional) and
|
||||
(not self.checkfirst or
|
||||
self.dialect.has_sequence(
|
||||
self.connection,
|
||||
sequence.name,
|
||||
schema=sequence.schema))
|
||||
)
|
||||
|
||||
def visit_index(self, index):
|
||||
self.connection.execute(DropIndex(index))
|
||||
|
||||
def visit_table(self, table, drop_ok=False):
|
||||
if not drop_ok and not self._can_drop_table(table):
|
||||
return
|
||||
|
||||
table.dispatch.before_drop(table, self.connection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
for column in table.columns:
|
||||
if column.default is not None:
|
||||
self.traverse_single(column.default)
|
||||
|
||||
self.connection.execute(DropTable(table))
|
||||
|
||||
table.dispatch.after_drop(table, self.connection,
|
||||
checkfirst=self.checkfirst,
|
||||
_ddl_runner=self)
|
||||
|
||||
def visit_sequence(self, sequence, drop_ok=False):
|
||||
if not drop_ok and not self._can_drop_sequence(sequence):
|
||||
return
|
||||
self.connection.execute(DropSequence(sequence))
|
||||
|
||||
|
||||
def sort_tables(tables, skip_fn=None, extra_dependencies=None):
|
||||
"""sort a collection of Table objects in order of
|
||||
their foreign-key dependency."""
|
||||
|
||||
tables = list(tables)
|
||||
tuples = []
|
||||
if extra_dependencies is not None:
|
||||
tuples.extend(extra_dependencies)
|
||||
|
||||
def visit_foreign_key(fkey):
|
||||
if fkey.use_alter:
|
||||
return
|
||||
elif skip_fn and skip_fn(fkey):
|
||||
return
|
||||
parent_table = fkey.column.table
|
||||
if parent_table in tables:
|
||||
child_table = fkey.parent.table
|
||||
if parent_table is not child_table:
|
||||
tuples.append((parent_table, child_table))
|
||||
|
||||
for table in tables:
|
||||
traverse(table,
|
||||
{'schema_visitor': True},
|
||||
{'foreign_key': visit_foreign_key})
|
||||
|
||||
tuples.extend(
|
||||
[parent, table] for parent in table._extra_dependencies
|
||||
)
|
||||
|
||||
return list(topological.sort(tuples, tables))
|
||||
311
lib/python3.5/site-packages/sqlalchemy/sql/default_comparator.py
Normal file
311
lib/python3.5/site-packages/sqlalchemy/sql/default_comparator.py
Normal file
|
|
@ -0,0 +1,311 @@
|
|||
# sql/default_comparator.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Default implementation of SQL comparison operations.
|
||||
"""
|
||||
|
||||
from .. import exc, util
|
||||
from . import operators
|
||||
from . import type_api
|
||||
from .elements import BindParameter, True_, False_, BinaryExpression, \
|
||||
Null, _const_expr, _clause_element_as_expr, \
|
||||
ClauseList, ColumnElement, TextClause, UnaryExpression, \
|
||||
collate, _is_literal, _literal_as_text, ClauseElement, and_, or_
|
||||
from .selectable import SelectBase, Alias, Selectable, ScalarSelect
|
||||
|
||||
|
||||
class _DefaultColumnComparator(operators.ColumnOperators):
|
||||
"""Defines comparison and math operations.
|
||||
|
||||
See :class:`.ColumnOperators` and :class:`.Operators` for descriptions
|
||||
of all operations.
|
||||
|
||||
"""
|
||||
|
||||
@util.memoized_property
|
||||
def type(self):
|
||||
return self.expr.type
|
||||
|
||||
def operate(self, op, *other, **kwargs):
|
||||
o = self.operators[op.__name__]
|
||||
return o[0](self, self.expr, op, *(other + o[1:]), **kwargs)
|
||||
|
||||
def reverse_operate(self, op, other, **kwargs):
|
||||
o = self.operators[op.__name__]
|
||||
return o[0](self, self.expr, op, other,
|
||||
reverse=True, *o[1:], **kwargs)
|
||||
|
||||
def _adapt_expression(self, op, other_comparator):
|
||||
"""evaluate the return type of <self> <op> <othertype>,
|
||||
and apply any adaptations to the given operator.
|
||||
|
||||
This method determines the type of a resulting binary expression
|
||||
given two source types and an operator. For example, two
|
||||
:class:`.Column` objects, both of the type :class:`.Integer`, will
|
||||
produce a :class:`.BinaryExpression` that also has the type
|
||||
:class:`.Integer` when compared via the addition (``+``) operator.
|
||||
However, using the addition operator with an :class:`.Integer`
|
||||
and a :class:`.Date` object will produce a :class:`.Date`, assuming
|
||||
"days delta" behavior by the database (in reality, most databases
|
||||
other than Postgresql don't accept this particular operation).
|
||||
|
||||
The method returns a tuple of the form <operator>, <type>.
|
||||
The resulting operator and type will be those applied to the
|
||||
resulting :class:`.BinaryExpression` as the final operator and the
|
||||
right-hand side of the expression.
|
||||
|
||||
Note that only a subset of operators make usage of
|
||||
:meth:`._adapt_expression`,
|
||||
including math operators and user-defined operators, but not
|
||||
boolean comparison or special SQL keywords like MATCH or BETWEEN.
|
||||
|
||||
"""
|
||||
return op, other_comparator.type
|
||||
|
||||
def _boolean_compare(self, expr, op, obj, negate=None, reverse=False,
|
||||
_python_is_types=(util.NoneType, bool),
|
||||
**kwargs):
|
||||
|
||||
if isinstance(obj, _python_is_types + (Null, True_, False_)):
|
||||
|
||||
# allow x ==/!= True/False to be treated as a literal.
|
||||
# this comes out to "== / != true/false" or "1/0" if those
|
||||
# constants aren't supported and works on all platforms
|
||||
if op in (operators.eq, operators.ne) and \
|
||||
isinstance(obj, (bool, True_, False_)):
|
||||
return BinaryExpression(expr,
|
||||
_literal_as_text(obj),
|
||||
op,
|
||||
type_=type_api.BOOLEANTYPE,
|
||||
negate=negate, modifiers=kwargs)
|
||||
else:
|
||||
# all other None/True/False uses IS, IS NOT
|
||||
if op in (operators.eq, operators.is_):
|
||||
return BinaryExpression(expr, _const_expr(obj),
|
||||
operators.is_,
|
||||
negate=operators.isnot)
|
||||
elif op in (operators.ne, operators.isnot):
|
||||
return BinaryExpression(expr, _const_expr(obj),
|
||||
operators.isnot,
|
||||
negate=operators.is_)
|
||||
else:
|
||||
raise exc.ArgumentError(
|
||||
"Only '=', '!=', 'is_()', 'isnot()' operators can "
|
||||
"be used with None/True/False")
|
||||
else:
|
||||
obj = self._check_literal(expr, op, obj)
|
||||
|
||||
if reverse:
|
||||
return BinaryExpression(obj,
|
||||
expr,
|
||||
op,
|
||||
type_=type_api.BOOLEANTYPE,
|
||||
negate=negate, modifiers=kwargs)
|
||||
else:
|
||||
return BinaryExpression(expr,
|
||||
obj,
|
||||
op,
|
||||
type_=type_api.BOOLEANTYPE,
|
||||
negate=negate, modifiers=kwargs)
|
||||
|
||||
def _binary_operate(self, expr, op, obj, reverse=False, result_type=None,
|
||||
**kw):
|
||||
obj = self._check_literal(expr, op, obj)
|
||||
|
||||
if reverse:
|
||||
left, right = obj, expr
|
||||
else:
|
||||
left, right = expr, obj
|
||||
|
||||
if result_type is None:
|
||||
op, result_type = left.comparator._adapt_expression(
|
||||
op, right.comparator)
|
||||
|
||||
return BinaryExpression(left, right, op, type_=result_type)
|
||||
|
||||
def _conjunction_operate(self, expr, op, other, **kw):
|
||||
if op is operators.and_:
|
||||
return and_(expr, other)
|
||||
elif op is operators.or_:
|
||||
return or_(expr, other)
|
||||
else:
|
||||
raise NotImplementedError()
|
||||
|
||||
def _scalar(self, expr, op, fn, **kw):
|
||||
return fn(expr)
|
||||
|
||||
def _in_impl(self, expr, op, seq_or_selectable, negate_op, **kw):
|
||||
seq_or_selectable = _clause_element_as_expr(seq_or_selectable)
|
||||
|
||||
if isinstance(seq_or_selectable, ScalarSelect):
|
||||
return self._boolean_compare(expr, op, seq_or_selectable,
|
||||
negate=negate_op)
|
||||
elif isinstance(seq_or_selectable, SelectBase):
|
||||
|
||||
# TODO: if we ever want to support (x, y, z) IN (select x,
|
||||
# y, z from table), we would need a multi-column version of
|
||||
# as_scalar() to produce a multi- column selectable that
|
||||
# does not export itself as a FROM clause
|
||||
|
||||
return self._boolean_compare(
|
||||
expr, op, seq_or_selectable.as_scalar(),
|
||||
negate=negate_op, **kw)
|
||||
elif isinstance(seq_or_selectable, (Selectable, TextClause)):
|
||||
return self._boolean_compare(expr, op, seq_or_selectable,
|
||||
negate=negate_op, **kw)
|
||||
elif isinstance(seq_or_selectable, ClauseElement):
|
||||
raise exc.InvalidRequestError(
|
||||
'in_() accepts'
|
||||
' either a list of expressions '
|
||||
'or a selectable: %r' % seq_or_selectable)
|
||||
|
||||
# Handle non selectable arguments as sequences
|
||||
args = []
|
||||
for o in seq_or_selectable:
|
||||
if not _is_literal(o):
|
||||
if not isinstance(o, operators.ColumnOperators):
|
||||
raise exc.InvalidRequestError(
|
||||
'in_() accepts'
|
||||
' either a list of expressions '
|
||||
'or a selectable: %r' % o)
|
||||
elif o is None:
|
||||
o = Null()
|
||||
else:
|
||||
o = expr._bind_param(op, o)
|
||||
args.append(o)
|
||||
if len(args) == 0:
|
||||
|
||||
# Special case handling for empty IN's, behave like
|
||||
# comparison against zero row selectable. We use != to
|
||||
# build the contradiction as it handles NULL values
|
||||
# appropriately, i.e. "not (x IN ())" should not return NULL
|
||||
# values for x.
|
||||
|
||||
util.warn('The IN-predicate on "%s" was invoked with an '
|
||||
'empty sequence. This results in a '
|
||||
'contradiction, which nonetheless can be '
|
||||
'expensive to evaluate. Consider alternative '
|
||||
'strategies for improved performance.' % expr)
|
||||
if op is operators.in_op:
|
||||
return expr != expr
|
||||
else:
|
||||
return expr == expr
|
||||
|
||||
return self._boolean_compare(expr, op,
|
||||
ClauseList(*args).self_group(against=op),
|
||||
negate=negate_op)
|
||||
|
||||
def _unsupported_impl(self, expr, op, *arg, **kw):
|
||||
raise NotImplementedError("Operator '%s' is not supported on "
|
||||
"this expression" % op.__name__)
|
||||
|
||||
def _inv_impl(self, expr, op, **kw):
|
||||
"""See :meth:`.ColumnOperators.__inv__`."""
|
||||
if hasattr(expr, 'negation_clause'):
|
||||
return expr.negation_clause
|
||||
else:
|
||||
return expr._negate()
|
||||
|
||||
def _neg_impl(self, expr, op, **kw):
|
||||
"""See :meth:`.ColumnOperators.__neg__`."""
|
||||
return UnaryExpression(expr, operator=operators.neg)
|
||||
|
||||
def _match_impl(self, expr, op, other, **kw):
|
||||
"""See :meth:`.ColumnOperators.match`."""
|
||||
return self._boolean_compare(
|
||||
expr, operators.match_op,
|
||||
self._check_literal(
|
||||
expr, operators.match_op, other),
|
||||
**kw)
|
||||
|
||||
def _distinct_impl(self, expr, op, **kw):
|
||||
"""See :meth:`.ColumnOperators.distinct`."""
|
||||
return UnaryExpression(expr, operator=operators.distinct_op,
|
||||
type_=expr.type)
|
||||
|
||||
def _between_impl(self, expr, op, cleft, cright, **kw):
|
||||
"""See :meth:`.ColumnOperators.between`."""
|
||||
return BinaryExpression(
|
||||
expr,
|
||||
ClauseList(
|
||||
self._check_literal(expr, operators.and_, cleft),
|
||||
self._check_literal(expr, operators.and_, cright),
|
||||
operator=operators.and_,
|
||||
group=False, group_contents=False),
|
||||
op,
|
||||
negate=operators.notbetween_op
|
||||
if op is operators.between_op
|
||||
else operators.between_op,
|
||||
modifiers=kw)
|
||||
|
||||
def _collate_impl(self, expr, op, other, **kw):
|
||||
return collate(expr, other)
|
||||
|
||||
# a mapping of operators with the method they use, along with
|
||||
# their negated operator for comparison operators
|
||||
operators = {
|
||||
"and_": (_conjunction_operate,),
|
||||
"or_": (_conjunction_operate,),
|
||||
"inv": (_inv_impl,),
|
||||
"add": (_binary_operate,),
|
||||
"mul": (_binary_operate,),
|
||||
"sub": (_binary_operate,),
|
||||
"div": (_binary_operate,),
|
||||
"mod": (_binary_operate,),
|
||||
"truediv": (_binary_operate,),
|
||||
"custom_op": (_binary_operate,),
|
||||
"concat_op": (_binary_operate,),
|
||||
"lt": (_boolean_compare, operators.ge),
|
||||
"le": (_boolean_compare, operators.gt),
|
||||
"ne": (_boolean_compare, operators.eq),
|
||||
"gt": (_boolean_compare, operators.le),
|
||||
"ge": (_boolean_compare, operators.lt),
|
||||
"eq": (_boolean_compare, operators.ne),
|
||||
"like_op": (_boolean_compare, operators.notlike_op),
|
||||
"ilike_op": (_boolean_compare, operators.notilike_op),
|
||||
"notlike_op": (_boolean_compare, operators.like_op),
|
||||
"notilike_op": (_boolean_compare, operators.ilike_op),
|
||||
"contains_op": (_boolean_compare, operators.notcontains_op),
|
||||
"startswith_op": (_boolean_compare, operators.notstartswith_op),
|
||||
"endswith_op": (_boolean_compare, operators.notendswith_op),
|
||||
"desc_op": (_scalar, UnaryExpression._create_desc),
|
||||
"asc_op": (_scalar, UnaryExpression._create_asc),
|
||||
"nullsfirst_op": (_scalar, UnaryExpression._create_nullsfirst),
|
||||
"nullslast_op": (_scalar, UnaryExpression._create_nullslast),
|
||||
"in_op": (_in_impl, operators.notin_op),
|
||||
"notin_op": (_in_impl, operators.in_op),
|
||||
"is_": (_boolean_compare, operators.is_),
|
||||
"isnot": (_boolean_compare, operators.isnot),
|
||||
"collate": (_collate_impl,),
|
||||
"match_op": (_match_impl,),
|
||||
"distinct_op": (_distinct_impl,),
|
||||
"between_op": (_between_impl, ),
|
||||
"notbetween_op": (_between_impl, ),
|
||||
"neg": (_neg_impl,),
|
||||
"getitem": (_unsupported_impl,),
|
||||
"lshift": (_unsupported_impl,),
|
||||
"rshift": (_unsupported_impl,),
|
||||
}
|
||||
|
||||
def _check_literal(self, expr, operator, other):
|
||||
if isinstance(other, (ColumnElement, TextClause)):
|
||||
if isinstance(other, BindParameter) and \
|
||||
other.type._isnull:
|
||||
other = other._clone()
|
||||
other.type = expr.type
|
||||
return other
|
||||
elif hasattr(other, '__clause_element__'):
|
||||
other = other.__clause_element__()
|
||||
elif isinstance(other, type_api.TypeEngine.Comparator):
|
||||
other = other.expr
|
||||
|
||||
if isinstance(other, (SelectBase, Alias)):
|
||||
return other.as_scalar()
|
||||
elif not isinstance(other, (ColumnElement, TextClause)):
|
||||
return expr._bind_param(operator, other)
|
||||
else:
|
||||
return other
|
||||
774
lib/python3.5/site-packages/sqlalchemy/sql/dml.py
Normal file
774
lib/python3.5/site-packages/sqlalchemy/sql/dml.py
Normal file
|
|
@ -0,0 +1,774 @@
|
|||
# sql/dml.py
|
||||
# Copyright (C) 2009-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
"""
|
||||
Provide :class:`.Insert`, :class:`.Update` and :class:`.Delete`.
|
||||
|
||||
"""
|
||||
|
||||
from .base import Executable, _generative, _from_objects, DialectKWArgs
|
||||
from .elements import ClauseElement, _literal_as_text, Null, and_, _clone
|
||||
from .selectable import _interpret_as_from, _interpret_as_select, HasPrefixes
|
||||
from .. import util
|
||||
from .. import exc
|
||||
|
||||
|
||||
class UpdateBase(DialectKWArgs, HasPrefixes, Executable, ClauseElement):
|
||||
"""Form the base for ``INSERT``, ``UPDATE``, and ``DELETE`` statements.
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = 'update_base'
|
||||
|
||||
_execution_options = \
|
||||
Executable._execution_options.union({'autocommit': True})
|
||||
_hints = util.immutabledict()
|
||||
_prefixes = ()
|
||||
|
||||
def _process_colparams(self, parameters):
|
||||
def process_single(p):
|
||||
if isinstance(p, (list, tuple)):
|
||||
return dict(
|
||||
(c.key, pval)
|
||||
for c, pval in zip(self.table.c, p)
|
||||
)
|
||||
else:
|
||||
return p
|
||||
|
||||
if (isinstance(parameters, (list, tuple)) and parameters and
|
||||
isinstance(parameters[0], (list, tuple, dict))):
|
||||
|
||||
if not self._supports_multi_parameters:
|
||||
raise exc.InvalidRequestError(
|
||||
"This construct does not support "
|
||||
"multiple parameter sets.")
|
||||
|
||||
return [process_single(p) for p in parameters], True
|
||||
else:
|
||||
return process_single(parameters), False
|
||||
|
||||
def params(self, *arg, **kw):
|
||||
"""Set the parameters for the statement.
|
||||
|
||||
This method raises ``NotImplementedError`` on the base class,
|
||||
and is overridden by :class:`.ValuesBase` to provide the
|
||||
SET/VALUES clause of UPDATE and INSERT.
|
||||
|
||||
"""
|
||||
raise NotImplementedError(
|
||||
"params() is not supported for INSERT/UPDATE/DELETE statements."
|
||||
" To set the values for an INSERT or UPDATE statement, use"
|
||||
" stmt.values(**parameters).")
|
||||
|
||||
def bind(self):
|
||||
"""Return a 'bind' linked to this :class:`.UpdateBase`
|
||||
or a :class:`.Table` associated with it.
|
||||
|
||||
"""
|
||||
return self._bind or self.table.bind
|
||||
|
||||
def _set_bind(self, bind):
|
||||
self._bind = bind
|
||||
bind = property(bind, _set_bind)
|
||||
|
||||
@_generative
|
||||
def returning(self, *cols):
|
||||
"""Add a :term:`RETURNING` or equivalent clause to this statement.
|
||||
|
||||
e.g.::
|
||||
|
||||
stmt = table.update().\\
|
||||
where(table.c.data == 'value').\\
|
||||
values(status='X').\\
|
||||
returning(table.c.server_flag,
|
||||
table.c.updated_timestamp)
|
||||
|
||||
for server_flag, updated_timestamp in connection.execute(stmt):
|
||||
print(server_flag, updated_timestamp)
|
||||
|
||||
The given collection of column expressions should be derived from
|
||||
the table that is
|
||||
the target of the INSERT, UPDATE, or DELETE. While :class:`.Column`
|
||||
objects are typical, the elements can also be expressions::
|
||||
|
||||
stmt = table.insert().returning(
|
||||
(table.c.first_name + " " + table.c.last_name).
|
||||
label('fullname'))
|
||||
|
||||
Upon compilation, a RETURNING clause, or database equivalent,
|
||||
will be rendered within the statement. For INSERT and UPDATE,
|
||||
the values are the newly inserted/updated values. For DELETE,
|
||||
the values are those of the rows which were deleted.
|
||||
|
||||
Upon execution, the values of the columns to be returned are made
|
||||
available via the result set and can be iterated using
|
||||
:meth:`.ResultProxy.fetchone` and similar. For DBAPIs which do not
|
||||
natively support returning values (i.e. cx_oracle), SQLAlchemy will
|
||||
approximate this behavior at the result level so that a reasonable
|
||||
amount of behavioral neutrality is provided.
|
||||
|
||||
Note that not all databases/DBAPIs
|
||||
support RETURNING. For those backends with no support,
|
||||
an exception is raised upon compilation and/or execution.
|
||||
For those who do support it, the functionality across backends
|
||||
varies greatly, including restrictions on executemany()
|
||||
and other statements which return multiple rows. Please
|
||||
read the documentation notes for the database in use in
|
||||
order to determine the availability of RETURNING.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ValuesBase.return_defaults` - an alternative method tailored
|
||||
towards efficient fetching of server-side defaults and triggers
|
||||
for single-row INSERTs or UPDATEs.
|
||||
|
||||
|
||||
"""
|
||||
self._returning = cols
|
||||
|
||||
@_generative
|
||||
def with_hint(self, text, selectable=None, dialect_name="*"):
|
||||
"""Add a table hint for a single table to this
|
||||
INSERT/UPDATE/DELETE statement.
|
||||
|
||||
.. note::
|
||||
|
||||
:meth:`.UpdateBase.with_hint` currently applies only to
|
||||
Microsoft SQL Server. For MySQL INSERT/UPDATE/DELETE hints, use
|
||||
:meth:`.UpdateBase.prefix_with`.
|
||||
|
||||
The text of the hint is rendered in the appropriate
|
||||
location for the database backend in use, relative
|
||||
to the :class:`.Table` that is the subject of this
|
||||
statement, or optionally to that of the given
|
||||
:class:`.Table` passed as the ``selectable`` argument.
|
||||
|
||||
The ``dialect_name`` option will limit the rendering of a particular
|
||||
hint to a particular backend. Such as, to add a hint
|
||||
that only takes effect for SQL Server::
|
||||
|
||||
mytable.insert().with_hint("WITH (PAGLOCK)", dialect_name="mssql")
|
||||
|
||||
.. versionadded:: 0.7.6
|
||||
|
||||
:param text: Text of the hint.
|
||||
:param selectable: optional :class:`.Table` that specifies
|
||||
an element of the FROM clause within an UPDATE or DELETE
|
||||
to be the subject of the hint - applies only to certain backends.
|
||||
:param dialect_name: defaults to ``*``, if specified as the name
|
||||
of a particular dialect, will apply these hints only when
|
||||
that dialect is in use.
|
||||
"""
|
||||
if selectable is None:
|
||||
selectable = self.table
|
||||
|
||||
self._hints = self._hints.union(
|
||||
{(selectable, dialect_name): text})
|
||||
|
||||
|
||||
class ValuesBase(UpdateBase):
|
||||
"""Supplies support for :meth:`.ValuesBase.values` to
|
||||
INSERT and UPDATE constructs."""
|
||||
|
||||
__visit_name__ = 'values_base'
|
||||
|
||||
_supports_multi_parameters = False
|
||||
_has_multi_parameters = False
|
||||
select = None
|
||||
|
||||
def __init__(self, table, values, prefixes):
|
||||
self.table = _interpret_as_from(table)
|
||||
self.parameters, self._has_multi_parameters = \
|
||||
self._process_colparams(values)
|
||||
if prefixes:
|
||||
self._setup_prefixes(prefixes)
|
||||
|
||||
@_generative
|
||||
def values(self, *args, **kwargs):
|
||||
"""specify a fixed VALUES clause for an INSERT statement, or the SET
|
||||
clause for an UPDATE.
|
||||
|
||||
Note that the :class:`.Insert` and :class:`.Update` constructs support
|
||||
per-execution time formatting of the VALUES and/or SET clauses,
|
||||
based on the arguments passed to :meth:`.Connection.execute`.
|
||||
However, the :meth:`.ValuesBase.values` method can be used to "fix" a
|
||||
particular set of parameters into the statement.
|
||||
|
||||
Multiple calls to :meth:`.ValuesBase.values` will produce a new
|
||||
construct, each one with the parameter list modified to include
|
||||
the new parameters sent. In the typical case of a single
|
||||
dictionary of parameters, the newly passed keys will replace
|
||||
the same keys in the previous construct. In the case of a list-based
|
||||
"multiple values" construct, each new list of values is extended
|
||||
onto the existing list of values.
|
||||
|
||||
:param \**kwargs: key value pairs representing the string key
|
||||
of a :class:`.Column` mapped to the value to be rendered into the
|
||||
VALUES or SET clause::
|
||||
|
||||
users.insert().values(name="some name")
|
||||
|
||||
users.update().where(users.c.id==5).values(name="some name")
|
||||
|
||||
:param \*args: Alternatively, a dictionary, tuple or list
|
||||
of dictionaries or tuples can be passed as a single positional
|
||||
argument in order to form the VALUES or
|
||||
SET clause of the statement. The single dictionary form
|
||||
works the same as the kwargs form::
|
||||
|
||||
users.insert().values({"name": "some name"})
|
||||
|
||||
If a tuple is passed, the tuple should contain the same number
|
||||
of columns as the target :class:`.Table`::
|
||||
|
||||
users.insert().values((5, "some name"))
|
||||
|
||||
The :class:`.Insert` construct also supports multiply-rendered VALUES
|
||||
construct, for those backends which support this SQL syntax
|
||||
(SQLite, Postgresql, MySQL). This mode is indicated by passing a
|
||||
list of one or more dictionaries/tuples::
|
||||
|
||||
users.insert().values([
|
||||
{"name": "some name"},
|
||||
{"name": "some other name"},
|
||||
{"name": "yet another name"},
|
||||
])
|
||||
|
||||
In the case of an :class:`.Update`
|
||||
construct, only the single dictionary/tuple form is accepted,
|
||||
else an exception is raised. It is also an exception case to
|
||||
attempt to mix the single-/multiple- value styles together,
|
||||
either through multiple :meth:`.ValuesBase.values` calls
|
||||
or by sending a list + kwargs at the same time.
|
||||
|
||||
.. note::
|
||||
|
||||
Passing a multiple values list is *not* the same
|
||||
as passing a multiple values list to the
|
||||
:meth:`.Connection.execute` method. Passing a list of parameter
|
||||
sets to :meth:`.ValuesBase.values` produces a construct of this
|
||||
form::
|
||||
|
||||
INSERT INTO table (col1, col2, col3) VALUES
|
||||
(col1_0, col2_0, col3_0),
|
||||
(col1_1, col2_1, col3_1),
|
||||
...
|
||||
|
||||
whereas a multiple list passed to :meth:`.Connection.execute`
|
||||
has the effect of using the DBAPI
|
||||
`executemany() <http://www.python.org/dev/peps/pep-0249/#id18>`_
|
||||
method, which provides a high-performance system of invoking
|
||||
a single-row INSERT statement many times against a series
|
||||
of parameter sets. The "executemany" style is supported by
|
||||
all database backends, as it does not depend on a special SQL
|
||||
syntax.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
Support for multiple-VALUES INSERT statements.
|
||||
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`inserts_and_updates` - SQL Expression
|
||||
Language Tutorial
|
||||
|
||||
:func:`~.expression.insert` - produce an ``INSERT`` statement
|
||||
|
||||
:func:`~.expression.update` - produce an ``UPDATE`` statement
|
||||
|
||||
"""
|
||||
if self.select is not None:
|
||||
raise exc.InvalidRequestError(
|
||||
"This construct already inserts from a SELECT")
|
||||
if self._has_multi_parameters and kwargs:
|
||||
raise exc.InvalidRequestError(
|
||||
"This construct already has multiple parameter sets.")
|
||||
|
||||
if args:
|
||||
if len(args) > 1:
|
||||
raise exc.ArgumentError(
|
||||
"Only a single dictionary/tuple or list of "
|
||||
"dictionaries/tuples is accepted positionally.")
|
||||
v = args[0]
|
||||
else:
|
||||
v = {}
|
||||
|
||||
if self.parameters is None:
|
||||
self.parameters, self._has_multi_parameters = \
|
||||
self._process_colparams(v)
|
||||
else:
|
||||
if self._has_multi_parameters:
|
||||
self.parameters = list(self.parameters)
|
||||
p, self._has_multi_parameters = self._process_colparams(v)
|
||||
if not self._has_multi_parameters:
|
||||
raise exc.ArgumentError(
|
||||
"Can't mix single-values and multiple values "
|
||||
"formats in one statement")
|
||||
|
||||
self.parameters.extend(p)
|
||||
else:
|
||||
self.parameters = self.parameters.copy()
|
||||
p, self._has_multi_parameters = self._process_colparams(v)
|
||||
if self._has_multi_parameters:
|
||||
raise exc.ArgumentError(
|
||||
"Can't mix single-values and multiple values "
|
||||
"formats in one statement")
|
||||
self.parameters.update(p)
|
||||
|
||||
if kwargs:
|
||||
if self._has_multi_parameters:
|
||||
raise exc.ArgumentError(
|
||||
"Can't pass kwargs and multiple parameter sets "
|
||||
"simultaenously")
|
||||
else:
|
||||
self.parameters.update(kwargs)
|
||||
|
||||
@_generative
|
||||
def return_defaults(self, *cols):
|
||||
"""Make use of a :term:`RETURNING` clause for the purpose
|
||||
of fetching server-side expressions and defaults.
|
||||
|
||||
E.g.::
|
||||
|
||||
stmt = table.insert().values(data='newdata').return_defaults()
|
||||
|
||||
result = connection.execute(stmt)
|
||||
|
||||
server_created_at = result.returned_defaults['created_at']
|
||||
|
||||
When used against a backend that supports RETURNING, all column
|
||||
values generated by SQL expression or server-side-default will be
|
||||
added to any existing RETURNING clause, provided that
|
||||
:meth:`.UpdateBase.returning` is not used simultaneously. The column
|
||||
values will then be available on the result using the
|
||||
:attr:`.ResultProxy.returned_defaults` accessor as a dictionary,
|
||||
referring to values keyed to the :class:`.Column` object as well as
|
||||
its ``.key``.
|
||||
|
||||
This method differs from :meth:`.UpdateBase.returning` in these ways:
|
||||
|
||||
1. :meth:`.ValuesBase.return_defaults` is only intended for use with
|
||||
an INSERT or an UPDATE statement that matches exactly one row.
|
||||
While the RETURNING construct in the general sense supports
|
||||
multiple rows for a multi-row UPDATE or DELETE statement, or for
|
||||
special cases of INSERT that return multiple rows (e.g. INSERT from
|
||||
SELECT, multi-valued VALUES clause),
|
||||
:meth:`.ValuesBase.return_defaults` is intended only for an
|
||||
"ORM-style" single-row INSERT/UPDATE statement. The row returned
|
||||
by the statement is also consumed implcitly when
|
||||
:meth:`.ValuesBase.return_defaults` is used. By contrast,
|
||||
:meth:`.UpdateBase.returning` leaves the RETURNING result-set
|
||||
intact with a collection of any number of rows.
|
||||
|
||||
2. It is compatible with the existing logic to fetch auto-generated
|
||||
primary key values, also known as "implicit returning". Backends
|
||||
that support RETURNING will automatically make use of RETURNING in
|
||||
order to fetch the value of newly generated primary keys; while the
|
||||
:meth:`.UpdateBase.returning` method circumvents this behavior,
|
||||
:meth:`.ValuesBase.return_defaults` leaves it intact.
|
||||
|
||||
3. It can be called against any backend. Backends that don't support
|
||||
RETURNING will skip the usage of the feature, rather than raising
|
||||
an exception. The return value of
|
||||
:attr:`.ResultProxy.returned_defaults` will be ``None``
|
||||
|
||||
:meth:`.ValuesBase.return_defaults` is used by the ORM to provide
|
||||
an efficient implementation for the ``eager_defaults`` feature of
|
||||
:func:`.mapper`.
|
||||
|
||||
:param cols: optional list of column key names or :class:`.Column`
|
||||
objects. If omitted, all column expressions evaulated on the server
|
||||
are added to the returning list.
|
||||
|
||||
.. versionadded:: 0.9.0
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.UpdateBase.returning`
|
||||
|
||||
:attr:`.ResultProxy.returned_defaults`
|
||||
|
||||
"""
|
||||
self._return_defaults = cols or True
|
||||
|
||||
|
||||
class Insert(ValuesBase):
|
||||
"""Represent an INSERT construct.
|
||||
|
||||
The :class:`.Insert` object is created using the
|
||||
:func:`~.expression.insert()` function.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`coretutorial_insert_expressions`
|
||||
|
||||
"""
|
||||
__visit_name__ = 'insert'
|
||||
|
||||
_supports_multi_parameters = True
|
||||
|
||||
def __init__(self,
|
||||
table,
|
||||
values=None,
|
||||
inline=False,
|
||||
bind=None,
|
||||
prefixes=None,
|
||||
returning=None,
|
||||
return_defaults=False,
|
||||
**dialect_kw):
|
||||
"""Construct an :class:`.Insert` object.
|
||||
|
||||
Similar functionality is available via the
|
||||
:meth:`~.TableClause.insert` method on
|
||||
:class:`~.schema.Table`.
|
||||
|
||||
:param table: :class:`.TableClause` which is the subject of the
|
||||
insert.
|
||||
|
||||
:param values: collection of values to be inserted; see
|
||||
:meth:`.Insert.values` for a description of allowed formats here.
|
||||
Can be omitted entirely; a :class:`.Insert` construct will also
|
||||
dynamically render the VALUES clause at execution time based on
|
||||
the parameters passed to :meth:`.Connection.execute`.
|
||||
|
||||
:param inline: if True, SQL defaults will be compiled 'inline' into
|
||||
the statement and not pre-executed.
|
||||
|
||||
If both `values` and compile-time bind parameters are present, the
|
||||
compile-time bind parameters override the information specified
|
||||
within `values` on a per-key basis.
|
||||
|
||||
The keys within `values` can be either
|
||||
:class:`~sqlalchemy.schema.Column` objects or their string
|
||||
identifiers. Each key may reference one of:
|
||||
|
||||
* a literal data value (i.e. string, number, etc.);
|
||||
* a Column object;
|
||||
* a SELECT statement.
|
||||
|
||||
If a ``SELECT`` statement is specified which references this
|
||||
``INSERT`` statement's table, the statement will be correlated
|
||||
against the ``INSERT`` statement.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`coretutorial_insert_expressions` - SQL Expression Tutorial
|
||||
|
||||
:ref:`inserts_and_updates` - SQL Expression Tutorial
|
||||
|
||||
"""
|
||||
ValuesBase.__init__(self, table, values, prefixes)
|
||||
self._bind = bind
|
||||
self.select = self.select_names = None
|
||||
self.inline = inline
|
||||
self._returning = returning
|
||||
self._validate_dialect_kwargs(dialect_kw)
|
||||
self._return_defaults = return_defaults
|
||||
|
||||
def get_children(self, **kwargs):
|
||||
if self.select is not None:
|
||||
return self.select,
|
||||
else:
|
||||
return ()
|
||||
|
||||
@_generative
|
||||
def from_select(self, names, select):
|
||||
"""Return a new :class:`.Insert` construct which represents
|
||||
an ``INSERT...FROM SELECT`` statement.
|
||||
|
||||
e.g.::
|
||||
|
||||
sel = select([table1.c.a, table1.c.b]).where(table1.c.c > 5)
|
||||
ins = table2.insert().from_select(['a', 'b'], sel)
|
||||
|
||||
:param names: a sequence of string column names or :class:`.Column`
|
||||
objects representing the target columns.
|
||||
:param select: a :func:`.select` construct, :class:`.FromClause`
|
||||
or other construct which resolves into a :class:`.FromClause`,
|
||||
such as an ORM :class:`.Query` object, etc. The order of
|
||||
columns returned from this FROM clause should correspond to the
|
||||
order of columns sent as the ``names`` parameter; while this
|
||||
is not checked before passing along to the database, the database
|
||||
would normally raise an exception if these column lists don't
|
||||
correspond.
|
||||
|
||||
.. note::
|
||||
|
||||
Depending on backend, it may be necessary for the :class:`.Insert`
|
||||
statement to be constructed using the ``inline=True`` flag; this
|
||||
flag will prevent the implicit usage of ``RETURNING`` when the
|
||||
``INSERT`` statement is rendered, which isn't supported on a
|
||||
backend such as Oracle in conjunction with an ``INSERT..SELECT``
|
||||
combination::
|
||||
|
||||
sel = select([table1.c.a, table1.c.b]).where(table1.c.c > 5)
|
||||
ins = table2.insert(inline=True).from_select(['a', 'b'], sel)
|
||||
|
||||
.. note::
|
||||
|
||||
A SELECT..INSERT construct in SQL has no VALUES clause. Therefore
|
||||
:class:`.Column` objects which utilize Python-side defaults
|
||||
(e.g. as described at :ref:`metadata_defaults_toplevel`)
|
||||
will **not** take effect when using :meth:`.Insert.from_select`.
|
||||
|
||||
.. versionadded:: 0.8.3
|
||||
|
||||
"""
|
||||
if self.parameters:
|
||||
raise exc.InvalidRequestError(
|
||||
"This construct already inserts value expressions")
|
||||
|
||||
self.parameters, self._has_multi_parameters = \
|
||||
self._process_colparams(dict((n, Null()) for n in names))
|
||||
|
||||
self.select_names = names
|
||||
self.select = _interpret_as_select(select)
|
||||
|
||||
def _copy_internals(self, clone=_clone, **kw):
|
||||
# TODO: coverage
|
||||
self.parameters = self.parameters.copy()
|
||||
if self.select is not None:
|
||||
self.select = _clone(self.select)
|
||||
|
||||
|
||||
class Update(ValuesBase):
|
||||
"""Represent an Update construct.
|
||||
|
||||
The :class:`.Update` object is created using the :func:`update()`
|
||||
function.
|
||||
|
||||
"""
|
||||
__visit_name__ = 'update'
|
||||
|
||||
def __init__(self,
|
||||
table,
|
||||
whereclause=None,
|
||||
values=None,
|
||||
inline=False,
|
||||
bind=None,
|
||||
prefixes=None,
|
||||
returning=None,
|
||||
return_defaults=False,
|
||||
**dialect_kw):
|
||||
"""Construct an :class:`.Update` object.
|
||||
|
||||
E.g.::
|
||||
|
||||
from sqlalchemy import update
|
||||
|
||||
stmt = update(users).where(users.c.id==5).\\
|
||||
values(name='user #5')
|
||||
|
||||
Similar functionality is available via the
|
||||
:meth:`~.TableClause.update` method on
|
||||
:class:`.Table`::
|
||||
|
||||
stmt = users.update().\\
|
||||
where(users.c.id==5).\\
|
||||
values(name='user #5')
|
||||
|
||||
:param table: A :class:`.Table` object representing the database
|
||||
table to be updated.
|
||||
|
||||
:param whereclause: Optional SQL expression describing the ``WHERE``
|
||||
condition of the ``UPDATE`` statement. Modern applications
|
||||
may prefer to use the generative :meth:`~Update.where()`
|
||||
method to specify the ``WHERE`` clause.
|
||||
|
||||
The WHERE clause can refer to multiple tables.
|
||||
For databases which support this, an ``UPDATE FROM`` clause will
|
||||
be generated, or on MySQL, a multi-table update. The statement
|
||||
will fail on databases that don't have support for multi-table
|
||||
update statements. A SQL-standard method of referring to
|
||||
additional tables in the WHERE clause is to use a correlated
|
||||
subquery::
|
||||
|
||||
users.update().values(name='ed').where(
|
||||
users.c.name==select([addresses.c.email_address]).\\
|
||||
where(addresses.c.user_id==users.c.id).\\
|
||||
as_scalar()
|
||||
)
|
||||
|
||||
.. versionchanged:: 0.7.4
|
||||
The WHERE clause can refer to multiple tables.
|
||||
|
||||
:param values:
|
||||
Optional dictionary which specifies the ``SET`` conditions of the
|
||||
``UPDATE``. If left as ``None``, the ``SET``
|
||||
conditions are determined from those parameters passed to the
|
||||
statement during the execution and/or compilation of the
|
||||
statement. When compiled standalone without any parameters,
|
||||
the ``SET`` clause generates for all columns.
|
||||
|
||||
Modern applications may prefer to use the generative
|
||||
:meth:`.Update.values` method to set the values of the
|
||||
UPDATE statement.
|
||||
|
||||
:param inline:
|
||||
if True, SQL defaults present on :class:`.Column` objects via
|
||||
the ``default`` keyword will be compiled 'inline' into the statement
|
||||
and not pre-executed. This means that their values will not
|
||||
be available in the dictionary returned from
|
||||
:meth:`.ResultProxy.last_updated_params`.
|
||||
|
||||
If both ``values`` and compile-time bind parameters are present, the
|
||||
compile-time bind parameters override the information specified
|
||||
within ``values`` on a per-key basis.
|
||||
|
||||
The keys within ``values`` can be either :class:`.Column`
|
||||
objects or their string identifiers (specifically the "key" of the
|
||||
:class:`.Column`, normally but not necessarily equivalent to
|
||||
its "name"). Normally, the
|
||||
:class:`.Column` objects used here are expected to be
|
||||
part of the target :class:`.Table` that is the table
|
||||
to be updated. However when using MySQL, a multiple-table
|
||||
UPDATE statement can refer to columns from any of
|
||||
the tables referred to in the WHERE clause.
|
||||
|
||||
The values referred to in ``values`` are typically:
|
||||
|
||||
* a literal data value (i.e. string, number, etc.)
|
||||
* a SQL expression, such as a related :class:`.Column`,
|
||||
a scalar-returning :func:`.select` construct,
|
||||
etc.
|
||||
|
||||
When combining :func:`.select` constructs within the values
|
||||
clause of an :func:`.update` construct,
|
||||
the subquery represented by the :func:`.select` should be
|
||||
*correlated* to the parent table, that is, providing criterion
|
||||
which links the table inside the subquery to the outer table
|
||||
being updated::
|
||||
|
||||
users.update().values(
|
||||
name=select([addresses.c.email_address]).\\
|
||||
where(addresses.c.user_id==users.c.id).\\
|
||||
as_scalar()
|
||||
)
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`inserts_and_updates` - SQL Expression
|
||||
Language Tutorial
|
||||
|
||||
|
||||
"""
|
||||
ValuesBase.__init__(self, table, values, prefixes)
|
||||
self._bind = bind
|
||||
self._returning = returning
|
||||
if whereclause is not None:
|
||||
self._whereclause = _literal_as_text(whereclause)
|
||||
else:
|
||||
self._whereclause = None
|
||||
self.inline = inline
|
||||
self._validate_dialect_kwargs(dialect_kw)
|
||||
self._return_defaults = return_defaults
|
||||
|
||||
def get_children(self, **kwargs):
|
||||
if self._whereclause is not None:
|
||||
return self._whereclause,
|
||||
else:
|
||||
return ()
|
||||
|
||||
def _copy_internals(self, clone=_clone, **kw):
|
||||
# TODO: coverage
|
||||
self._whereclause = clone(self._whereclause, **kw)
|
||||
self.parameters = self.parameters.copy()
|
||||
|
||||
@_generative
|
||||
def where(self, whereclause):
|
||||
"""return a new update() construct with the given expression added to
|
||||
its WHERE clause, joined to the existing clause via AND, if any.
|
||||
|
||||
"""
|
||||
if self._whereclause is not None:
|
||||
self._whereclause = and_(self._whereclause,
|
||||
_literal_as_text(whereclause))
|
||||
else:
|
||||
self._whereclause = _literal_as_text(whereclause)
|
||||
|
||||
@property
|
||||
def _extra_froms(self):
|
||||
# TODO: this could be made memoized
|
||||
# if the memoization is reset on each generative call.
|
||||
froms = []
|
||||
seen = set([self.table])
|
||||
|
||||
if self._whereclause is not None:
|
||||
for item in _from_objects(self._whereclause):
|
||||
if not seen.intersection(item._cloned_set):
|
||||
froms.append(item)
|
||||
seen.update(item._cloned_set)
|
||||
|
||||
return froms
|
||||
|
||||
|
||||
class Delete(UpdateBase):
|
||||
"""Represent a DELETE construct.
|
||||
|
||||
The :class:`.Delete` object is created using the :func:`delete()`
|
||||
function.
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = 'delete'
|
||||
|
||||
def __init__(self,
|
||||
table,
|
||||
whereclause=None,
|
||||
bind=None,
|
||||
returning=None,
|
||||
prefixes=None,
|
||||
**dialect_kw):
|
||||
"""Construct :class:`.Delete` object.
|
||||
|
||||
Similar functionality is available via the
|
||||
:meth:`~.TableClause.delete` method on
|
||||
:class:`~.schema.Table`.
|
||||
|
||||
:param table: The table to be updated.
|
||||
|
||||
:param whereclause: A :class:`.ClauseElement` describing the ``WHERE``
|
||||
condition of the ``UPDATE`` statement. Note that the
|
||||
:meth:`~Delete.where()` generative method may be used instead.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`deletes` - SQL Expression Tutorial
|
||||
|
||||
"""
|
||||
self._bind = bind
|
||||
self.table = _interpret_as_from(table)
|
||||
self._returning = returning
|
||||
|
||||
if prefixes:
|
||||
self._setup_prefixes(prefixes)
|
||||
|
||||
if whereclause is not None:
|
||||
self._whereclause = _literal_as_text(whereclause)
|
||||
else:
|
||||
self._whereclause = None
|
||||
|
||||
self._validate_dialect_kwargs(dialect_kw)
|
||||
|
||||
def get_children(self, **kwargs):
|
||||
if self._whereclause is not None:
|
||||
return self._whereclause,
|
||||
else:
|
||||
return ()
|
||||
|
||||
@_generative
|
||||
def where(self, whereclause):
|
||||
"""Add the given WHERE clause to a newly returned delete construct."""
|
||||
|
||||
if self._whereclause is not None:
|
||||
self._whereclause = and_(self._whereclause,
|
||||
_literal_as_text(whereclause))
|
||||
else:
|
||||
self._whereclause = _literal_as_text(whereclause)
|
||||
|
||||
def _copy_internals(self, clone=_clone, **kw):
|
||||
# TODO: coverage
|
||||
self._whereclause = clone(self._whereclause, **kw)
|
||||
3577
lib/python3.5/site-packages/sqlalchemy/sql/elements.py
Normal file
3577
lib/python3.5/site-packages/sqlalchemy/sql/elements.py
Normal file
File diff suppressed because it is too large
Load diff
134
lib/python3.5/site-packages/sqlalchemy/sql/expression.py
Normal file
134
lib/python3.5/site-packages/sqlalchemy/sql/expression.py
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
# sql/expression.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Defines the public namespace for SQL expression constructs.
|
||||
|
||||
Prior to version 0.9, this module contained all of "elements", "dml",
|
||||
"default_comparator" and "selectable". The module was broken up
|
||||
and most "factory" functions were moved to be grouped with their associated
|
||||
class.
|
||||
|
||||
"""
|
||||
|
||||
__all__ = [
|
||||
'Alias', 'ClauseElement', 'ColumnCollection', 'ColumnElement',
|
||||
'CompoundSelect', 'Delete', 'FromClause', 'Insert', 'Join', 'Select',
|
||||
'Selectable', 'TableClause', 'Update', 'alias', 'and_', 'asc', 'between',
|
||||
'bindparam', 'case', 'cast', 'column', 'delete', 'desc', 'distinct',
|
||||
'except_', 'except_all', 'exists', 'extract', 'func', 'modifier',
|
||||
'collate', 'insert', 'intersect', 'intersect_all', 'join', 'label',
|
||||
'literal', 'literal_column', 'not_', 'null', 'nullsfirst', 'nullslast',
|
||||
'or_', 'outparam', 'outerjoin', 'over', 'select', 'subquery',
|
||||
'table', 'text',
|
||||
'tuple_', 'type_coerce', 'union', 'union_all', 'update']
|
||||
|
||||
|
||||
from .visitors import Visitable
|
||||
from .functions import func, modifier, FunctionElement, Function
|
||||
from ..util.langhelpers import public_factory
|
||||
from .elements import ClauseElement, ColumnElement,\
|
||||
BindParameter, UnaryExpression, BooleanClauseList, \
|
||||
Label, Cast, Case, ColumnClause, TextClause, Over, Null, \
|
||||
True_, False_, BinaryExpression, Tuple, TypeClause, Extract, \
|
||||
Grouping, not_, \
|
||||
collate, literal_column, between,\
|
||||
literal, outparam, type_coerce, ClauseList
|
||||
|
||||
from .elements import SavepointClause, RollbackToSavepointClause, \
|
||||
ReleaseSavepointClause
|
||||
|
||||
from .base import ColumnCollection, Generative, Executable, \
|
||||
PARSE_AUTOCOMMIT
|
||||
|
||||
from .selectable import Alias, Join, Select, Selectable, TableClause, \
|
||||
CompoundSelect, CTE, FromClause, FromGrouping, SelectBase, \
|
||||
alias, GenerativeSelect, \
|
||||
subquery, HasPrefixes, Exists, ScalarSelect, TextAsFrom
|
||||
|
||||
|
||||
from .dml import Insert, Update, Delete, UpdateBase, ValuesBase
|
||||
|
||||
# factory functions - these pull class-bound constructors and classmethods
|
||||
# from SQL elements and selectables into public functions. This allows
|
||||
# the functions to be available in the sqlalchemy.sql.* namespace and
|
||||
# to be auto-cross-documenting from the function to the class itself.
|
||||
|
||||
and_ = public_factory(BooleanClauseList.and_, ".expression.and_")
|
||||
or_ = public_factory(BooleanClauseList.or_, ".expression.or_")
|
||||
bindparam = public_factory(BindParameter, ".expression.bindparam")
|
||||
select = public_factory(Select, ".expression.select")
|
||||
text = public_factory(TextClause._create_text, ".expression.text")
|
||||
table = public_factory(TableClause, ".expression.table")
|
||||
column = public_factory(ColumnClause, ".expression.column")
|
||||
over = public_factory(Over, ".expression.over")
|
||||
label = public_factory(Label, ".expression.label")
|
||||
case = public_factory(Case, ".expression.case")
|
||||
cast = public_factory(Cast, ".expression.cast")
|
||||
extract = public_factory(Extract, ".expression.extract")
|
||||
tuple_ = public_factory(Tuple, ".expression.tuple_")
|
||||
except_ = public_factory(CompoundSelect._create_except, ".expression.except_")
|
||||
except_all = public_factory(
|
||||
CompoundSelect._create_except_all, ".expression.except_all")
|
||||
intersect = public_factory(
|
||||
CompoundSelect._create_intersect, ".expression.intersect")
|
||||
intersect_all = public_factory(
|
||||
CompoundSelect._create_intersect_all, ".expression.intersect_all")
|
||||
union = public_factory(CompoundSelect._create_union, ".expression.union")
|
||||
union_all = public_factory(
|
||||
CompoundSelect._create_union_all, ".expression.union_all")
|
||||
exists = public_factory(Exists, ".expression.exists")
|
||||
nullsfirst = public_factory(
|
||||
UnaryExpression._create_nullsfirst, ".expression.nullsfirst")
|
||||
nullslast = public_factory(
|
||||
UnaryExpression._create_nullslast, ".expression.nullslast")
|
||||
asc = public_factory(UnaryExpression._create_asc, ".expression.asc")
|
||||
desc = public_factory(UnaryExpression._create_desc, ".expression.desc")
|
||||
distinct = public_factory(
|
||||
UnaryExpression._create_distinct, ".expression.distinct")
|
||||
true = public_factory(True_._singleton, ".expression.true")
|
||||
false = public_factory(False_._singleton, ".expression.false")
|
||||
null = public_factory(Null._singleton, ".expression.null")
|
||||
join = public_factory(Join._create_join, ".expression.join")
|
||||
outerjoin = public_factory(Join._create_outerjoin, ".expression.outerjoin")
|
||||
insert = public_factory(Insert, ".expression.insert")
|
||||
update = public_factory(Update, ".expression.update")
|
||||
delete = public_factory(Delete, ".expression.delete")
|
||||
|
||||
|
||||
# internal functions still being called from tests and the ORM,
|
||||
# these might be better off in some other namespace
|
||||
from .base import _from_objects
|
||||
from .elements import _literal_as_text, _clause_element_as_expr,\
|
||||
_is_column, _labeled, _only_column_elements, _string_or_unprintable, \
|
||||
_truncated_label, _clone, _cloned_difference, _cloned_intersection,\
|
||||
_column_as_key, _literal_as_binds, _select_iterables, \
|
||||
_corresponding_column_or_error
|
||||
from .selectable import _interpret_as_from
|
||||
|
||||
|
||||
# old names for compatibility
|
||||
_Executable = Executable
|
||||
_BindParamClause = BindParameter
|
||||
_Label = Label
|
||||
_SelectBase = SelectBase
|
||||
_BinaryExpression = BinaryExpression
|
||||
_Cast = Cast
|
||||
_Null = Null
|
||||
_False = False_
|
||||
_True = True_
|
||||
_TextClause = TextClause
|
||||
_UnaryExpression = UnaryExpression
|
||||
_Case = Case
|
||||
_Tuple = Tuple
|
||||
_Over = Over
|
||||
_Generative = Generative
|
||||
_TypeClause = TypeClause
|
||||
_Extract = Extract
|
||||
_Exists = Exists
|
||||
_Grouping = Grouping
|
||||
_FromGrouping = FromGrouping
|
||||
_ScalarSelect = ScalarSelect
|
||||
547
lib/python3.5/site-packages/sqlalchemy/sql/functions.py
Normal file
547
lib/python3.5/site-packages/sqlalchemy/sql/functions.py
Normal file
|
|
@ -0,0 +1,547 @@
|
|||
# sql/functions.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""SQL function API, factories, and built-in functions.
|
||||
|
||||
"""
|
||||
from . import sqltypes, schema
|
||||
from .base import Executable
|
||||
from .elements import ClauseList, Cast, Extract, _literal_as_binds, \
|
||||
literal_column, _type_from_args, ColumnElement, _clone,\
|
||||
Over, BindParameter
|
||||
from .selectable import FromClause, Select
|
||||
|
||||
from . import operators
|
||||
from .visitors import VisitableType
|
||||
from .. import util
|
||||
from . import annotation
|
||||
|
||||
_registry = util.defaultdict(dict)
|
||||
|
||||
|
||||
def register_function(identifier, fn, package="_default"):
|
||||
"""Associate a callable with a particular func. name.
|
||||
|
||||
This is normally called by _GenericMeta, but is also
|
||||
available by itself so that a non-Function construct
|
||||
can be associated with the :data:`.func` accessor (i.e.
|
||||
CAST, EXTRACT).
|
||||
|
||||
"""
|
||||
reg = _registry[package]
|
||||
reg[identifier] = fn
|
||||
|
||||
|
||||
class FunctionElement(Executable, ColumnElement, FromClause):
|
||||
"""Base for SQL function-oriented constructs.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:class:`.Function` - named SQL function.
|
||||
|
||||
:data:`.func` - namespace which produces registered or ad-hoc
|
||||
:class:`.Function` instances.
|
||||
|
||||
:class:`.GenericFunction` - allows creation of registered function
|
||||
types.
|
||||
|
||||
"""
|
||||
|
||||
packagenames = ()
|
||||
|
||||
def __init__(self, *clauses, **kwargs):
|
||||
"""Construct a :class:`.FunctionElement`.
|
||||
"""
|
||||
args = [_literal_as_binds(c, self.name) for c in clauses]
|
||||
self.clause_expr = ClauseList(
|
||||
operator=operators.comma_op,
|
||||
group_contents=True, *args).\
|
||||
self_group()
|
||||
|
||||
def _execute_on_connection(self, connection, multiparams, params):
|
||||
return connection._execute_function(self, multiparams, params)
|
||||
|
||||
@property
|
||||
def columns(self):
|
||||
"""Fulfill the 'columns' contract of :class:`.ColumnElement`.
|
||||
|
||||
Returns a single-element list consisting of this object.
|
||||
|
||||
"""
|
||||
return [self]
|
||||
|
||||
@util.memoized_property
|
||||
def clauses(self):
|
||||
"""Return the underlying :class:`.ClauseList` which contains
|
||||
the arguments for this :class:`.FunctionElement`.
|
||||
|
||||
"""
|
||||
return self.clause_expr.element
|
||||
|
||||
def over(self, partition_by=None, order_by=None):
|
||||
"""Produce an OVER clause against this function.
|
||||
|
||||
Used against aggregate or so-called "window" functions,
|
||||
for database backends that support window functions.
|
||||
|
||||
The expression::
|
||||
|
||||
func.row_number().over(order_by='x')
|
||||
|
||||
is shorthand for::
|
||||
|
||||
from sqlalchemy import over
|
||||
over(func.row_number(), order_by='x')
|
||||
|
||||
See :func:`~.expression.over` for a full description.
|
||||
|
||||
.. versionadded:: 0.7
|
||||
|
||||
"""
|
||||
return Over(self, partition_by=partition_by, order_by=order_by)
|
||||
|
||||
@property
|
||||
def _from_objects(self):
|
||||
return self.clauses._from_objects
|
||||
|
||||
def get_children(self, **kwargs):
|
||||
return self.clause_expr,
|
||||
|
||||
def _copy_internals(self, clone=_clone, **kw):
|
||||
self.clause_expr = clone(self.clause_expr, **kw)
|
||||
self._reset_exported()
|
||||
FunctionElement.clauses._reset(self)
|
||||
|
||||
def select(self):
|
||||
"""Produce a :func:`~.expression.select` construct
|
||||
against this :class:`.FunctionElement`.
|
||||
|
||||
This is shorthand for::
|
||||
|
||||
s = select([function_element])
|
||||
|
||||
"""
|
||||
s = Select([self])
|
||||
if self._execution_options:
|
||||
s = s.execution_options(**self._execution_options)
|
||||
return s
|
||||
|
||||
def scalar(self):
|
||||
"""Execute this :class:`.FunctionElement` against an embedded
|
||||
'bind' and return a scalar value.
|
||||
|
||||
This first calls :meth:`~.FunctionElement.select` to
|
||||
produce a SELECT construct.
|
||||
|
||||
Note that :class:`.FunctionElement` can be passed to
|
||||
the :meth:`.Connectable.scalar` method of :class:`.Connection`
|
||||
or :class:`.Engine`.
|
||||
|
||||
"""
|
||||
return self.select().execute().scalar()
|
||||
|
||||
def execute(self):
|
||||
"""Execute this :class:`.FunctionElement` against an embedded
|
||||
'bind'.
|
||||
|
||||
This first calls :meth:`~.FunctionElement.select` to
|
||||
produce a SELECT construct.
|
||||
|
||||
Note that :class:`.FunctionElement` can be passed to
|
||||
the :meth:`.Connectable.execute` method of :class:`.Connection`
|
||||
or :class:`.Engine`.
|
||||
|
||||
"""
|
||||
return self.select().execute()
|
||||
|
||||
def _bind_param(self, operator, obj):
|
||||
return BindParameter(None, obj, _compared_to_operator=operator,
|
||||
_compared_to_type=self.type, unique=True)
|
||||
|
||||
|
||||
class _FunctionGenerator(object):
|
||||
"""Generate :class:`.Function` objects based on getattr calls."""
|
||||
|
||||
def __init__(self, **opts):
|
||||
self.__names = []
|
||||
self.opts = opts
|
||||
|
||||
def __getattr__(self, name):
|
||||
# passthru __ attributes; fixes pydoc
|
||||
if name.startswith('__'):
|
||||
try:
|
||||
return self.__dict__[name]
|
||||
except KeyError:
|
||||
raise AttributeError(name)
|
||||
|
||||
elif name.endswith('_'):
|
||||
name = name[0:-1]
|
||||
f = _FunctionGenerator(**self.opts)
|
||||
f.__names = list(self.__names) + [name]
|
||||
return f
|
||||
|
||||
def __call__(self, *c, **kwargs):
|
||||
o = self.opts.copy()
|
||||
o.update(kwargs)
|
||||
|
||||
tokens = len(self.__names)
|
||||
|
||||
if tokens == 2:
|
||||
package, fname = self.__names
|
||||
elif tokens == 1:
|
||||
package, fname = "_default", self.__names[0]
|
||||
else:
|
||||
package = None
|
||||
|
||||
if package is not None:
|
||||
func = _registry[package].get(fname)
|
||||
if func is not None:
|
||||
return func(*c, **o)
|
||||
|
||||
return Function(self.__names[-1],
|
||||
packagenames=self.__names[0:-1], *c, **o)
|
||||
|
||||
|
||||
func = _FunctionGenerator()
|
||||
"""Generate SQL function expressions.
|
||||
|
||||
:data:`.func` is a special object instance which generates SQL
|
||||
functions based on name-based attributes, e.g.::
|
||||
|
||||
>>> print func.count(1)
|
||||
count(:param_1)
|
||||
|
||||
The element is a column-oriented SQL element like any other, and is
|
||||
used in that way::
|
||||
|
||||
>>> print select([func.count(table.c.id)])
|
||||
SELECT count(sometable.id) FROM sometable
|
||||
|
||||
Any name can be given to :data:`.func`. If the function name is unknown to
|
||||
SQLAlchemy, it will be rendered exactly as is. For common SQL functions
|
||||
which SQLAlchemy is aware of, the name may be interpreted as a *generic
|
||||
function* which will be compiled appropriately to the target database::
|
||||
|
||||
>>> print func.current_timestamp()
|
||||
CURRENT_TIMESTAMP
|
||||
|
||||
To call functions which are present in dot-separated packages,
|
||||
specify them in the same manner::
|
||||
|
||||
>>> print func.stats.yield_curve(5, 10)
|
||||
stats.yield_curve(:yield_curve_1, :yield_curve_2)
|
||||
|
||||
SQLAlchemy can be made aware of the return type of functions to enable
|
||||
type-specific lexical and result-based behavior. For example, to ensure
|
||||
that a string-based function returns a Unicode value and is similarly
|
||||
treated as a string in expressions, specify
|
||||
:class:`~sqlalchemy.types.Unicode` as the type:
|
||||
|
||||
>>> print func.my_string(u'hi', type_=Unicode) + ' ' + \
|
||||
... func.my_string(u'there', type_=Unicode)
|
||||
my_string(:my_string_1) || :my_string_2 || my_string(:my_string_3)
|
||||
|
||||
The object returned by a :data:`.func` call is usually an instance of
|
||||
:class:`.Function`.
|
||||
This object meets the "column" interface, including comparison and labeling
|
||||
functions. The object can also be passed the :meth:`~.Connectable.execute`
|
||||
method of a :class:`.Connection` or :class:`.Engine`, where it will be
|
||||
wrapped inside of a SELECT statement first::
|
||||
|
||||
print connection.execute(func.current_timestamp()).scalar()
|
||||
|
||||
In a few exception cases, the :data:`.func` accessor
|
||||
will redirect a name to a built-in expression such as :func:`.cast`
|
||||
or :func:`.extract`, as these names have well-known meaning
|
||||
but are not exactly the same as "functions" from a SQLAlchemy
|
||||
perspective.
|
||||
|
||||
.. versionadded:: 0.8 :data:`.func` can return non-function expression
|
||||
constructs for common quasi-functional names like :func:`.cast`
|
||||
and :func:`.extract`.
|
||||
|
||||
Functions which are interpreted as "generic" functions know how to
|
||||
calculate their return type automatically. For a listing of known generic
|
||||
functions, see :ref:`generic_functions`.
|
||||
|
||||
.. note::
|
||||
|
||||
The :data:`.func` construct has only limited support for calling
|
||||
standalone "stored procedures", especially those with special
|
||||
parameterization concerns.
|
||||
|
||||
See the section :ref:`stored_procedures` for details on how to use
|
||||
the DBAPI-level ``callproc()`` method for fully traditional stored
|
||||
procedures.
|
||||
|
||||
"""
|
||||
|
||||
modifier = _FunctionGenerator(group=False)
|
||||
|
||||
|
||||
class Function(FunctionElement):
|
||||
"""Describe a named SQL function.
|
||||
|
||||
See the superclass :class:`.FunctionElement` for a description
|
||||
of public methods.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:data:`.func` - namespace which produces registered or ad-hoc
|
||||
:class:`.Function` instances.
|
||||
|
||||
:class:`.GenericFunction` - allows creation of registered function
|
||||
types.
|
||||
|
||||
"""
|
||||
|
||||
__visit_name__ = 'function'
|
||||
|
||||
def __init__(self, name, *clauses, **kw):
|
||||
"""Construct a :class:`.Function`.
|
||||
|
||||
The :data:`.func` construct is normally used to construct
|
||||
new :class:`.Function` instances.
|
||||
|
||||
"""
|
||||
self.packagenames = kw.pop('packagenames', None) or []
|
||||
self.name = name
|
||||
self._bind = kw.get('bind', None)
|
||||
self.type = sqltypes.to_instance(kw.get('type_', None))
|
||||
|
||||
FunctionElement.__init__(self, *clauses, **kw)
|
||||
|
||||
def _bind_param(self, operator, obj):
|
||||
return BindParameter(self.name, obj,
|
||||
_compared_to_operator=operator,
|
||||
_compared_to_type=self.type,
|
||||
unique=True)
|
||||
|
||||
|
||||
class _GenericMeta(VisitableType):
|
||||
def __init__(cls, clsname, bases, clsdict):
|
||||
if annotation.Annotated not in cls.__mro__:
|
||||
cls.name = name = clsdict.get('name', clsname)
|
||||
cls.identifier = identifier = clsdict.get('identifier', name)
|
||||
package = clsdict.pop('package', '_default')
|
||||
# legacy
|
||||
if '__return_type__' in clsdict:
|
||||
cls.type = clsdict['__return_type__']
|
||||
register_function(identifier, cls, package)
|
||||
super(_GenericMeta, cls).__init__(clsname, bases, clsdict)
|
||||
|
||||
|
||||
class GenericFunction(util.with_metaclass(_GenericMeta, Function)):
|
||||
"""Define a 'generic' function.
|
||||
|
||||
A generic function is a pre-established :class:`.Function`
|
||||
class that is instantiated automatically when called
|
||||
by name from the :data:`.func` attribute. Note that
|
||||
calling any name from :data:`.func` has the effect that
|
||||
a new :class:`.Function` instance is created automatically,
|
||||
given that name. The primary use case for defining
|
||||
a :class:`.GenericFunction` class is so that a function
|
||||
of a particular name may be given a fixed return type.
|
||||
It can also include custom argument parsing schemes as well
|
||||
as additional methods.
|
||||
|
||||
Subclasses of :class:`.GenericFunction` are automatically
|
||||
registered under the name of the class. For
|
||||
example, a user-defined function ``as_utc()`` would
|
||||
be available immediately::
|
||||
|
||||
from sqlalchemy.sql.functions import GenericFunction
|
||||
from sqlalchemy.types import DateTime
|
||||
|
||||
class as_utc(GenericFunction):
|
||||
type = DateTime
|
||||
|
||||
print select([func.as_utc()])
|
||||
|
||||
User-defined generic functions can be organized into
|
||||
packages by specifying the "package" attribute when defining
|
||||
:class:`.GenericFunction`. Third party libraries
|
||||
containing many functions may want to use this in order
|
||||
to avoid name conflicts with other systems. For example,
|
||||
if our ``as_utc()`` function were part of a package
|
||||
"time"::
|
||||
|
||||
class as_utc(GenericFunction):
|
||||
type = DateTime
|
||||
package = "time"
|
||||
|
||||
The above function would be available from :data:`.func`
|
||||
using the package name ``time``::
|
||||
|
||||
print select([func.time.as_utc()])
|
||||
|
||||
A final option is to allow the function to be accessed
|
||||
from one name in :data:`.func` but to render as a different name.
|
||||
The ``identifier`` attribute will override the name used to
|
||||
access the function as loaded from :data:`.func`, but will retain
|
||||
the usage of ``name`` as the rendered name::
|
||||
|
||||
class GeoBuffer(GenericFunction):
|
||||
type = Geometry
|
||||
package = "geo"
|
||||
name = "ST_Buffer"
|
||||
identifier = "buffer"
|
||||
|
||||
The above function will render as follows::
|
||||
|
||||
>>> print func.geo.buffer()
|
||||
ST_Buffer()
|
||||
|
||||
.. versionadded:: 0.8 :class:`.GenericFunction` now supports
|
||||
automatic registration of new functions as well as package
|
||||
and custom naming support.
|
||||
|
||||
.. versionchanged:: 0.8 The attribute name ``type`` is used
|
||||
to specify the function's return type at the class level.
|
||||
Previously, the name ``__return_type__`` was used. This
|
||||
name is still recognized for backwards-compatibility.
|
||||
|
||||
"""
|
||||
|
||||
coerce_arguments = True
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
parsed_args = kwargs.pop('_parsed_args', None)
|
||||
if parsed_args is None:
|
||||
parsed_args = [_literal_as_binds(c) for c in args]
|
||||
self.packagenames = []
|
||||
self._bind = kwargs.get('bind', None)
|
||||
self.clause_expr = ClauseList(
|
||||
operator=operators.comma_op,
|
||||
group_contents=True, *parsed_args).self_group()
|
||||
self.type = sqltypes.to_instance(
|
||||
kwargs.pop("type_", None) or getattr(self, 'type', None))
|
||||
|
||||
register_function("cast", Cast)
|
||||
register_function("extract", Extract)
|
||||
|
||||
|
||||
class next_value(GenericFunction):
|
||||
"""Represent the 'next value', given a :class:`.Sequence`
|
||||
as its single argument.
|
||||
|
||||
Compiles into the appropriate function on each backend,
|
||||
or will raise NotImplementedError if used on a backend
|
||||
that does not provide support for sequences.
|
||||
|
||||
"""
|
||||
type = sqltypes.Integer()
|
||||
name = "next_value"
|
||||
|
||||
def __init__(self, seq, **kw):
|
||||
assert isinstance(seq, schema.Sequence), \
|
||||
"next_value() accepts a Sequence object as input."
|
||||
self._bind = kw.get('bind', None)
|
||||
self.sequence = seq
|
||||
|
||||
@property
|
||||
def _from_objects(self):
|
||||
return []
|
||||
|
||||
|
||||
class AnsiFunction(GenericFunction):
|
||||
def __init__(self, **kwargs):
|
||||
GenericFunction.__init__(self, **kwargs)
|
||||
|
||||
|
||||
class ReturnTypeFromArgs(GenericFunction):
|
||||
"""Define a function whose return type is the same as its arguments."""
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
args = [_literal_as_binds(c) for c in args]
|
||||
kwargs.setdefault('type_', _type_from_args(args))
|
||||
kwargs['_parsed_args'] = args
|
||||
GenericFunction.__init__(self, *args, **kwargs)
|
||||
|
||||
|
||||
class coalesce(ReturnTypeFromArgs):
|
||||
pass
|
||||
|
||||
|
||||
class max(ReturnTypeFromArgs):
|
||||
pass
|
||||
|
||||
|
||||
class min(ReturnTypeFromArgs):
|
||||
pass
|
||||
|
||||
|
||||
class sum(ReturnTypeFromArgs):
|
||||
pass
|
||||
|
||||
|
||||
class now(GenericFunction):
|
||||
type = sqltypes.DateTime
|
||||
|
||||
|
||||
class concat(GenericFunction):
|
||||
type = sqltypes.String
|
||||
|
||||
|
||||
class char_length(GenericFunction):
|
||||
type = sqltypes.Integer
|
||||
|
||||
def __init__(self, arg, **kwargs):
|
||||
GenericFunction.__init__(self, arg, **kwargs)
|
||||
|
||||
|
||||
class random(GenericFunction):
|
||||
pass
|
||||
|
||||
|
||||
class count(GenericFunction):
|
||||
"""The ANSI COUNT aggregate function. With no arguments,
|
||||
emits COUNT \*.
|
||||
|
||||
"""
|
||||
type = sqltypes.Integer
|
||||
|
||||
def __init__(self, expression=None, **kwargs):
|
||||
if expression is None:
|
||||
expression = literal_column('*')
|
||||
GenericFunction.__init__(self, expression, **kwargs)
|
||||
|
||||
|
||||
class current_date(AnsiFunction):
|
||||
type = sqltypes.Date
|
||||
|
||||
|
||||
class current_time(AnsiFunction):
|
||||
type = sqltypes.Time
|
||||
|
||||
|
||||
class current_timestamp(AnsiFunction):
|
||||
type = sqltypes.DateTime
|
||||
|
||||
|
||||
class current_user(AnsiFunction):
|
||||
type = sqltypes.String
|
||||
|
||||
|
||||
class localtime(AnsiFunction):
|
||||
type = sqltypes.DateTime
|
||||
|
||||
|
||||
class localtimestamp(AnsiFunction):
|
||||
type = sqltypes.DateTime
|
||||
|
||||
|
||||
class session_user(AnsiFunction):
|
||||
type = sqltypes.String
|
||||
|
||||
|
||||
class sysdate(AnsiFunction):
|
||||
type = sqltypes.DateTime
|
||||
|
||||
|
||||
class user(AnsiFunction):
|
||||
type = sqltypes.String
|
||||
144
lib/python3.5/site-packages/sqlalchemy/sql/naming.py
Normal file
144
lib/python3.5/site-packages/sqlalchemy/sql/naming.py
Normal file
|
|
@ -0,0 +1,144 @@
|
|||
# sqlalchemy/naming.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Establish constraint and index naming conventions.
|
||||
|
||||
|
||||
"""
|
||||
|
||||
from .schema import Constraint, ForeignKeyConstraint, PrimaryKeyConstraint, \
|
||||
UniqueConstraint, CheckConstraint, Index, Table, Column
|
||||
from .. import event, events
|
||||
from .. import exc
|
||||
from .elements import _truncated_label, _defer_name, _defer_none_name, conv
|
||||
import re
|
||||
|
||||
|
||||
class ConventionDict(object):
|
||||
|
||||
def __init__(self, const, table, convention):
|
||||
self.const = const
|
||||
self._is_fk = isinstance(const, ForeignKeyConstraint)
|
||||
self.table = table
|
||||
self.convention = convention
|
||||
self._const_name = const.name
|
||||
|
||||
def _key_table_name(self):
|
||||
return self.table.name
|
||||
|
||||
def _column_X(self, idx):
|
||||
if self._is_fk:
|
||||
fk = self.const.elements[idx]
|
||||
return fk.parent
|
||||
else:
|
||||
return list(self.const.columns)[idx]
|
||||
|
||||
def _key_constraint_name(self):
|
||||
if isinstance(self._const_name, (type(None), _defer_none_name)):
|
||||
raise exc.InvalidRequestError(
|
||||
"Naming convention including "
|
||||
"%(constraint_name)s token requires that "
|
||||
"constraint is explicitly named."
|
||||
)
|
||||
if not isinstance(self._const_name, conv):
|
||||
self.const.name = None
|
||||
return self._const_name
|
||||
|
||||
def _key_column_X_name(self, idx):
|
||||
return self._column_X(idx).name
|
||||
|
||||
def _key_column_X_label(self, idx):
|
||||
return self._column_X(idx)._label
|
||||
|
||||
def _key_referred_table_name(self):
|
||||
fk = self.const.elements[0]
|
||||
refs = fk.target_fullname.split(".")
|
||||
if len(refs) == 3:
|
||||
refschema, reftable, refcol = refs
|
||||
else:
|
||||
reftable, refcol = refs
|
||||
return reftable
|
||||
|
||||
def _key_referred_column_X_name(self, idx):
|
||||
fk = self.const.elements[idx]
|
||||
refs = fk.target_fullname.split(".")
|
||||
if len(refs) == 3:
|
||||
refschema, reftable, refcol = refs
|
||||
else:
|
||||
reftable, refcol = refs
|
||||
return refcol
|
||||
|
||||
def __getitem__(self, key):
|
||||
if key in self.convention:
|
||||
return self.convention[key](self.const, self.table)
|
||||
elif hasattr(self, '_key_%s' % key):
|
||||
return getattr(self, '_key_%s' % key)()
|
||||
else:
|
||||
col_template = re.match(r".*_?column_(\d+)_.+", key)
|
||||
if col_template:
|
||||
idx = col_template.group(1)
|
||||
attr = "_key_" + key.replace(idx, "X")
|
||||
idx = int(idx)
|
||||
if hasattr(self, attr):
|
||||
return getattr(self, attr)(idx)
|
||||
raise KeyError(key)
|
||||
|
||||
_prefix_dict = {
|
||||
Index: "ix",
|
||||
PrimaryKeyConstraint: "pk",
|
||||
CheckConstraint: "ck",
|
||||
UniqueConstraint: "uq",
|
||||
ForeignKeyConstraint: "fk"
|
||||
}
|
||||
|
||||
|
||||
def _get_convention(dict_, key):
|
||||
|
||||
for super_ in key.__mro__:
|
||||
if super_ in _prefix_dict and _prefix_dict[super_] in dict_:
|
||||
return dict_[_prefix_dict[super_]]
|
||||
elif super_ in dict_:
|
||||
return dict_[super_]
|
||||
else:
|
||||
return None
|
||||
|
||||
|
||||
def _constraint_name_for_table(const, table):
|
||||
metadata = table.metadata
|
||||
convention = _get_convention(metadata.naming_convention, type(const))
|
||||
|
||||
if isinstance(const.name, conv):
|
||||
return const.name
|
||||
elif convention is not None and (
|
||||
const.name is None or not isinstance(const.name, conv) and
|
||||
"constraint_name" in convention
|
||||
):
|
||||
return conv(
|
||||
convention % ConventionDict(const, table,
|
||||
metadata.naming_convention)
|
||||
)
|
||||
elif isinstance(convention, _defer_none_name):
|
||||
return None
|
||||
|
||||
|
||||
@event.listens_for(Constraint, "after_parent_attach")
|
||||
@event.listens_for(Index, "after_parent_attach")
|
||||
def _constraint_name(const, table):
|
||||
if isinstance(table, Column):
|
||||
# for column-attached constraint, set another event
|
||||
# to link the column attached to the table as this constraint
|
||||
# associated with the table.
|
||||
event.listen(table, "after_parent_attach",
|
||||
lambda col, table: _constraint_name(const, table)
|
||||
)
|
||||
elif isinstance(table, Table):
|
||||
if isinstance(const.name, (conv, _defer_name)):
|
||||
return
|
||||
|
||||
newname = _constraint_name_for_table(const, table)
|
||||
if newname is not None:
|
||||
const.name = newname
|
||||
884
lib/python3.5/site-packages/sqlalchemy/sql/operators.py
Normal file
884
lib/python3.5/site-packages/sqlalchemy/sql/operators.py
Normal file
|
|
@ -0,0 +1,884 @@
|
|||
# sql/operators.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Defines operators used in SQL expressions."""
|
||||
|
||||
from .. import util
|
||||
|
||||
|
||||
from operator import (
|
||||
and_, or_, inv, add, mul, sub, mod, truediv, lt, le, ne, gt, ge, eq, neg,
|
||||
getitem, lshift, rshift
|
||||
)
|
||||
|
||||
if util.py2k:
|
||||
from operator import div
|
||||
else:
|
||||
div = truediv
|
||||
|
||||
|
||||
class Operators(object):
|
||||
"""Base of comparison and logical operators.
|
||||
|
||||
Implements base methods
|
||||
:meth:`~sqlalchemy.sql.operators.Operators.operate` and
|
||||
:meth:`~sqlalchemy.sql.operators.Operators.reverse_operate`, as well as
|
||||
:meth:`~sqlalchemy.sql.operators.Operators.__and__`,
|
||||
:meth:`~sqlalchemy.sql.operators.Operators.__or__`,
|
||||
:meth:`~sqlalchemy.sql.operators.Operators.__invert__`.
|
||||
|
||||
Usually is used via its most common subclass
|
||||
:class:`.ColumnOperators`.
|
||||
|
||||
"""
|
||||
|
||||
def __and__(self, other):
|
||||
"""Implement the ``&`` operator.
|
||||
|
||||
When used with SQL expressions, results in an
|
||||
AND operation, equivalent to
|
||||
:func:`~.expression.and_`, that is::
|
||||
|
||||
a & b
|
||||
|
||||
is equivalent to::
|
||||
|
||||
from sqlalchemy import and_
|
||||
and_(a, b)
|
||||
|
||||
Care should be taken when using ``&`` regarding
|
||||
operator precedence; the ``&`` operator has the highest precedence.
|
||||
The operands should be enclosed in parenthesis if they contain
|
||||
further sub expressions::
|
||||
|
||||
(a == 2) & (b == 4)
|
||||
|
||||
"""
|
||||
return self.operate(and_, other)
|
||||
|
||||
def __or__(self, other):
|
||||
"""Implement the ``|`` operator.
|
||||
|
||||
When used with SQL expressions, results in an
|
||||
OR operation, equivalent to
|
||||
:func:`~.expression.or_`, that is::
|
||||
|
||||
a | b
|
||||
|
||||
is equivalent to::
|
||||
|
||||
from sqlalchemy import or_
|
||||
or_(a, b)
|
||||
|
||||
Care should be taken when using ``|`` regarding
|
||||
operator precedence; the ``|`` operator has the highest precedence.
|
||||
The operands should be enclosed in parenthesis if they contain
|
||||
further sub expressions::
|
||||
|
||||
(a == 2) | (b == 4)
|
||||
|
||||
"""
|
||||
return self.operate(or_, other)
|
||||
|
||||
def __invert__(self):
|
||||
"""Implement the ``~`` operator.
|
||||
|
||||
When used with SQL expressions, results in a
|
||||
NOT operation, equivalent to
|
||||
:func:`~.expression.not_`, that is::
|
||||
|
||||
~a
|
||||
|
||||
is equivalent to::
|
||||
|
||||
from sqlalchemy import not_
|
||||
not_(a)
|
||||
|
||||
"""
|
||||
return self.operate(inv)
|
||||
|
||||
def op(self, opstring, precedence=0, is_comparison=False):
|
||||
"""produce a generic operator function.
|
||||
|
||||
e.g.::
|
||||
|
||||
somecolumn.op("*")(5)
|
||||
|
||||
produces::
|
||||
|
||||
somecolumn * 5
|
||||
|
||||
This function can also be used to make bitwise operators explicit. For
|
||||
example::
|
||||
|
||||
somecolumn.op('&')(0xff)
|
||||
|
||||
is a bitwise AND of the value in ``somecolumn``.
|
||||
|
||||
:param operator: a string which will be output as the infix operator
|
||||
between this element and the expression passed to the
|
||||
generated function.
|
||||
|
||||
:param precedence: precedence to apply to the operator, when
|
||||
parenthesizing expressions. A lower number will cause the expression
|
||||
to be parenthesized when applied against another operator with
|
||||
higher precedence. The default value of ``0`` is lower than all
|
||||
operators except for the comma (``,``) and ``AS`` operators.
|
||||
A value of 100 will be higher or equal to all operators, and -100
|
||||
will be lower than or equal to all operators.
|
||||
|
||||
.. versionadded:: 0.8 - added the 'precedence' argument.
|
||||
|
||||
:param is_comparison: if True, the operator will be considered as a
|
||||
"comparison" operator, that is which evaulates to a boolean
|
||||
true/false value, like ``==``, ``>``, etc. This flag should be set
|
||||
so that ORM relationships can establish that the operator is a
|
||||
comparison operator when used in a custom join condition.
|
||||
|
||||
.. versionadded:: 0.9.2 - added the
|
||||
:paramref:`.Operators.op.is_comparison` flag.
|
||||
|
||||
.. seealso::
|
||||
|
||||
:ref:`types_operators`
|
||||
|
||||
:ref:`relationship_custom_operator`
|
||||
|
||||
"""
|
||||
operator = custom_op(opstring, precedence, is_comparison)
|
||||
|
||||
def against(other):
|
||||
return operator(self, other)
|
||||
return against
|
||||
|
||||
def operate(self, op, *other, **kwargs):
|
||||
"""Operate on an argument.
|
||||
|
||||
This is the lowest level of operation, raises
|
||||
:class:`NotImplementedError` by default.
|
||||
|
||||
Overriding this on a subclass can allow common
|
||||
behavior to be applied to all operations.
|
||||
For example, overriding :class:`.ColumnOperators`
|
||||
to apply ``func.lower()`` to the left and right
|
||||
side::
|
||||
|
||||
class MyComparator(ColumnOperators):
|
||||
def operate(self, op, other):
|
||||
return op(func.lower(self), func.lower(other))
|
||||
|
||||
:param op: Operator callable.
|
||||
:param \*other: the 'other' side of the operation. Will
|
||||
be a single scalar for most operations.
|
||||
:param \**kwargs: modifiers. These may be passed by special
|
||||
operators such as :meth:`ColumnOperators.contains`.
|
||||
|
||||
|
||||
"""
|
||||
raise NotImplementedError(str(op))
|
||||
|
||||
def reverse_operate(self, op, other, **kwargs):
|
||||
"""Reverse operate on an argument.
|
||||
|
||||
Usage is the same as :meth:`operate`.
|
||||
|
||||
"""
|
||||
raise NotImplementedError(str(op))
|
||||
|
||||
|
||||
class custom_op(object):
|
||||
"""Represent a 'custom' operator.
|
||||
|
||||
:class:`.custom_op` is normally instantitated when the
|
||||
:meth:`.ColumnOperators.op` method is used to create a
|
||||
custom operator callable. The class can also be used directly
|
||||
when programmatically constructing expressions. E.g.
|
||||
to represent the "factorial" operation::
|
||||
|
||||
from sqlalchemy.sql import UnaryExpression
|
||||
from sqlalchemy.sql import operators
|
||||
from sqlalchemy import Numeric
|
||||
|
||||
unary = UnaryExpression(table.c.somecolumn,
|
||||
modifier=operators.custom_op("!"),
|
||||
type_=Numeric)
|
||||
|
||||
"""
|
||||
__name__ = 'custom_op'
|
||||
|
||||
def __init__(self, opstring, precedence=0, is_comparison=False):
|
||||
self.opstring = opstring
|
||||
self.precedence = precedence
|
||||
self.is_comparison = is_comparison
|
||||
|
||||
def __eq__(self, other):
|
||||
return isinstance(other, custom_op) and \
|
||||
other.opstring == self.opstring
|
||||
|
||||
def __hash__(self):
|
||||
return id(self)
|
||||
|
||||
def __call__(self, left, right, **kw):
|
||||
return left.operate(self, right, **kw)
|
||||
|
||||
|
||||
class ColumnOperators(Operators):
|
||||
"""Defines boolean, comparison, and other operators for
|
||||
:class:`.ColumnElement` expressions.
|
||||
|
||||
By default, all methods call down to
|
||||
:meth:`.operate` or :meth:`.reverse_operate`,
|
||||
passing in the appropriate operator function from the
|
||||
Python builtin ``operator`` module or
|
||||
a SQLAlchemy-specific operator function from
|
||||
:mod:`sqlalchemy.expression.operators`. For example
|
||||
the ``__eq__`` function::
|
||||
|
||||
def __eq__(self, other):
|
||||
return self.operate(operators.eq, other)
|
||||
|
||||
Where ``operators.eq`` is essentially::
|
||||
|
||||
def eq(a, b):
|
||||
return a == b
|
||||
|
||||
The core column expression unit :class:`.ColumnElement`
|
||||
overrides :meth:`.Operators.operate` and others
|
||||
to return further :class:`.ColumnElement` constructs,
|
||||
so that the ``==`` operation above is replaced by a clause
|
||||
construct.
|
||||
|
||||
See also:
|
||||
|
||||
:ref:`types_operators`
|
||||
|
||||
:attr:`.TypeEngine.comparator_factory`
|
||||
|
||||
:class:`.ColumnOperators`
|
||||
|
||||
:class:`.PropComparator`
|
||||
|
||||
"""
|
||||
|
||||
timetuple = None
|
||||
"""Hack, allows datetime objects to be compared on the LHS."""
|
||||
|
||||
def __lt__(self, other):
|
||||
"""Implement the ``<`` operator.
|
||||
|
||||
In a column context, produces the clause ``a < b``.
|
||||
|
||||
"""
|
||||
return self.operate(lt, other)
|
||||
|
||||
def __le__(self, other):
|
||||
"""Implement the ``<=`` operator.
|
||||
|
||||
In a column context, produces the clause ``a <= b``.
|
||||
|
||||
"""
|
||||
return self.operate(le, other)
|
||||
|
||||
__hash__ = Operators.__hash__
|
||||
|
||||
def __eq__(self, other):
|
||||
"""Implement the ``==`` operator.
|
||||
|
||||
In a column context, produces the clause ``a = b``.
|
||||
If the target is ``None``, produces ``a IS NULL``.
|
||||
|
||||
"""
|
||||
return self.operate(eq, other)
|
||||
|
||||
def __ne__(self, other):
|
||||
"""Implement the ``!=`` operator.
|
||||
|
||||
In a column context, produces the clause ``a != b``.
|
||||
If the target is ``None``, produces ``a IS NOT NULL``.
|
||||
|
||||
"""
|
||||
return self.operate(ne, other)
|
||||
|
||||
def __gt__(self, other):
|
||||
"""Implement the ``>`` operator.
|
||||
|
||||
In a column context, produces the clause ``a > b``.
|
||||
|
||||
"""
|
||||
return self.operate(gt, other)
|
||||
|
||||
def __ge__(self, other):
|
||||
"""Implement the ``>=`` operator.
|
||||
|
||||
In a column context, produces the clause ``a >= b``.
|
||||
|
||||
"""
|
||||
return self.operate(ge, other)
|
||||
|
||||
def __neg__(self):
|
||||
"""Implement the ``-`` operator.
|
||||
|
||||
In a column context, produces the clause ``-a``.
|
||||
|
||||
"""
|
||||
return self.operate(neg)
|
||||
|
||||
def __getitem__(self, index):
|
||||
"""Implement the [] operator.
|
||||
|
||||
This can be used by some database-specific types
|
||||
such as Postgresql ARRAY and HSTORE.
|
||||
|
||||
"""
|
||||
return self.operate(getitem, index)
|
||||
|
||||
def __lshift__(self, other):
|
||||
"""implement the << operator.
|
||||
|
||||
Not used by SQLAlchemy core, this is provided
|
||||
for custom operator systems which want to use
|
||||
<< as an extension point.
|
||||
"""
|
||||
return self.operate(lshift, other)
|
||||
|
||||
def __rshift__(self, other):
|
||||
"""implement the >> operator.
|
||||
|
||||
Not used by SQLAlchemy core, this is provided
|
||||
for custom operator systems which want to use
|
||||
>> as an extension point.
|
||||
"""
|
||||
return self.operate(rshift, other)
|
||||
|
||||
def concat(self, other):
|
||||
"""Implement the 'concat' operator.
|
||||
|
||||
In a column context, produces the clause ``a || b``,
|
||||
or uses the ``concat()`` operator on MySQL.
|
||||
|
||||
"""
|
||||
return self.operate(concat_op, other)
|
||||
|
||||
def like(self, other, escape=None):
|
||||
"""Implement the ``like`` operator.
|
||||
|
||||
In a column context, produces the clause ``a LIKE other``.
|
||||
|
||||
E.g.::
|
||||
|
||||
select([sometable]).where(sometable.c.column.like("%foobar%"))
|
||||
|
||||
:param other: expression to be compared
|
||||
:param escape: optional escape character, renders the ``ESCAPE``
|
||||
keyword, e.g.::
|
||||
|
||||
somecolumn.like("foo/%bar", escape="/")
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ColumnOperators.ilike`
|
||||
|
||||
"""
|
||||
return self.operate(like_op, other, escape=escape)
|
||||
|
||||
def ilike(self, other, escape=None):
|
||||
"""Implement the ``ilike`` operator.
|
||||
|
||||
In a column context, produces the clause ``a ILIKE other``.
|
||||
|
||||
E.g.::
|
||||
|
||||
select([sometable]).where(sometable.c.column.ilike("%foobar%"))
|
||||
|
||||
:param other: expression to be compared
|
||||
:param escape: optional escape character, renders the ``ESCAPE``
|
||||
keyword, e.g.::
|
||||
|
||||
somecolumn.ilike("foo/%bar", escape="/")
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ColumnOperators.like`
|
||||
|
||||
"""
|
||||
return self.operate(ilike_op, other, escape=escape)
|
||||
|
||||
def in_(self, other):
|
||||
"""Implement the ``in`` operator.
|
||||
|
||||
In a column context, produces the clause ``a IN other``.
|
||||
"other" may be a tuple/list of column expressions,
|
||||
or a :func:`~.expression.select` construct.
|
||||
|
||||
"""
|
||||
return self.operate(in_op, other)
|
||||
|
||||
def notin_(self, other):
|
||||
"""implement the ``NOT IN`` operator.
|
||||
|
||||
This is equivalent to using negation with
|
||||
:meth:`.ColumnOperators.in_`, i.e. ``~x.in_(y)``.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ColumnOperators.in_`
|
||||
|
||||
"""
|
||||
return self.operate(notin_op, other)
|
||||
|
||||
def notlike(self, other, escape=None):
|
||||
"""implement the ``NOT LIKE`` operator.
|
||||
|
||||
This is equivalent to using negation with
|
||||
:meth:`.ColumnOperators.like`, i.e. ``~x.like(y)``.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ColumnOperators.like`
|
||||
|
||||
"""
|
||||
return self.operate(notlike_op, other, escape=escape)
|
||||
|
||||
def notilike(self, other, escape=None):
|
||||
"""implement the ``NOT ILIKE`` operator.
|
||||
|
||||
This is equivalent to using negation with
|
||||
:meth:`.ColumnOperators.ilike`, i.e. ``~x.ilike(y)``.
|
||||
|
||||
.. versionadded:: 0.8
|
||||
|
||||
.. seealso::
|
||||
|
||||
:meth:`.ColumnOperators.ilike`
|
||||
|
||||
"""
|
||||
return self.operate(notilike_op, other, escape=escape)
|
||||
|
||||
def is_(self, other):
|
||||
"""Implement the ``IS`` operator.
|
||||
|
||||
Normally, ``IS`` is generated automatically when comparing to a
|
||||
value of ``None``, which resolves to ``NULL``. However, explicit
|
||||
usage of ``IS`` may be desirable if comparing to boolean values
|
||||
on certain platforms.
|
||||
|
||||
.. versionadded:: 0.7.9
|
||||
|
||||
.. seealso:: :meth:`.ColumnOperators.isnot`
|
||||
|
||||
"""
|
||||
return self.operate(is_, other)
|
||||
|
||||
def isnot(self, other):
|
||||
"""Implement the ``IS NOT`` operator.
|
||||
|
||||
Normally, ``IS NOT`` is generated automatically when comparing to a
|
||||
value of ``None``, which resolves to ``NULL``. However, explicit
|
||||
usage of ``IS NOT`` may be desirable if comparing to boolean values
|
||||
on certain platforms.
|
||||
|
||||
.. versionadded:: 0.7.9
|
||||
|
||||
.. seealso:: :meth:`.ColumnOperators.is_`
|
||||
|
||||
"""
|
||||
return self.operate(isnot, other)
|
||||
|
||||
def startswith(self, other, **kwargs):
|
||||
"""Implement the ``startwith`` operator.
|
||||
|
||||
In a column context, produces the clause ``LIKE '<other>%'``
|
||||
|
||||
"""
|
||||
return self.operate(startswith_op, other, **kwargs)
|
||||
|
||||
def endswith(self, other, **kwargs):
|
||||
"""Implement the 'endswith' operator.
|
||||
|
||||
In a column context, produces the clause ``LIKE '%<other>'``
|
||||
|
||||
"""
|
||||
return self.operate(endswith_op, other, **kwargs)
|
||||
|
||||
def contains(self, other, **kwargs):
|
||||
"""Implement the 'contains' operator.
|
||||
|
||||
In a column context, produces the clause ``LIKE '%<other>%'``
|
||||
|
||||
"""
|
||||
return self.operate(contains_op, other, **kwargs)
|
||||
|
||||
def match(self, other, **kwargs):
|
||||
"""Implements a database-specific 'match' operator.
|
||||
|
||||
:meth:`~.ColumnOperators.match` attempts to resolve to
|
||||
a MATCH-like function or operator provided by the backend.
|
||||
Examples include:
|
||||
|
||||
* Postgresql - renders ``x @@ to_tsquery(y)``
|
||||
* MySQL - renders ``MATCH (x) AGAINST (y IN BOOLEAN MODE)``
|
||||
* Oracle - renders ``CONTAINS(x, y)``
|
||||
* other backends may provide special implementations;
|
||||
some backends such as SQLite have no support.
|
||||
|
||||
"""
|
||||
return self.operate(match_op, other, **kwargs)
|
||||
|
||||
def desc(self):
|
||||
"""Produce a :func:`~.expression.desc` clause against the
|
||||
parent object."""
|
||||
return self.operate(desc_op)
|
||||
|
||||
def asc(self):
|
||||
"""Produce a :func:`~.expression.asc` clause against the
|
||||
parent object."""
|
||||
return self.operate(asc_op)
|
||||
|
||||
def nullsfirst(self):
|
||||
"""Produce a :func:`~.expression.nullsfirst` clause against the
|
||||
parent object."""
|
||||
return self.operate(nullsfirst_op)
|
||||
|
||||
def nullslast(self):
|
||||
"""Produce a :func:`~.expression.nullslast` clause against the
|
||||
parent object."""
|
||||
return self.operate(nullslast_op)
|
||||
|
||||
def collate(self, collation):
|
||||
"""Produce a :func:`~.expression.collate` clause against
|
||||
the parent object, given the collation string."""
|
||||
return self.operate(collate, collation)
|
||||
|
||||
def __radd__(self, other):
|
||||
"""Implement the ``+`` operator in reverse.
|
||||
|
||||
See :meth:`.ColumnOperators.__add__`.
|
||||
|
||||
"""
|
||||
return self.reverse_operate(add, other)
|
||||
|
||||
def __rsub__(self, other):
|
||||
"""Implement the ``-`` operator in reverse.
|
||||
|
||||
See :meth:`.ColumnOperators.__sub__`.
|
||||
|
||||
"""
|
||||
return self.reverse_operate(sub, other)
|
||||
|
||||
def __rmul__(self, other):
|
||||
"""Implement the ``*`` operator in reverse.
|
||||
|
||||
See :meth:`.ColumnOperators.__mul__`.
|
||||
|
||||
"""
|
||||
return self.reverse_operate(mul, other)
|
||||
|
||||
def __rdiv__(self, other):
|
||||
"""Implement the ``/`` operator in reverse.
|
||||
|
||||
See :meth:`.ColumnOperators.__div__`.
|
||||
|
||||
"""
|
||||
return self.reverse_operate(div, other)
|
||||
|
||||
def between(self, cleft, cright, symmetric=False):
|
||||
"""Produce a :func:`~.expression.between` clause against
|
||||
the parent object, given the lower and upper range.
|
||||
|
||||
"""
|
||||
return self.operate(between_op, cleft, cright, symmetric=symmetric)
|
||||
|
||||
def distinct(self):
|
||||
"""Produce a :func:`~.expression.distinct` clause against the
|
||||
parent object.
|
||||
|
||||
"""
|
||||
return self.operate(distinct_op)
|
||||
|
||||
def __add__(self, other):
|
||||
"""Implement the ``+`` operator.
|
||||
|
||||
In a column context, produces the clause ``a + b``
|
||||
if the parent object has non-string affinity.
|
||||
If the parent object has a string affinity,
|
||||
produces the concatenation operator, ``a || b`` -
|
||||
see :meth:`.ColumnOperators.concat`.
|
||||
|
||||
"""
|
||||
return self.operate(add, other)
|
||||
|
||||
def __sub__(self, other):
|
||||
"""Implement the ``-`` operator.
|
||||
|
||||
In a column context, produces the clause ``a - b``.
|
||||
|
||||
"""
|
||||
return self.operate(sub, other)
|
||||
|
||||
def __mul__(self, other):
|
||||
"""Implement the ``*`` operator.
|
||||
|
||||
In a column context, produces the clause ``a * b``.
|
||||
|
||||
"""
|
||||
return self.operate(mul, other)
|
||||
|
||||
def __div__(self, other):
|
||||
"""Implement the ``/`` operator.
|
||||
|
||||
In a column context, produces the clause ``a / b``.
|
||||
|
||||
"""
|
||||
return self.operate(div, other)
|
||||
|
||||
def __mod__(self, other):
|
||||
"""Implement the ``%`` operator.
|
||||
|
||||
In a column context, produces the clause ``a % b``.
|
||||
|
||||
"""
|
||||
return self.operate(mod, other)
|
||||
|
||||
def __truediv__(self, other):
|
||||
"""Implement the ``//`` operator.
|
||||
|
||||
In a column context, produces the clause ``a / b``.
|
||||
|
||||
"""
|
||||
return self.operate(truediv, other)
|
||||
|
||||
def __rtruediv__(self, other):
|
||||
"""Implement the ``//`` operator in reverse.
|
||||
|
||||
See :meth:`.ColumnOperators.__truediv__`.
|
||||
|
||||
"""
|
||||
return self.reverse_operate(truediv, other)
|
||||
|
||||
|
||||
def from_():
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def as_():
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def exists():
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def istrue(a):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def isfalse(a):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def is_(a, b):
|
||||
return a.is_(b)
|
||||
|
||||
|
||||
def isnot(a, b):
|
||||
return a.isnot(b)
|
||||
|
||||
|
||||
def collate(a, b):
|
||||
return a.collate(b)
|
||||
|
||||
|
||||
def op(a, opstring, b):
|
||||
return a.op(opstring)(b)
|
||||
|
||||
|
||||
def like_op(a, b, escape=None):
|
||||
return a.like(b, escape=escape)
|
||||
|
||||
|
||||
def notlike_op(a, b, escape=None):
|
||||
return a.notlike(b, escape=escape)
|
||||
|
||||
|
||||
def ilike_op(a, b, escape=None):
|
||||
return a.ilike(b, escape=escape)
|
||||
|
||||
|
||||
def notilike_op(a, b, escape=None):
|
||||
return a.notilike(b, escape=escape)
|
||||
|
||||
|
||||
def between_op(a, b, c, symmetric=False):
|
||||
return a.between(b, c, symmetric=symmetric)
|
||||
|
||||
|
||||
def notbetween_op(a, b, c, symmetric=False):
|
||||
return a.notbetween(b, c, symmetric=symmetric)
|
||||
|
||||
|
||||
def in_op(a, b):
|
||||
return a.in_(b)
|
||||
|
||||
|
||||
def notin_op(a, b):
|
||||
return a.notin_(b)
|
||||
|
||||
|
||||
def distinct_op(a):
|
||||
return a.distinct()
|
||||
|
||||
|
||||
def startswith_op(a, b, escape=None):
|
||||
return a.startswith(b, escape=escape)
|
||||
|
||||
|
||||
def notstartswith_op(a, b, escape=None):
|
||||
return ~a.startswith(b, escape=escape)
|
||||
|
||||
|
||||
def endswith_op(a, b, escape=None):
|
||||
return a.endswith(b, escape=escape)
|
||||
|
||||
|
||||
def notendswith_op(a, b, escape=None):
|
||||
return ~a.endswith(b, escape=escape)
|
||||
|
||||
|
||||
def contains_op(a, b, escape=None):
|
||||
return a.contains(b, escape=escape)
|
||||
|
||||
|
||||
def notcontains_op(a, b, escape=None):
|
||||
return ~a.contains(b, escape=escape)
|
||||
|
||||
|
||||
def match_op(a, b, **kw):
|
||||
return a.match(b, **kw)
|
||||
|
||||
|
||||
def comma_op(a, b):
|
||||
raise NotImplementedError()
|
||||
|
||||
|
||||
def concat_op(a, b):
|
||||
return a.concat(b)
|
||||
|
||||
|
||||
def desc_op(a):
|
||||
return a.desc()
|
||||
|
||||
|
||||
def asc_op(a):
|
||||
return a.asc()
|
||||
|
||||
|
||||
def nullsfirst_op(a):
|
||||
return a.nullsfirst()
|
||||
|
||||
|
||||
def nullslast_op(a):
|
||||
return a.nullslast()
|
||||
|
||||
|
||||
_commutative = set([eq, ne, add, mul])
|
||||
|
||||
_comparison = set([eq, ne, lt, gt, ge, le, between_op, like_op])
|
||||
|
||||
|
||||
def is_comparison(op):
|
||||
return op in _comparison or \
|
||||
isinstance(op, custom_op) and op.is_comparison
|
||||
|
||||
|
||||
def is_commutative(op):
|
||||
return op in _commutative
|
||||
|
||||
|
||||
def is_ordering_modifier(op):
|
||||
return op in (asc_op, desc_op,
|
||||
nullsfirst_op, nullslast_op)
|
||||
|
||||
_associative = _commutative.union([concat_op, and_, or_])
|
||||
|
||||
_natural_self_precedent = _associative.union([getitem])
|
||||
"""Operators where if we have (a op b) op c, we don't want to
|
||||
parenthesize (a op b).
|
||||
|
||||
"""
|
||||
|
||||
_asbool = util.symbol('_asbool', canonical=-10)
|
||||
_smallest = util.symbol('_smallest', canonical=-100)
|
||||
_largest = util.symbol('_largest', canonical=100)
|
||||
|
||||
_PRECEDENCE = {
|
||||
from_: 15,
|
||||
getitem: 15,
|
||||
mul: 8,
|
||||
truediv: 8,
|
||||
div: 8,
|
||||
mod: 8,
|
||||
neg: 8,
|
||||
add: 7,
|
||||
sub: 7,
|
||||
|
||||
concat_op: 6,
|
||||
match_op: 6,
|
||||
|
||||
ilike_op: 6,
|
||||
notilike_op: 6,
|
||||
like_op: 6,
|
||||
notlike_op: 6,
|
||||
in_op: 6,
|
||||
notin_op: 6,
|
||||
|
||||
is_: 6,
|
||||
isnot: 6,
|
||||
|
||||
eq: 5,
|
||||
ne: 5,
|
||||
gt: 5,
|
||||
lt: 5,
|
||||
ge: 5,
|
||||
le: 5,
|
||||
|
||||
between_op: 5,
|
||||
notbetween_op: 5,
|
||||
distinct_op: 5,
|
||||
inv: 5,
|
||||
istrue: 5,
|
||||
isfalse: 5,
|
||||
and_: 3,
|
||||
or_: 2,
|
||||
comma_op: -1,
|
||||
|
||||
desc_op: 3,
|
||||
asc_op: 3,
|
||||
collate: 4,
|
||||
|
||||
as_: -1,
|
||||
exists: 0,
|
||||
_asbool: -10,
|
||||
_smallest: _smallest,
|
||||
_largest: _largest
|
||||
}
|
||||
|
||||
|
||||
def is_precedent(operator, against):
|
||||
if operator is against and operator in _natural_self_precedent:
|
||||
return False
|
||||
else:
|
||||
return (_PRECEDENCE.get(operator,
|
||||
getattr(operator, 'precedence', _smallest)) <=
|
||||
_PRECEDENCE.get(against,
|
||||
getattr(against, 'precedence', _largest)))
|
||||
3444
lib/python3.5/site-packages/sqlalchemy/sql/schema.py
Normal file
3444
lib/python3.5/site-packages/sqlalchemy/sql/schema.py
Normal file
File diff suppressed because it is too large
Load diff
3152
lib/python3.5/site-packages/sqlalchemy/sql/selectable.py
Normal file
3152
lib/python3.5/site-packages/sqlalchemy/sql/selectable.py
Normal file
File diff suppressed because it is too large
Load diff
1701
lib/python3.5/site-packages/sqlalchemy/sql/sqltypes.py
Normal file
1701
lib/python3.5/site-packages/sqlalchemy/sql/sqltypes.py
Normal file
File diff suppressed because it is too large
Load diff
1071
lib/python3.5/site-packages/sqlalchemy/sql/type_api.py
Normal file
1071
lib/python3.5/site-packages/sqlalchemy/sql/type_api.py
Normal file
File diff suppressed because it is too large
Load diff
606
lib/python3.5/site-packages/sqlalchemy/sql/util.py
Normal file
606
lib/python3.5/site-packages/sqlalchemy/sql/util.py
Normal file
|
|
@ -0,0 +1,606 @@
|
|||
# sql/util.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""High level utilities which build upon other modules here.
|
||||
|
||||
"""
|
||||
|
||||
from .. import exc, util
|
||||
from .base import _from_objects, ColumnSet
|
||||
from . import operators, visitors
|
||||
from itertools import chain
|
||||
from collections import deque
|
||||
|
||||
from .elements import BindParameter, ColumnClause, ColumnElement, \
|
||||
Null, UnaryExpression, literal_column, Label
|
||||
from .selectable import ScalarSelect, Join, FromClause, FromGrouping
|
||||
from .schema import Column
|
||||
|
||||
join_condition = util.langhelpers.public_factory(
|
||||
Join._join_condition,
|
||||
".sql.util.join_condition")
|
||||
|
||||
# names that are still being imported from the outside
|
||||
from .annotation import _shallow_annotate, _deep_annotate, _deep_deannotate
|
||||
from .elements import _find_columns
|
||||
from .ddl import sort_tables
|
||||
|
||||
|
||||
def find_join_source(clauses, join_to):
|
||||
"""Given a list of FROM clauses and a selectable,
|
||||
return the first index and element from the list of
|
||||
clauses which can be joined against the selectable. returns
|
||||
None, None if no match is found.
|
||||
|
||||
e.g.::
|
||||
|
||||
clause1 = table1.join(table2)
|
||||
clause2 = table4.join(table5)
|
||||
|
||||
join_to = table2.join(table3)
|
||||
|
||||
find_join_source([clause1, clause2], join_to) == clause1
|
||||
|
||||
"""
|
||||
|
||||
selectables = list(_from_objects(join_to))
|
||||
for i, f in enumerate(clauses):
|
||||
for s in selectables:
|
||||
if f.is_derived_from(s):
|
||||
return i, f
|
||||
else:
|
||||
return None, None
|
||||
|
||||
|
||||
def visit_binary_product(fn, expr):
|
||||
"""Produce a traversal of the given expression, delivering
|
||||
column comparisons to the given function.
|
||||
|
||||
The function is of the form::
|
||||
|
||||
def my_fn(binary, left, right)
|
||||
|
||||
For each binary expression located which has a
|
||||
comparison operator, the product of "left" and
|
||||
"right" will be delivered to that function,
|
||||
in terms of that binary.
|
||||
|
||||
Hence an expression like::
|
||||
|
||||
and_(
|
||||
(a + b) == q + func.sum(e + f),
|
||||
j == r
|
||||
)
|
||||
|
||||
would have the traversal::
|
||||
|
||||
a <eq> q
|
||||
a <eq> e
|
||||
a <eq> f
|
||||
b <eq> q
|
||||
b <eq> e
|
||||
b <eq> f
|
||||
j <eq> r
|
||||
|
||||
That is, every combination of "left" and
|
||||
"right" that doesn't further contain
|
||||
a binary comparison is passed as pairs.
|
||||
|
||||
"""
|
||||
stack = []
|
||||
|
||||
def visit(element):
|
||||
if isinstance(element, ScalarSelect):
|
||||
# we don't want to dig into correlated subqueries,
|
||||
# those are just column elements by themselves
|
||||
yield element
|
||||
elif element.__visit_name__ == 'binary' and \
|
||||
operators.is_comparison(element.operator):
|
||||
stack.insert(0, element)
|
||||
for l in visit(element.left):
|
||||
for r in visit(element.right):
|
||||
fn(stack[0], l, r)
|
||||
stack.pop(0)
|
||||
for elem in element.get_children():
|
||||
visit(elem)
|
||||
else:
|
||||
if isinstance(element, ColumnClause):
|
||||
yield element
|
||||
for elem in element.get_children():
|
||||
for e in visit(elem):
|
||||
yield e
|
||||
list(visit(expr))
|
||||
|
||||
|
||||
def find_tables(clause, check_columns=False,
|
||||
include_aliases=False, include_joins=False,
|
||||
include_selects=False, include_crud=False):
|
||||
"""locate Table objects within the given expression."""
|
||||
|
||||
tables = []
|
||||
_visitors = {}
|
||||
|
||||
if include_selects:
|
||||
_visitors['select'] = _visitors['compound_select'] = tables.append
|
||||
|
||||
if include_joins:
|
||||
_visitors['join'] = tables.append
|
||||
|
||||
if include_aliases:
|
||||
_visitors['alias'] = tables.append
|
||||
|
||||
if include_crud:
|
||||
_visitors['insert'] = _visitors['update'] = \
|
||||
_visitors['delete'] = lambda ent: tables.append(ent.table)
|
||||
|
||||
if check_columns:
|
||||
def visit_column(column):
|
||||
tables.append(column.table)
|
||||
_visitors['column'] = visit_column
|
||||
|
||||
_visitors['table'] = tables.append
|
||||
|
||||
visitors.traverse(clause, {'column_collections': False}, _visitors)
|
||||
return tables
|
||||
|
||||
|
||||
def unwrap_order_by(clause):
|
||||
"""Break up an 'order by' expression into individual column-expressions,
|
||||
without DESC/ASC/NULLS FIRST/NULLS LAST"""
|
||||
|
||||
cols = util.column_set()
|
||||
stack = deque([clause])
|
||||
while stack:
|
||||
t = stack.popleft()
|
||||
if isinstance(t, ColumnElement) and \
|
||||
(
|
||||
not isinstance(t, UnaryExpression) or
|
||||
not operators.is_ordering_modifier(t.modifier)
|
||||
):
|
||||
cols.add(t)
|
||||
else:
|
||||
for c in t.get_children():
|
||||
stack.append(c)
|
||||
return cols
|
||||
|
||||
|
||||
def clause_is_present(clause, search):
|
||||
"""Given a target clause and a second to search within, return True
|
||||
if the target is plainly present in the search without any
|
||||
subqueries or aliases involved.
|
||||
|
||||
Basically descends through Joins.
|
||||
|
||||
"""
|
||||
|
||||
for elem in surface_selectables(search):
|
||||
if clause == elem: # use == here so that Annotated's compare
|
||||
return True
|
||||
else:
|
||||
return False
|
||||
|
||||
|
||||
def surface_selectables(clause):
|
||||
stack = [clause]
|
||||
while stack:
|
||||
elem = stack.pop()
|
||||
yield elem
|
||||
if isinstance(elem, Join):
|
||||
stack.extend((elem.left, elem.right))
|
||||
elif isinstance(elem, FromGrouping):
|
||||
stack.append(elem.element)
|
||||
|
||||
|
||||
def selectables_overlap(left, right):
|
||||
"""Return True if left/right have some overlapping selectable"""
|
||||
|
||||
return bool(
|
||||
set(surface_selectables(left)).intersection(
|
||||
surface_selectables(right)
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
def bind_values(clause):
|
||||
"""Return an ordered list of "bound" values in the given clause.
|
||||
|
||||
E.g.::
|
||||
|
||||
>>> expr = and_(
|
||||
... table.c.foo==5, table.c.foo==7
|
||||
... )
|
||||
>>> bind_values(expr)
|
||||
[5, 7]
|
||||
"""
|
||||
|
||||
v = []
|
||||
|
||||
def visit_bindparam(bind):
|
||||
v.append(bind.effective_value)
|
||||
|
||||
visitors.traverse(clause, {}, {'bindparam': visit_bindparam})
|
||||
return v
|
||||
|
||||
|
||||
def _quote_ddl_expr(element):
|
||||
if isinstance(element, util.string_types):
|
||||
element = element.replace("'", "''")
|
||||
return "'%s'" % element
|
||||
else:
|
||||
return repr(element)
|
||||
|
||||
|
||||
class _repr_params(object):
|
||||
"""A string view of bound parameters, truncating
|
||||
display to the given number of 'multi' parameter sets.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, params, batches):
|
||||
self.params = params
|
||||
self.batches = batches
|
||||
|
||||
def __repr__(self):
|
||||
if isinstance(self.params, (list, tuple)) and \
|
||||
len(self.params) > self.batches and \
|
||||
isinstance(self.params[0], (list, dict, tuple)):
|
||||
msg = " ... displaying %i of %i total bound parameter sets ... "
|
||||
return ' '.join((
|
||||
repr(self.params[:self.batches - 2])[0:-1],
|
||||
msg % (self.batches, len(self.params)),
|
||||
repr(self.params[-2:])[1:]
|
||||
))
|
||||
else:
|
||||
return repr(self.params)
|
||||
|
||||
|
||||
def adapt_criterion_to_null(crit, nulls):
|
||||
"""given criterion containing bind params, convert selected elements
|
||||
to IS NULL.
|
||||
|
||||
"""
|
||||
|
||||
def visit_binary(binary):
|
||||
if isinstance(binary.left, BindParameter) \
|
||||
and binary.left._identifying_key in nulls:
|
||||
# reverse order if the NULL is on the left side
|
||||
binary.left = binary.right
|
||||
binary.right = Null()
|
||||
binary.operator = operators.is_
|
||||
binary.negate = operators.isnot
|
||||
elif isinstance(binary.right, BindParameter) \
|
||||
and binary.right._identifying_key in nulls:
|
||||
binary.right = Null()
|
||||
binary.operator = operators.is_
|
||||
binary.negate = operators.isnot
|
||||
|
||||
return visitors.cloned_traverse(crit, {}, {'binary': visit_binary})
|
||||
|
||||
|
||||
def splice_joins(left, right, stop_on=None):
|
||||
if left is None:
|
||||
return right
|
||||
|
||||
stack = [(right, None)]
|
||||
|
||||
adapter = ClauseAdapter(left)
|
||||
ret = None
|
||||
while stack:
|
||||
(right, prevright) = stack.pop()
|
||||
if isinstance(right, Join) and right is not stop_on:
|
||||
right = right._clone()
|
||||
right._reset_exported()
|
||||
right.onclause = adapter.traverse(right.onclause)
|
||||
stack.append((right.left, right))
|
||||
else:
|
||||
right = adapter.traverse(right)
|
||||
if prevright is not None:
|
||||
prevright.left = right
|
||||
if ret is None:
|
||||
ret = right
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def reduce_columns(columns, *clauses, **kw):
|
||||
"""given a list of columns, return a 'reduced' set based on natural
|
||||
equivalents.
|
||||
|
||||
the set is reduced to the smallest list of columns which have no natural
|
||||
equivalent present in the list. A "natural equivalent" means that two
|
||||
columns will ultimately represent the same value because they are related
|
||||
by a foreign key.
|
||||
|
||||
\*clauses is an optional list of join clauses which will be traversed
|
||||
to further identify columns that are "equivalent".
|
||||
|
||||
\**kw may specify 'ignore_nonexistent_tables' to ignore foreign keys
|
||||
whose tables are not yet configured, or columns that aren't yet present.
|
||||
|
||||
This function is primarily used to determine the most minimal "primary
|
||||
key" from a selectable, by reducing the set of primary key columns present
|
||||
in the selectable to just those that are not repeated.
|
||||
|
||||
"""
|
||||
ignore_nonexistent_tables = kw.pop('ignore_nonexistent_tables', False)
|
||||
only_synonyms = kw.pop('only_synonyms', False)
|
||||
|
||||
columns = util.ordered_column_set(columns)
|
||||
|
||||
omit = util.column_set()
|
||||
for col in columns:
|
||||
for fk in chain(*[c.foreign_keys for c in col.proxy_set]):
|
||||
for c in columns:
|
||||
if c is col:
|
||||
continue
|
||||
try:
|
||||
fk_col = fk.column
|
||||
except exc.NoReferencedColumnError:
|
||||
# TODO: add specific coverage here
|
||||
# to test/sql/test_selectable ReduceTest
|
||||
if ignore_nonexistent_tables:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
except exc.NoReferencedTableError:
|
||||
# TODO: add specific coverage here
|
||||
# to test/sql/test_selectable ReduceTest
|
||||
if ignore_nonexistent_tables:
|
||||
continue
|
||||
else:
|
||||
raise
|
||||
if fk_col.shares_lineage(c) and \
|
||||
(not only_synonyms or
|
||||
c.name == col.name):
|
||||
omit.add(col)
|
||||
break
|
||||
|
||||
if clauses:
|
||||
def visit_binary(binary):
|
||||
if binary.operator == operators.eq:
|
||||
cols = util.column_set(
|
||||
chain(*[c.proxy_set for c in columns.difference(omit)]))
|
||||
if binary.left in cols and binary.right in cols:
|
||||
for c in reversed(columns):
|
||||
if c.shares_lineage(binary.right) and \
|
||||
(not only_synonyms or
|
||||
c.name == binary.left.name):
|
||||
omit.add(c)
|
||||
break
|
||||
for clause in clauses:
|
||||
if clause is not None:
|
||||
visitors.traverse(clause, {}, {'binary': visit_binary})
|
||||
|
||||
return ColumnSet(columns.difference(omit))
|
||||
|
||||
|
||||
def criterion_as_pairs(expression, consider_as_foreign_keys=None,
|
||||
consider_as_referenced_keys=None, any_operator=False):
|
||||
"""traverse an expression and locate binary criterion pairs."""
|
||||
|
||||
if consider_as_foreign_keys and consider_as_referenced_keys:
|
||||
raise exc.ArgumentError("Can only specify one of "
|
||||
"'consider_as_foreign_keys' or "
|
||||
"'consider_as_referenced_keys'")
|
||||
|
||||
def col_is(a, b):
|
||||
# return a is b
|
||||
return a.compare(b)
|
||||
|
||||
def visit_binary(binary):
|
||||
if not any_operator and binary.operator is not operators.eq:
|
||||
return
|
||||
if not isinstance(binary.left, ColumnElement) or \
|
||||
not isinstance(binary.right, ColumnElement):
|
||||
return
|
||||
|
||||
if consider_as_foreign_keys:
|
||||
if binary.left in consider_as_foreign_keys and \
|
||||
(col_is(binary.right, binary.left) or
|
||||
binary.right not in consider_as_foreign_keys):
|
||||
pairs.append((binary.right, binary.left))
|
||||
elif binary.right in consider_as_foreign_keys and \
|
||||
(col_is(binary.left, binary.right) or
|
||||
binary.left not in consider_as_foreign_keys):
|
||||
pairs.append((binary.left, binary.right))
|
||||
elif consider_as_referenced_keys:
|
||||
if binary.left in consider_as_referenced_keys and \
|
||||
(col_is(binary.right, binary.left) or
|
||||
binary.right not in consider_as_referenced_keys):
|
||||
pairs.append((binary.left, binary.right))
|
||||
elif binary.right in consider_as_referenced_keys and \
|
||||
(col_is(binary.left, binary.right) or
|
||||
binary.left not in consider_as_referenced_keys):
|
||||
pairs.append((binary.right, binary.left))
|
||||
else:
|
||||
if isinstance(binary.left, Column) and \
|
||||
isinstance(binary.right, Column):
|
||||
if binary.left.references(binary.right):
|
||||
pairs.append((binary.right, binary.left))
|
||||
elif binary.right.references(binary.left):
|
||||
pairs.append((binary.left, binary.right))
|
||||
pairs = []
|
||||
visitors.traverse(expression, {}, {'binary': visit_binary})
|
||||
return pairs
|
||||
|
||||
|
||||
class AliasedRow(object):
|
||||
"""Wrap a RowProxy with a translation map.
|
||||
|
||||
This object allows a set of keys to be translated
|
||||
to those present in a RowProxy.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, row, map):
|
||||
# AliasedRow objects don't nest, so un-nest
|
||||
# if another AliasedRow was passed
|
||||
if isinstance(row, AliasedRow):
|
||||
self.row = row.row
|
||||
else:
|
||||
self.row = row
|
||||
self.map = map
|
||||
|
||||
def __contains__(self, key):
|
||||
return self.map[key] in self.row
|
||||
|
||||
def has_key(self, key):
|
||||
return key in self
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.row[self.map[key]]
|
||||
|
||||
def keys(self):
|
||||
return self.row.keys()
|
||||
|
||||
|
||||
class ClauseAdapter(visitors.ReplacingCloningVisitor):
|
||||
"""Clones and modifies clauses based on column correspondence.
|
||||
|
||||
E.g.::
|
||||
|
||||
table1 = Table('sometable', metadata,
|
||||
Column('col1', Integer),
|
||||
Column('col2', Integer)
|
||||
)
|
||||
table2 = Table('someothertable', metadata,
|
||||
Column('col1', Integer),
|
||||
Column('col2', Integer)
|
||||
)
|
||||
|
||||
condition = table1.c.col1 == table2.c.col1
|
||||
|
||||
make an alias of table1::
|
||||
|
||||
s = table1.alias('foo')
|
||||
|
||||
calling ``ClauseAdapter(s).traverse(condition)`` converts
|
||||
condition to read::
|
||||
|
||||
s.c.col1 == table2.c.col1
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, selectable, equivalents=None,
|
||||
include=None, exclude=None,
|
||||
include_fn=None, exclude_fn=None,
|
||||
adapt_on_names=False):
|
||||
self.__traverse_options__ = {'stop_on': [selectable]}
|
||||
self.selectable = selectable
|
||||
if include:
|
||||
assert not include_fn
|
||||
self.include_fn = lambda e: e in include
|
||||
else:
|
||||
self.include_fn = include_fn
|
||||
if exclude:
|
||||
assert not exclude_fn
|
||||
self.exclude_fn = lambda e: e in exclude
|
||||
else:
|
||||
self.exclude_fn = exclude_fn
|
||||
self.equivalents = util.column_dict(equivalents or {})
|
||||
self.adapt_on_names = adapt_on_names
|
||||
|
||||
def _corresponding_column(self, col, require_embedded,
|
||||
_seen=util.EMPTY_SET):
|
||||
newcol = self.selectable.corresponding_column(
|
||||
col,
|
||||
require_embedded=require_embedded)
|
||||
if newcol is None and col in self.equivalents and col not in _seen:
|
||||
for equiv in self.equivalents[col]:
|
||||
newcol = self._corresponding_column(
|
||||
equiv, require_embedded=require_embedded,
|
||||
_seen=_seen.union([col]))
|
||||
if newcol is not None:
|
||||
return newcol
|
||||
if self.adapt_on_names and newcol is None:
|
||||
newcol = self.selectable.c.get(col.name)
|
||||
return newcol
|
||||
|
||||
magic_flag = False
|
||||
|
||||
def replace(self, col):
|
||||
if not self.magic_flag and isinstance(col, FromClause) and \
|
||||
self.selectable.is_derived_from(col):
|
||||
return self.selectable
|
||||
elif not isinstance(col, ColumnElement):
|
||||
return None
|
||||
elif self.include_fn and not self.include_fn(col):
|
||||
return None
|
||||
elif self.exclude_fn and self.exclude_fn(col):
|
||||
return None
|
||||
else:
|
||||
return self._corresponding_column(col, True)
|
||||
|
||||
|
||||
class ColumnAdapter(ClauseAdapter):
|
||||
"""Extends ClauseAdapter with extra utility functions.
|
||||
|
||||
Provides the ability to "wrap" this ClauseAdapter
|
||||
around another, a columns dictionary which returns
|
||||
adapted elements given an original, and an
|
||||
adapted_row() factory.
|
||||
|
||||
"""
|
||||
|
||||
def __init__(self, selectable, equivalents=None,
|
||||
chain_to=None, include=None,
|
||||
exclude=None, adapt_required=False):
|
||||
ClauseAdapter.__init__(self, selectable, equivalents,
|
||||
include, exclude)
|
||||
if chain_to:
|
||||
self.chain(chain_to)
|
||||
self.columns = util.populate_column_dict(self._locate_col)
|
||||
self.adapt_required = adapt_required
|
||||
|
||||
def wrap(self, adapter):
|
||||
ac = self.__class__.__new__(self.__class__)
|
||||
ac.__dict__ = self.__dict__.copy()
|
||||
ac._locate_col = ac._wrap(ac._locate_col, adapter._locate_col)
|
||||
ac.adapt_clause = ac._wrap(ac.adapt_clause, adapter.adapt_clause)
|
||||
ac.adapt_list = ac._wrap(ac.adapt_list, adapter.adapt_list)
|
||||
ac.columns = util.populate_column_dict(ac._locate_col)
|
||||
return ac
|
||||
|
||||
adapt_clause = ClauseAdapter.traverse
|
||||
adapt_list = ClauseAdapter.copy_and_process
|
||||
|
||||
def _wrap(self, local, wrapped):
|
||||
def locate(col):
|
||||
col = local(col)
|
||||
return wrapped(col)
|
||||
return locate
|
||||
|
||||
def _locate_col(self, col):
|
||||
c = self._corresponding_column(col, True)
|
||||
if c is None:
|
||||
c = self.adapt_clause(col)
|
||||
|
||||
# anonymize labels in case they have a hardcoded name
|
||||
if isinstance(c, Label):
|
||||
c = c.label(None)
|
||||
|
||||
# adapt_required used by eager loading to indicate that
|
||||
# we don't trust a result row column that is not translated.
|
||||
# this is to prevent a column from being interpreted as that
|
||||
# of the child row in a self-referential scenario, see
|
||||
# inheritance/test_basic.py->EagerTargetingTest.test_adapt_stringency
|
||||
if self.adapt_required and c is col:
|
||||
return None
|
||||
|
||||
return c
|
||||
|
||||
def adapted_row(self, row):
|
||||
return AliasedRow(row, self.columns)
|
||||
|
||||
def __getstate__(self):
|
||||
d = self.__dict__.copy()
|
||||
del d['columns']
|
||||
return d
|
||||
|
||||
def __setstate__(self, state):
|
||||
self.__dict__.update(state)
|
||||
self.columns = util.PopulateDict(self._locate_col)
|
||||
315
lib/python3.5/site-packages/sqlalchemy/sql/visitors.py
Normal file
315
lib/python3.5/site-packages/sqlalchemy/sql/visitors.py
Normal file
|
|
@ -0,0 +1,315 @@
|
|||
# sql/visitors.py
|
||||
# Copyright (C) 2005-2014 the SQLAlchemy authors and contributors
|
||||
# <see AUTHORS file>
|
||||
#
|
||||
# This module is part of SQLAlchemy and is released under
|
||||
# the MIT License: http://www.opensource.org/licenses/mit-license.php
|
||||
|
||||
"""Visitor/traversal interface and library functions.
|
||||
|
||||
SQLAlchemy schema and expression constructs rely on a Python-centric
|
||||
version of the classic "visitor" pattern as the primary way in which
|
||||
they apply functionality. The most common use of this pattern
|
||||
is statement compilation, where individual expression classes match
|
||||
up to rendering methods that produce a string result. Beyond this,
|
||||
the visitor system is also used to inspect expressions for various
|
||||
information and patterns, as well as for usage in
|
||||
some kinds of expression transformation. Other kinds of transformation
|
||||
use a non-visitor traversal system.
|
||||
|
||||
For many examples of how the visit system is used, see the
|
||||
sqlalchemy.sql.util and the sqlalchemy.sql.compiler modules.
|
||||
For an introduction to clause adaption, see
|
||||
http://techspot.zzzeek.org/2008/01/23/expression-transformations/
|
||||
|
||||
"""
|
||||
|
||||
from collections import deque
|
||||
from .. import util
|
||||
import operator
|
||||
from .. import exc
|
||||
|
||||
__all__ = ['VisitableType', 'Visitable', 'ClauseVisitor',
|
||||
'CloningVisitor', 'ReplacingCloningVisitor', 'iterate',
|
||||
'iterate_depthfirst', 'traverse_using', 'traverse',
|
||||
'traverse_depthfirst',
|
||||
'cloned_traverse', 'replacement_traverse']
|
||||
|
||||
|
||||
class VisitableType(type):
|
||||
"""Metaclass which assigns a `_compiler_dispatch` method to classes
|
||||
having a `__visit_name__` attribute.
|
||||
|
||||
The _compiler_dispatch attribute becomes an instance method which
|
||||
looks approximately like the following::
|
||||
|
||||
def _compiler_dispatch (self, visitor, **kw):
|
||||
'''Look for an attribute named "visit_" + self.__visit_name__
|
||||
on the visitor, and call it with the same kw params.'''
|
||||
visit_attr = 'visit_%s' % self.__visit_name__
|
||||
return getattr(visitor, visit_attr)(self, **kw)
|
||||
|
||||
Classes having no __visit_name__ attribute will remain unaffected.
|
||||
"""
|
||||
def __init__(cls, clsname, bases, clsdict):
|
||||
if clsname != 'Visitable' and \
|
||||
hasattr(cls, '__visit_name__'):
|
||||
_generate_dispatch(cls)
|
||||
|
||||
super(VisitableType, cls).__init__(clsname, bases, clsdict)
|
||||
|
||||
|
||||
def _generate_dispatch(cls):
|
||||
"""Return an optimized visit dispatch function for the cls
|
||||
for use by the compiler.
|
||||
"""
|
||||
if '__visit_name__' in cls.__dict__:
|
||||
visit_name = cls.__visit_name__
|
||||
if isinstance(visit_name, str):
|
||||
# There is an optimization opportunity here because the
|
||||
# the string name of the class's __visit_name__ is known at
|
||||
# this early stage (import time) so it can be pre-constructed.
|
||||
getter = operator.attrgetter("visit_%s" % visit_name)
|
||||
|
||||
def _compiler_dispatch(self, visitor, **kw):
|
||||
try:
|
||||
meth = getter(visitor)
|
||||
except AttributeError:
|
||||
raise exc.UnsupportedCompilationError(visitor, cls)
|
||||
else:
|
||||
return meth(self, **kw)
|
||||
else:
|
||||
# The optimization opportunity is lost for this case because the
|
||||
# __visit_name__ is not yet a string. As a result, the visit
|
||||
# string has to be recalculated with each compilation.
|
||||
def _compiler_dispatch(self, visitor, **kw):
|
||||
visit_attr = 'visit_%s' % self.__visit_name__
|
||||
try:
|
||||
meth = getattr(visitor, visit_attr)
|
||||
except AttributeError:
|
||||
raise exc.UnsupportedCompilationError(visitor, cls)
|
||||
else:
|
||||
return meth(self, **kw)
|
||||
|
||||
_compiler_dispatch.__doc__ = \
|
||||
"""Look for an attribute named "visit_" + self.__visit_name__
|
||||
on the visitor, and call it with the same kw params.
|
||||
"""
|
||||
cls._compiler_dispatch = _compiler_dispatch
|
||||
|
||||
|
||||
class Visitable(util.with_metaclass(VisitableType, object)):
|
||||
"""Base class for visitable objects, applies the
|
||||
``VisitableType`` metaclass.
|
||||
|
||||
"""
|
||||
|
||||
|
||||
class ClauseVisitor(object):
|
||||
"""Base class for visitor objects which can traverse using
|
||||
the traverse() function.
|
||||
|
||||
"""
|
||||
|
||||
__traverse_options__ = {}
|
||||
|
||||
def traverse_single(self, obj, **kw):
|
||||
for v in self._visitor_iterator:
|
||||
meth = getattr(v, "visit_%s" % obj.__visit_name__, None)
|
||||
if meth:
|
||||
return meth(obj, **kw)
|
||||
|
||||
def iterate(self, obj):
|
||||
"""traverse the given expression structure, returning an iterator
|
||||
of all elements.
|
||||
|
||||
"""
|
||||
return iterate(obj, self.__traverse_options__)
|
||||
|
||||
def traverse(self, obj):
|
||||
"""traverse and visit the given expression structure."""
|
||||
|
||||
return traverse(obj, self.__traverse_options__, self._visitor_dict)
|
||||
|
||||
@util.memoized_property
|
||||
def _visitor_dict(self):
|
||||
visitors = {}
|
||||
|
||||
for name in dir(self):
|
||||
if name.startswith('visit_'):
|
||||
visitors[name[6:]] = getattr(self, name)
|
||||
return visitors
|
||||
|
||||
@property
|
||||
def _visitor_iterator(self):
|
||||
"""iterate through this visitor and each 'chained' visitor."""
|
||||
|
||||
v = self
|
||||
while v:
|
||||
yield v
|
||||
v = getattr(v, '_next', None)
|
||||
|
||||
def chain(self, visitor):
|
||||
"""'chain' an additional ClauseVisitor onto this ClauseVisitor.
|
||||
|
||||
the chained visitor will receive all visit events after this one.
|
||||
|
||||
"""
|
||||
tail = list(self._visitor_iterator)[-1]
|
||||
tail._next = visitor
|
||||
return self
|
||||
|
||||
|
||||
class CloningVisitor(ClauseVisitor):
|
||||
"""Base class for visitor objects which can traverse using
|
||||
the cloned_traverse() function.
|
||||
|
||||
"""
|
||||
|
||||
def copy_and_process(self, list_):
|
||||
"""Apply cloned traversal to the given list of elements, and return
|
||||
the new list.
|
||||
|
||||
"""
|
||||
return [self.traverse(x) for x in list_]
|
||||
|
||||
def traverse(self, obj):
|
||||
"""traverse and visit the given expression structure."""
|
||||
|
||||
return cloned_traverse(
|
||||
obj, self.__traverse_options__, self._visitor_dict)
|
||||
|
||||
|
||||
class ReplacingCloningVisitor(CloningVisitor):
|
||||
"""Base class for visitor objects which can traverse using
|
||||
the replacement_traverse() function.
|
||||
|
||||
"""
|
||||
|
||||
def replace(self, elem):
|
||||
"""receive pre-copied elements during a cloning traversal.
|
||||
|
||||
If the method returns a new element, the element is used
|
||||
instead of creating a simple copy of the element. Traversal
|
||||
will halt on the newly returned element if it is re-encountered.
|
||||
"""
|
||||
return None
|
||||
|
||||
def traverse(self, obj):
|
||||
"""traverse and visit the given expression structure."""
|
||||
|
||||
def replace(elem):
|
||||
for v in self._visitor_iterator:
|
||||
e = v.replace(elem)
|
||||
if e is not None:
|
||||
return e
|
||||
return replacement_traverse(obj, self.__traverse_options__, replace)
|
||||
|
||||
|
||||
def iterate(obj, opts):
|
||||
"""traverse the given expression structure, returning an iterator.
|
||||
|
||||
traversal is configured to be breadth-first.
|
||||
|
||||
"""
|
||||
stack = deque([obj])
|
||||
while stack:
|
||||
t = stack.popleft()
|
||||
yield t
|
||||
for c in t.get_children(**opts):
|
||||
stack.append(c)
|
||||
|
||||
|
||||
def iterate_depthfirst(obj, opts):
|
||||
"""traverse the given expression structure, returning an iterator.
|
||||
|
||||
traversal is configured to be depth-first.
|
||||
|
||||
"""
|
||||
stack = deque([obj])
|
||||
traversal = deque()
|
||||
while stack:
|
||||
t = stack.pop()
|
||||
traversal.appendleft(t)
|
||||
for c in t.get_children(**opts):
|
||||
stack.append(c)
|
||||
return iter(traversal)
|
||||
|
||||
|
||||
def traverse_using(iterator, obj, visitors):
|
||||
"""visit the given expression structure using the given iterator of
|
||||
objects.
|
||||
|
||||
"""
|
||||
for target in iterator:
|
||||
meth = visitors.get(target.__visit_name__, None)
|
||||
if meth:
|
||||
meth(target)
|
||||
return obj
|
||||
|
||||
|
||||
def traverse(obj, opts, visitors):
|
||||
"""traverse and visit the given expression structure using the default
|
||||
iterator.
|
||||
|
||||
"""
|
||||
return traverse_using(iterate(obj, opts), obj, visitors)
|
||||
|
||||
|
||||
def traverse_depthfirst(obj, opts, visitors):
|
||||
"""traverse and visit the given expression structure using the
|
||||
depth-first iterator.
|
||||
|
||||
"""
|
||||
return traverse_using(iterate_depthfirst(obj, opts), obj, visitors)
|
||||
|
||||
|
||||
def cloned_traverse(obj, opts, visitors):
|
||||
"""clone the given expression structure, allowing
|
||||
modifications by visitors."""
|
||||
|
||||
cloned = {}
|
||||
stop_on = set(opts.get('stop_on', []))
|
||||
|
||||
def clone(elem):
|
||||
if elem in stop_on:
|
||||
return elem
|
||||
else:
|
||||
if id(elem) not in cloned:
|
||||
cloned[id(elem)] = newelem = elem._clone()
|
||||
newelem._copy_internals(clone=clone)
|
||||
meth = visitors.get(newelem.__visit_name__, None)
|
||||
if meth:
|
||||
meth(newelem)
|
||||
return cloned[id(elem)]
|
||||
|
||||
if obj is not None:
|
||||
obj = clone(obj)
|
||||
return obj
|
||||
|
||||
|
||||
def replacement_traverse(obj, opts, replace):
|
||||
"""clone the given expression structure, allowing element
|
||||
replacement by a given replacement function."""
|
||||
|
||||
cloned = {}
|
||||
stop_on = set([id(x) for x in opts.get('stop_on', [])])
|
||||
|
||||
def clone(elem, **kw):
|
||||
if id(elem) in stop_on or \
|
||||
'no_replacement_traverse' in elem._annotations:
|
||||
return elem
|
||||
else:
|
||||
newelem = replace(elem)
|
||||
if newelem is not None:
|
||||
stop_on.add(id(newelem))
|
||||
return newelem
|
||||
else:
|
||||
if elem not in cloned:
|
||||
cloned[elem] = newelem = elem._clone()
|
||||
newelem._copy_internals(clone=clone, **kw)
|
||||
return cloned[elem]
|
||||
|
||||
if obj is not None:
|
||||
obj = clone(obj, **opts)
|
||||
return obj
|
||||
Loading…
Add table
Add a link
Reference in a new issue