# sql/schema.py
# Copyright (C) 2005-2018 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 schema module provides the building blocks for database metadata.
Each element within this module describes a database entity which can be
created and dropped, or is otherwise part of such an entity. Examples include
tables, columns, sequences, and indexes.
All entities are subclasses of :class:`~sqlalchemy.schema.SchemaItem`, and as
defined in this module they are intended to be agnostic of any vendor-specific
constructs.
A collection of entities are grouped into a unit called
:class:`~sqlalchemy.schema.MetaData`. MetaData serves as a logical grouping of
schema elements, and can also be associated with an actual database connection
such that operations involving the contained elements can contact the database
as needed.
Two of the elements here also build upon their "syntactic" counterparts, which
are defined in :class:`~sqlalchemy.sql.expression.`, specifically
:class:`~sqlalchemy.schema.Table` and :class:`~sqlalchemy.schema.Column`.
Since these objects are part of the SQL expression language, they are usable
as components in SQL expressions.
"""
from __future__ import absolute_import
from .. import exc, util, event, inspection
from .base import SchemaEventTarget, DialectKWArgs
import operator
from . import visitors
from . import type_api
from .base import _bind_or_error, ColumnCollection
from .elements import ClauseElement, ColumnClause, \
_as_truncated, TextClause, _literal_as_text,\
ColumnElement, quoted_name
from .selectable import TableClause
import collections
import sqlalchemy
from . import ddl
RETAIN_SCHEMA = util.symbol('retain_schema')
BLANK_SCHEMA = util.symbol(
'blank_schema',
"""Symbol indicating that a :class:`.Table` or :class:`.Sequence`
should have 'None' for its schema, even if the parent
:class:`.MetaData` has specified a schema.
.. versionadded:: 1.0.14
"""
)
def _get_table_key(name, schema):
if schema is None:
return name
else:
return schema + "." + name
# this should really be in sql/util.py but we'd have to
# break an import cycle
def _copy_expression(expression, source_table, target_table):
def replace(col):
if isinstance(col, Column) and \
col.table is source_table and col.key in source_table.c:
return target_table.c[col.key]
else:
return None
return visitors.replacement_traverse(expression, {}, replace)
@inspection._self_inspects
class SchemaItem(SchemaEventTarget, visitors.Visitable):
"""Base class for items that define a database schema."""
__visit_name__ = 'schema_item'
def _init_items(self, *args):
"""Initialize the list of child items for this SchemaItem."""
for item in args:
if item is not None:
item._set_parent_with_dispatch(self)
def get_children(self, **kwargs):
"""used to allow SchemaVisitor access"""
return []
def __repr__(self):
return util.generic_repr(self, omit_kwarg=['info'])
@property
@util.deprecated('0.9', 'Use ``<obj>.name.quote``')
def quote(self):
"""Return the value of the ``quote`` flag passed
to this schema object, for those schema items which
have a ``name`` field.
"""
return self.name.quote
@util.memoized_property
def info(self):
"""Info dictionary associated with the object, allowing user-defined
data to be associated with this :class:`.SchemaItem`.
The dictionary is automatically generated when first accessed.
It can also be specified in the constructor of some objects,
such as :class:`.Table` and :class:`.Column`.
"""
return {}
def _schema_item_copy(self, schema_item):
if 'info' in self.__dict__:
schema_item.info = self.info.copy()
schema_item.dispatch._update(self.dispatch)
return schema_item
def _translate_schema(self, effective_schema, map_):
return map_.get(effective_schema, effective_schema)
class Table(DialectKWArgs, SchemaItem, TableClause):
r"""Represent a table in a database.
e.g.::
mytable = Table("mytable", metadata,
Column('mytable_id', Integer, primary_key=True),
Column('value', String(50))
)
The :class:`.Table` object constructs a unique instance of itself based
on its name and optional schema name within the given
:class:`.MetaData` object. Calling the :class:`.Table`
constructor with the same name and same :class:`.MetaData` argument
a second time will return the *same* :class:`.Table` object - in this way
the :class:`.Table` constructor acts as a registry function.
.. seealso::
:ref:`metadata_describing` - Introduction to database metadata
Constructor arguments are as follows:
:param name: The name of this table as represented in the database.
The table name, along with the value of the ``schema`` parameter,
forms a key which uniquely identifies this :class:`.Table` within
the owning :class:`.MetaData` collection.
Additional calls to :class:`.Table` with the same name, metadata,
and schema name will return the same :class:`.Table` object.
Names which contain no upper case characters
will be treated as case insensitive names, and will not be quoted
unless they are a reserved word or contain special characters.
A name with any number of upper case characters is considered
to be case sensitive, and will be sent as quoted.
To enable unconditional quoting for the table name, specify the flag
``quote=True`` to the constructor, or use the :class:`.quoted_name`
construct to specify the name.
:param metadata: a :class:`.MetaData` object which will contain this
table. The metadata is used as a point of association of this table
with other tables which are referenced via foreign key. It also
may be used to associate this table with a particular
:class:`.Connectable`.
:param \*args: Additional positional arguments are used primarily
to add the list of :class:`.Column` objects contained within this
table. Similar to the style of a CREATE TABLE statement, other
:class:`.SchemaItem` constructs may be added here, including
:class:`.PrimaryKeyConstraint`, and :class:`.ForeignKeyConstraint`.
:param autoload: Defaults to False, unless :paramref:`.Table.autoload_with`
is set in which case it defaults to True; :class:`.Column` objects
for this table should be reflected from the database, possibly
augmenting or replacing existing :class:`.Column` objects that were
explicitly specified.
.. versionchanged:: 1.0.0 setting the :paramref:`.Table.autoload_with`
parameter implies that :paramref:`.Table.autoload` will default
to True.
.. seealso::
:ref:`metadata_reflection_toplevel`
:param autoload_replace: Defaults to ``True``; when using
:paramref:`.Table.autoload`
in conjunction with :paramref:`.Table.extend_existing`, indicates
that :class:`.Column` objects present in the already-existing
:class:`.Table` object should be replaced with columns of the same
name retrieved from the autoload process. When ``False``, columns
already present under existing names will be omitted from the
reflection process.
Note that this setting does not impact :class:`.Column` objects
specified programmatically within the call to :class:`.Table` that
also is autoloading; those :class:`.Column` objects will always
replace existing columns of the same name when
:paramref:`.Table.extend_existing` is ``True``.
.. versionadded:: 0.7.5
.. seealso::
:paramref:`.Table.autoload`
:paramref:`.Table.extend_existing`
:param autoload_with: An :class:`.Engine` or :class:`.Connection` object
with which this :class:`.Table` object will be reflected; when
set to a non-None value, it implies that :paramref:`.Table.autoload`
is ``True``. If left unset, but :paramref:`.Table.autoload` is
explicitly set to ``True``, an autoload operation will attempt to
proceed by locating an :class:`.Engine` or :class:`.Connection` bound
to the underlying :class:`.MetaData` object.
.. seealso::
:paramref:`.Table.autoload`
:param extend_existing: When ``True``, indicates that if this
:class:`.Table` is already present in the given :class:`.MetaData`,
apply further arguments within the constructor to the existing
:class:`.Table`.
If :paramref:`.Table.extend_existing` or
:paramref:`.Table.keep_existing` are not set, and the given name
of the new :class:`.Table` refers to a :class:`.Table` that is
already present in the target :class:`.MetaData` collection, and
this :class:`.Table` specifies additional columns or other constructs
or flags that modify the table's state, an
error is raised. The purpose of these two mutually-exclusive flags
is to specify what action should be taken when a :class:`.Table`
is specified that matches an existing :class:`.Table`, yet specifies
additional constructs.
:paramref:`.Table.extend_existing` will also work in conjunction
with :paramref:`.Table.autoload` to run a new reflection
operation against the database, even if a :class:`.Table`
of the same name is already present in the target
:class:`.MetaData`; newly reflected :class:`.Column` objects
and other options will be added into the state of the
:class:`.Table`, potentially overwriting existing columns
and options of the same name.
.. versionchanged:: 0.7.4 :paramref:`.Table.extend_existing` will
invoke a new reflection operation when combined with
:paramref:`.Table.autoload` set to True.
As is always the case with :paramref:`.Table.autoload`,
:class:`.Column` objects can be specified in the same :class:`.Table`
constructor, which will take precedence. Below, the existing
table ``mytable`` will be augmented with :class:`.Column` objects
both reflected from the database, as well as the given :class:`.Column`
named "y"::
Table("mytable", metadata,
Column('y', Integer),
extend_existing=True,
autoload=True,
autoload_with=engine
)
.. seealso::
:paramref:`.Table.autoload`
:paramref:`.Table.autoload_replace`
:paramref:`.Table.keep_existing`
:param implicit_returning: True by default - indicates that
RETURNING can be used by default to fetch newly inserted primary key
values, for backends which support this. Note that
create_engine() also provides an implicit_returning flag.
:param include_columns: A list of strings indicating a subset of
columns to be loaded via the ``autoload`` operation; table columns who
aren't present in this list will not be represented on the resulting
``Table`` object. Defaults to ``None`` which indicates all columns
should be reflected.
:param info: Optional data dictionary which will be populated into the
:attr:`.SchemaItem.info` attribute of this object.
:param keep_existing: When ``True``, indicates that if this Table
is already present in the given :class:`.MetaData`, ignore
further arguments within the constructor to the existing
:class:`.Table`, and return the :class:`.Table` object as
originally created. This is to allow a function that wishes
to define a new :class:`.Table` on first call, but on
subsequent calls will return the same :class:`.Table`,
without any of the declarations (particularly constraints)
being applied a second time.
If :paramref:`.Table.extend_existing` or
:paramref:`.Table.keep_existing` are not set, and the given name
of the new :class:`.Table` refers to a :class:`.Table` that is
already present in the target :class:`.MetaData` collection, and
this :class:`.Table` specifies additional columns or other constructs
or flags that modify the table's state, an
error is raised. The purpose of these two mutually-exclusive flags
is to specify what action should be taken when a :class:`.Table`
is specified that matches an existing :class:`.Table`, yet specifies
additional constructs.
.. seealso::
:paramref:`.Table.extend_existing`
:param listeners: A list of tuples of the form ``(<eventname>, <fn>)``
which will be passed to :func:`.event.listen` upon construction.
This alternate hook to :func:`.event.listen` allows the establishment
of a listener function specific to this :class:`.Table` before
the "autoload" process begins. Particularly useful for
the :meth:`.DDLEvents.column_reflect` event::
def listen_for_reflect(table, column_info):
"handle the column reflection event"
# ...
t = Table(
'sometable',
autoload=True,
listeners=[
('column_reflect', listen_for_reflect)
])
:param mustexist: When ``True``, indicates that this Table must already
be present in the given :class:`.MetaData` collection, else
Loading ...