diff options
author | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-06-25 11:40:56 -0400 |
---|---|---|
committer | Mike Bayer <mike_mp@zzzcomputing.com> | 2019-06-25 16:31:43 -0400 |
commit | d4951ffb66f933ca332baf85faa15c7547523ecb (patch) | |
tree | 2d783ac42d6657f423cf36a56e624e402f8da828 /tests/test_batch.py | |
parent | 26453a8b284743bd590a86208968ca862caa67ca (diff) | |
download | alembic-d4951ffb66f933ca332baf85faa15c7547523ecb.tar.gz |
Ensure SQLite default expressions are parenthesized
- SQLite server default reflection will ensure parenthesis are surrounding a
column default expression that is detected as being a non-constant
expression, such as a ``datetime()`` default, to accommodate for the
requirement that SQL expressions have to be parenthesized when being sent
as DDL. Parenthesis are not added to constant expressions to allow for
maximum cross-compatibility with other dialects and existing test suites
(such as Alembic's), which necessarily entails scanning the expression to
eliminate for constant numeric and string values. The logic is added to the
two "reflection->DDL round trip" paths which are currently autogenerate and
batch migration. Within autogenerate, the logic is on the rendering side,
whereas in batch the logic is installed as a column reflection hook.
- Improved SQLite server default comparison to accommodate for a ``text()``
construct that added parenthesis directly vs. a construct that relied
upon the SQLAlchemy SQLite dialect to render the parenthesis, as well
as improved support for various forms of constant expressions such as
values that are quoted vs. non-quoted.
- Fixed bug where the "literal_binds" flag was not being set when
autogenerate would create a server default value, meaning server default
comparisons would fail for functions that contained literal values.
Fixes: #579
Change-Id: I78b87573b8ecd15cb4ced08f054902f574e3956c
Diffstat (limited to 'tests/test_batch.py')
-rw-r--r-- | tests/test_batch.py | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/tests/test_batch.py b/tests/test_batch.py index 8879c9c..c8c5b33 100644 --- a/tests/test_batch.py +++ b/tests/test_batch.py @@ -9,6 +9,7 @@ from sqlalchemy import Enum from sqlalchemy import exc from sqlalchemy import ForeignKey from sqlalchemy import ForeignKeyConstraint +from sqlalchemy import func from sqlalchemy import Index from sqlalchemy import Integer from sqlalchemy import MetaData @@ -1117,6 +1118,23 @@ class BatchRoundTripTest(TestBase): t.create(self.conn) return t + def _datetime_server_default_fixture(self): + return func.datetime("now", "localtime") + + def _timestamp_w_expr_default_fixture(self): + t = Table( + "hasts", + self.metadata, + Column( + "x", + DateTime(), + server_default=self._datetime_server_default_fixture(), + nullable=False, + ), + ) + t.create(self.conn) + return t + def _int_to_boolean_fixture(self): t = Table("hasbool", self.metadata, Column("x", Integer)) t.create(self.conn) @@ -1157,6 +1175,23 @@ class BatchRoundTripTest(TestBase): [(datetime.datetime(2012, 5, 18, 15, 32, 5),)], ) + @config.requirements.sqlalchemy_12 + def test_no_net_change_timestamp_w_default(self): + t = self._timestamp_w_expr_default_fixture() + + with self.op.batch_alter_table("hasts") as batch_op: + batch_op.alter_column( + "x", + type_=DateTime(), + nullable=False, + server_default=self._datetime_server_default_fixture(), + ) + + self.conn.execute(t.insert()) + + row = self.conn.execute(select([t.c.x])).fetchone() + assert row["x"] is not None + def test_drop_col_schematype(self): self._boolean_fixture() with self.op.batch_alter_table("hasbool") as batch_op: @@ -1612,6 +1647,9 @@ class BatchRoundTripMySQLTest(BatchRoundTripTest): __only_on__ = "mysql" __backend__ = True + def _datetime_server_default_fixture(self): + return func.current_timestamp() + @exclusions.fails() def test_drop_pk_col_readd_pk_col(self): super(BatchRoundTripMySQLTest, self).test_drop_pk_col_readd_pk_col() @@ -1655,6 +1693,9 @@ class BatchRoundTripPostgresqlTest(BatchRoundTripTest): __only_on__ = "postgresql" __backend__ = True + def _datetime_server_default_fixture(self): + return func.current_timestamp() + @exclusions.fails() def test_drop_pk_col_readd_pk_col(self): super( |