From 55ad10370f9eb50795e136aac595193168982e92 Mon Sep 17 00:00:00 2001 From: Mike Bayer Date: Wed, 23 Nov 2016 09:14:02 -0500 Subject: Add _extend_on deduplicating set for metadata.reflect() The "extend_existing" option of :class:`.Table` reflection would cause indexes and constraints to be doubled up in the case that the parameter were used with :meth:`.MetaData.reflect` (as the automap extension does) due to tables being reflected both within the foreign key path as well as directly. A new de-duplicating set is passed through within the :meth:`.MetaData.reflect` sequence to prevent double reflection in this way. Change-Id: Ibf6650c1e76a44ccbe15765fd79df2fa53d6bac7 Fixes: #3861 --- lib/sqlalchemy/sql/schema.py | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) (limited to 'lib/sqlalchemy/sql') diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index 27ef9e01b..5c48e5bbb 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -485,6 +485,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause): autoload = kwargs.pop('autoload', autoload_with is not None) # this argument is only used with _init_existing() kwargs.pop('autoload_replace', True) + _extend_on = kwargs.pop("_extend_on", None) + include_columns = kwargs.pop('include_columns', None) self.implicit_returning = kwargs.pop('implicit_returning', True) @@ -504,19 +506,22 @@ class Table(DialectKWArgs, SchemaItem, TableClause): # we do it after the table is in the singleton dictionary to support # circular foreign keys if autoload: - self._autoload(metadata, autoload_with, include_columns) + self._autoload( + metadata, autoload_with, + include_columns, _extend_on=_extend_on) # initialize all the column, etc. objects. done after reflection to # allow user-overrides self._init_items(*args) def _autoload(self, metadata, autoload_with, include_columns, - exclude_columns=()): + exclude_columns=(), _extend_on=None): if autoload_with: autoload_with.run_callable( autoload_with.dialect.reflecttable, - self, include_columns, exclude_columns + self, include_columns, exclude_columns, + _extend_on=_extend_on ) else: bind = _bind_or_error( @@ -528,7 +533,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause): "metadata.bind=") bind.run_callable( bind.dialect.reflecttable, - self, include_columns, exclude_columns + self, include_columns, exclude_columns, + _extend_on=_extend_on ) @property @@ -557,6 +563,8 @@ class Table(DialectKWArgs, SchemaItem, TableClause): autoload = kwargs.pop('autoload', autoload_with is not None) autoload_replace = kwargs.pop('autoload_replace', True) schema = kwargs.pop('schema', None) + _extend_on = kwargs.pop('_extend_on', None) + if schema and schema != self.schema: raise exc.ArgumentError( "Can't change schema of existing table from '%s' to '%s'", @@ -579,12 +587,15 @@ class Table(DialectKWArgs, SchemaItem, TableClause): if autoload: if not autoload_replace: + # don't replace columns already present. + # we'd like to do this for constraints also however we don't + # have simple de-duping for unnamed constraints. exclude_columns = [c.name for c in self.c] else: exclude_columns = () self._autoload( self.metadata, autoload_with, - include_columns, exclude_columns) + include_columns, exclude_columns, _extend_on=_extend_on) self._extra_kwargs(**kwargs) self._init_items(*args) @@ -3758,7 +3769,8 @@ class MetaData(SchemaItem): 'autoload': True, 'autoload_with': conn, 'extend_existing': extend_existing, - 'autoload_replace': autoload_replace + 'autoload_replace': autoload_replace, + '_extend_on': set() } reflect_opts.update(dialect_kwargs) -- cgit v1.2.1