diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-10-06 23:38:43 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2015-10-06 23:43:33 -0400 |
commit | ba47b3e756b20d632db50acc2b30819c06801d9f (patch) | |
tree | 97b9ce85844b902f3ecc648693e04717d9009216 | |
parent | 0a34070d9274d3dda05628543560bb42e8588dde (diff) | |
download | sqlalchemy-ba47b3e756b20d632db50acc2b30819c06801d9f.tar.gz |
- get tests working
- re-support the use case of composite PK where some cols are *supposed*
to be NULL, check nullable flag
-rw-r--r-- | doc/build/changelog/migration_11.rst | 10 | ||||
-rw-r--r-- | lib/sqlalchemy/sql/crud.py | 12 | ||||
-rw-r--r-- | lib/sqlalchemy/testing/schema.py | 2 | ||||
-rw-r--r-- | test/ext/declarative/test_basic.py | 3 | ||||
-rw-r--r-- | test/orm/test_composites.py | 3 | ||||
-rw-r--r-- | test/orm/test_query.py | 3 | ||||
-rw-r--r-- | test/orm/test_relationships.py | 11 | ||||
-rw-r--r-- | test/orm/test_unitofwork.py | 2 | ||||
-rw-r--r-- | test/sql/test_defaults.py | 1 | ||||
-rw-r--r-- | test/sql/test_insert.py | 11 |
10 files changed, 37 insertions, 21 deletions
diff --git a/doc/build/changelog/migration_11.rst b/doc/build/changelog/migration_11.rst index 56fb5cff6..12f1af721 100644 --- a/doc/build/changelog/migration_11.rst +++ b/doc/build/changelog/migration_11.rst @@ -333,6 +333,16 @@ value generator can be indicated using :class:`.FetchedValue`:: Column('y', Integer, primary_key=True, server_default=FetchedValue()) ) +For the very unlikely case where a composite primary key is actually intended +to store NULL in one or more of its columns (only supported on SQLite and MySQL), +specify the column with ``nullable=True``:: + + Table( + 'b', metadata, + Column('x', Integer, primary_key=True), + Column('y', Integer, primary_key=True, nullable=True) + ) + .. seealso:: diff --git a/lib/sqlalchemy/sql/crud.py b/lib/sqlalchemy/sql/crud.py index eaad680d6..72b66c036 100644 --- a/lib/sqlalchemy/sql/crud.py +++ b/lib/sqlalchemy/sql/crud.py @@ -249,7 +249,9 @@ def _scan_cols( elif implicit_return_defaults and \ c in implicit_return_defaults: compiler.returning.append(c) - elif c.primary_key and c is not stmt.table._autoincrement_column: + elif c.primary_key and \ + c is not stmt.table._autoincrement_column and \ + not c.nullable: _raise_pk_with_no_anticipated_value(c) elif compiler.isupdate: @@ -324,7 +326,7 @@ def _append_param_insert_pk_returning(compiler, stmt, c, values, kw): ) elif c is stmt.table._autoincrement_column or c.server_default is not None: compiler.returning.append(c) - else: + elif not c.nullable: # no .default, no .server_default, not autoincrement, we have # no indication this primary key column will have any value _raise_pk_with_no_anticipated_value(c) @@ -400,7 +402,7 @@ def _append_param_insert_pk(compiler, stmt, c, values, kw): values.append( (c, _create_prefetch_bind_param(compiler, c)) ) - elif c.default is None and c.server_default is None: + elif c.default is None and c.server_default is None and not c.nullable: # no .default, no .server_default, not autoincrement, we have # no indication this primary key column will have any value _raise_pk_with_no_anticipated_value(c) @@ -612,9 +614,9 @@ def _raise_pk_with_no_anticipated_value(c): "Column '%s.%s' is marked as a member of the " "primary key for table '%s', " "but has no Python-side or server-side default generator indicated, " - "nor does it indicate 'autoincrement=True', " + "nor does it indicate 'autoincrement=True' or 'nullable=True', " "and no explicit value is passed. " - "Primary key columns may not store NULL." + "Primary key columns typically may not store NULL." % (c.table.fullname, c.name, c.table.fullname)) if len(c.table.primary_key.columns) > 1: diff --git a/lib/sqlalchemy/testing/schema.py b/lib/sqlalchemy/testing/schema.py index 517e31870..257578668 100644 --- a/lib/sqlalchemy/testing/schema.py +++ b/lib/sqlalchemy/testing/schema.py @@ -71,7 +71,7 @@ def Column(*args, **kw): args = [arg for arg in args if not isinstance(arg, schema.ForeignKey)] col = schema.Column(*args, **kw) - if 'test_needs_autoincrement' in test_opts and \ + if test_opts.get('test_needs_autoincrement', False) and \ kw.get('primary_key', False): if col.default is None and col.server_default is None: diff --git a/test/ext/declarative/test_basic.py b/test/ext/declarative/test_basic.py index ab0de801c..5165d9cc9 100644 --- a/test/ext/declarative/test_basic.py +++ b/test/ext/declarative/test_basic.py @@ -1570,8 +1570,7 @@ class DeclarativeTest(DeclarativeTestBase): meta = MetaData(testing.db) t1 = Table( 't1', meta, - Column('id', String(50), - primary_key=True, test_needs_autoincrement=True), + Column('id', String(50), primary_key=True), Column('data', String(50))) meta.create_all() try: diff --git a/test/orm/test_composites.py b/test/orm/test_composites.py index 8b777dcdf..48027ec2d 100644 --- a/test/orm/test_composites.py +++ b/test/orm/test_composites.py @@ -313,8 +313,7 @@ class PrimaryKeyTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): Table('graphs', metadata, - Column('id', Integer, primary_key=True, - test_needs_autoincrement=True), + Column('id', Integer, primary_key=True), Column('version_id', Integer, primary_key=True, nullable=True), Column('name', String(30))) diff --git a/test/orm/test_query.py b/test/orm/test_query.py index 4ae0b010a..833613ec6 100644 --- a/test/orm/test_query.py +++ b/test/orm/test_query.py @@ -579,8 +579,7 @@ class GetTest(QueryTest): table = Table( 'unicode_data', metadata, Column( - 'id', Unicode(40), primary_key=True, - test_needs_autoincrement=True), + 'id', Unicode(40), primary_key=True), Column('data', Unicode(40))) metadata.create_all() ustring = util.b('petit voix m\xe2\x80\x99a').decode('utf-8') diff --git a/test/orm/test_relationships.py b/test/orm/test_relationships.py index 9e4b38a90..061187330 100644 --- a/test/orm/test_relationships.py +++ b/test/orm/test_relationships.py @@ -931,14 +931,12 @@ class SynonymsAsFKsTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): Table("tableA", metadata, - Column("id", Integer, primary_key=True, - test_needs_autoincrement=True), + Column("id", Integer, primary_key=True), Column("foo", Integer,), test_needs_fk=True) Table("tableB", metadata, - Column("id", Integer, primary_key=True, - test_needs_autoincrement=True), + Column("id", Integer, primary_key=True), Column("_a_id", Integer, key='a_id', primary_key=True), test_needs_fk=True) @@ -1093,7 +1091,7 @@ class FKsAsPksTest(fixtures.MappedTest): 'tablec', tableA.metadata, Column('id', Integer, primary_key=True), Column('a_id', Integer, ForeignKey('tableA.id'), - primary_key=True, autoincrement=False, nullable=True)) + primary_key=True, nullable=True)) tableC.create() class C(fixtures.BasicEntity): @@ -2703,8 +2701,7 @@ class ExplicitLocalRemoteTest(fixtures.MappedTest): @classmethod def define_tables(cls, metadata): Table('t1', metadata, - Column('id', String(50), primary_key=True, - test_needs_autoincrement=True), + Column('id', String(50), primary_key=True), Column('data', String(50))) Table('t2', metadata, Column('id', Integer, primary_key=True, diff --git a/test/orm/test_unitofwork.py b/test/orm/test_unitofwork.py index 5a47903f0..2f67943f1 100644 --- a/test/orm/test_unitofwork.py +++ b/test/orm/test_unitofwork.py @@ -260,7 +260,7 @@ class PKTest(fixtures.MappedTest): def define_tables(cls, metadata): Table('multipk1', metadata, Column('multi_id', Integer, primary_key=True, - test_needs_autoincrement=True), + test_needs_autoincrement=not testing.against('sqlite')), Column('multi_rev', Integer, primary_key=True), Column('name', String(50), nullable=False), Column('value', String(100))) diff --git a/test/sql/test_defaults.py b/test/sql/test_defaults.py index c17920af1..8a0e27ebd 100644 --- a/test/sql/test_defaults.py +++ b/test/sql/test_defaults.py @@ -732,7 +732,6 @@ class AutoIncrementTest(fixtures.TablesTest): ) assert x._autoincrement_column is None - @testing.fails_on('sqlite', 'FIXME: unknown') def test_non_autoincrement(self): # sqlite INT primary keys can be non-unique! (only for ints) nonai = Table( diff --git a/test/sql/test_insert.py b/test/sql/test_insert.py index 7e5e1699e..bdaf4f38c 100644 --- a/test/sql/test_insert.py +++ b/test/sql/test_insert.py @@ -433,6 +433,17 @@ class InsertTest(_InsertTestBase, fixtures.TablesTest, AssertsCompiledSQL): ) + def test_anticipate_nullable_composite_pk(self): + t = Table( + 't', MetaData(), Column('x', Integer, primary_key=True), + Column('y', Integer, primary_key=True, nullable=True) + ) + self.assert_compile( + t.insert(), + "INSERT INTO t (x) VALUES (:x)", + params={'x': 5}, + ) + def test_anticipate_no_pk_non_composite_pk(self): t = Table( 't', MetaData(), |