diff options
author | mike bayer <mike_mp@zzzcomputing.com> | 2017-05-25 16:24:25 -0400 |
---|---|---|
committer | Gerrit Code Review <gerrit@awstats.zzzcomputing.com> | 2017-05-25 16:24:25 -0400 |
commit | 915012950c26ca5ed68917088761b73047691113 (patch) | |
tree | dbd37503841a00a64841d2c8b7e73432ed6bf8d0 | |
parent | f8a3f14e4f862a4bf0be591699f1f72815c72514 (diff) | |
parent | a78718b9340e9840a470300932af178ce57c0f7d (diff) | |
download | sqlalchemy-915012950c26ca5ed68917088761b73047691113.tar.gz |
Merge "Raise if ForeignKeyConstraint created with different numbers of local and remote columns."
-rw-r--r-- | doc/build/changelog/changelog_11.rst | 12 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/schema.py | 16 | ||||
-rw-r--r-- | test/sql/test_metadata.py | 23 |
3 files changed, 51 insertions, 0 deletions
diff --git a/doc/build/changelog/changelog_11.rst b/doc/build/changelog/changelog_11.rst index 89d42f473..66f6bb45a 100644 --- a/doc/build/changelog/changelog_11.rst +++ b/doc/build/changelog/changelog_11.rst @@ -67,6 +67,18 @@ fail for cx_Oracle version 6.0b1 due to the "b" character. Version string parsing is now via a regexp rather than a simple split. + .. change:: 3949 + :tags: bug, schema + :versions: 1.2.0b1 + :tickets: 3949 + + An :class:`.ArgumentError` is now raised if a + :class:`.ForeignKeyConstraint` object is created with a mismatched + number of "local" and "remote" columns, which otherwise causes the + internal state of the constraint to be incorrect. Note that this + also impacts the condition where a dialect's reflection process + produces a mismatched set of columns for a foreign key constraint. + .. change:: 3980 :tags: bug, ext :versions: 1.2.0b1 diff --git a/lib/sqlalchemy/sql/schema.py b/lib/sqlalchemy/sql/schema.py index a9aee5883..4eb095196 100644 --- a/lib/sqlalchemy/sql/schema.py +++ b/lib/sqlalchemy/sql/schema.py @@ -2883,6 +2883,22 @@ class ForeignKeyConstraint(ColumnCollectionConstraint): self.use_alter = use_alter self.match = match + if len(set(columns)) != len(refcolumns): + if len(set(columns)) != len(columns): + # e.g. FOREIGN KEY (a, a) REFERENCES r (b, c) + raise exc.ArgumentError( + "ForeignKeyConstraint with duplicate source column " + "references are not supported." + ) + else: + # e.g. FOREIGN KEY (a) REFERENCES r (b, c) + # paraphrasing https://www.postgresql.org/docs/9.2/static/\ + # ddl-constraints.html + raise exc.ArgumentError( + "ForeignKeyConstraint number " + "of constrained columns must match the number of " + "referenced columns.") + # standalone ForeignKeyConstraint - create # associated ForeignKey objects which will be applied to hosted # Column objects (in col.foreign_keys), either now or when attached diff --git a/test/sql/test_metadata.py b/test/sql/test_metadata.py index 6d0df3b5f..61fbbc57b 100644 --- a/test/sql/test_metadata.py +++ b/test/sql/test_metadata.py @@ -348,6 +348,29 @@ class MetaDataTest(fixtures.TestBase, ComparesTables): getattr, list(a.foreign_keys)[0], "column" ) + def test_fk_mismatched_local_remote_cols(self): + + assert_raises_message( + exc.ArgumentError, + "ForeignKeyConstraint number of constrained columns must " + "match the number of referenced columns.", + ForeignKeyConstraint, ['a'], ['b.a', 'b.b'] + ) + + assert_raises_message( + exc.ArgumentError, + "ForeignKeyConstraint number of constrained columns " + "must match the number of referenced columns.", + ForeignKeyConstraint, ['a', 'b'], ['b.a'] + ) + + assert_raises_message( + exc.ArgumentError, + "ForeignKeyConstraint with duplicate source column " + "references are not supported.", + ForeignKeyConstraint, ['a', 'a'], ['b.a', 'b.b'] + ) + def test_pickle_metadata_sequence_restated(self): m1 = MetaData() Table('a', m1, |