-
-
Notifications
You must be signed in to change notification settings - Fork 246
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update the type comparison code used for schema autogeneration. Compare #619
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision e4aeb65 of this pull request into gerrit so we can run tests and reviews and stuff
New Gerrit review created for change e4aeb65: https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
the jenkins runner will run some openstack suites which in the case of neutron might exercise the type comparison stuff a bit. let's see what happens. |
mike bayer (zzzeek) wrote: Let me start off with, thank you very much for this work so far, it looks amazing! This is a really critical area where we get a lot of complaints and I am really excited if we can finally make it work for real. so there's a bunch of failures but they look to be all in the realm of unexpected positives for the comparison logic. in the main suite, we have for example, an unexpected change in type between VARCHAR and String (this is likely because on Oracle, it's rendered as VARCHAR2 ? ) Traceback (most recent call last): over in openstack nova, where they run tests that compare schemas to be the same on MySQL, where the VARCHAR datatype has a lot of flags, we see: AssertionError: Models and migration scripts aren't in sync: those are all false positives; Unicode / String render VARCHAR on MySQL and there are default values for collation and charset. I think a good rule here might be if the DB-reflected column has some flags that are set, and the model-side has no flag set for that value at all, that means no change. so this opens up a new subject area which is that when we add new comparison features to autogenerate, especially when we added indexes/unique constraints, the vast majority of issues reported were related to false positives. The index/unique thing, I must have had 20 issues over the course of several years with that. So, we might want to build this so that it's being very conservative about reporting a change based on keyword arguments that are different. as always, let me know how you are doing and if you have motivation / resources to keep going. I can always pick up sooner rather than later if need be but I am glad if you'd like to keep going! |
That is a WAY better idea. Felt pretty ugly adding in all those default keywords into the synonyms list, and I knew I would miss a bunch. But only comparing keywords if they BOTH have them is exactly the right thing to do! I can add I pushed up an update. I have been testing with postgresql/mysql/sqlite. I think this version of the code is a little easier to follow as well... but still feels too complicated? |
Oh, question- I made the assumption that |
as far as I know, sure. I would think that all the logic here would be overridable by a subclass impl if they needed to get in there and change things. |
a453c9e
to
94e7ad0
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 94e7ad0 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 94e7ad0 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
Added the VARCHAR/VARCHAR2 synonym to oracle |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 8963755 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 8963755 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 8963755 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 8963755 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 17a39d6 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 17a39d6 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
2d67713
to
2edf464
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 2edf464 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 2edf464 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
2edf464
to
07495dd
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 2c9faf6 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 2c9faf6 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
2c9faf6
to
b80f225
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision b80f225 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset b80f225 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
b80f225
to
97da348
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 97da348 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 97da348 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
@@ -50,6 +52,30 @@ def pytest_pycollect_makeitem(collector, name, obj): | |||
return [] | |||
|
|||
|
|||
def vendored_exclusions(compound_object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As you mentioned, the testing construct isn't in sqlalchemy before 1.3. So I did this janky thing- though I think it may make more sense to just drop the support for older versions as you mentioned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
(4 comments)
haven't reviewed the doc changes yet, just a few quickies...
alembic/ddl/impl.py
Outdated
@@ -39,6 +44,7 @@ class DefaultImpl(with_metaclass(ImplMeta)): | |||
|
|||
transactional_ddl = False | |||
command_terminator = ";" | |||
type_synonyms = [{"NUMERIC", "DECIMAL"}] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
I tend to use tuples for things like this to make sure nothing is mutated...
@@ -50,6 +52,30 @@ def pytest_pycollect_makeitem(collector, name, obj): | |||
return [] | |||
|
|||
|
|||
def vendored_exclusions(compound_object): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
I've re-vendored this into alembic again in alembic/testing/exclusions.py so we can remove this
@@ -5,6 +5,10 @@ | |||
|
|||
|
|||
class DefaultRequirements(SuiteRequirements): | |||
@property |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
the def name should be stated in terms of whatever it is that oracle is not doing, not the DB name itself
tests/test_autogen_diffs.py
Outdated
from alembic.util import CommandError | ||
from ._autogen_fixtures import AutogenFixtureTest | ||
from ._autogen_fixtures import AutogenTest | ||
from ._autogen_fixtures import _default_object_filters, AutogenFixtureTest, \ |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
this is all going to reformat w/ black...if you install the .pre-commit-config.yml hook for your next commit
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the project switching to black? I had it in black format and undid it in some places to match the older style haha. I approve! will do
mike bayer (zzzeek) wrote:
alembic has been on black for many months now, actually the lines here would reformat because of the "zimports" tool I wrote first and foremost. Just turn on the pre-commit hooks and it will all be taken care of :). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
Code-Review-1
(9 comments)
OK I have a full review on here now.
) | ||
if comparison is not None: | ||
return not comparison | ||
for meta, inspect in zip(inspected_params.args, meta_params.args): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
do we know that these two .args are the same length? What if a VARCHAR has a default length that gets set up on the database side but isn't in the metadata? i think perhaps if len(meta_params.args) == 0, we skip this test.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I picked zip was in case was in case the lists weren't of equal length. We only compare up to the length of the shorter list, ignoring differences in "extra" arguments (that may have been added by the server defaults). If the shorter list is len 0, this loop will just be skipped.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
do we have any scenarios that exercise these cases? I';m not sure our datatypes have so much positional arguments for this to matter. I'm fine with it for now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If I do
if inspected_params.args and meta_params.args and inspected_params.args != meta_params.args:
return False
AutogenerateVariantCompareTest_oracle+cx_oracle_11_2_0_2_0::test_variant_no_issue fails comparing BigInteger to BigInteger, while test_autogen_diffs.py::CompareMetadataToInspectorTest_oracle+cx_oracle_11_2_0_2_0::test_introspected_columns_match_metadata_columns[cola10] fails comparing Boolean to Boolean.
This is because the Oracle dialect prints those as NUMERIC(19) ... but the server adds precision to the returned value.
I added an extra test to be a bit more explicit with DECIMAL(10, 2) compared to NUMERIC(10)
specified (such as lengths, precisions, or enumeration members), they will be | ||
compared as well. However, if keywords are only specified for one, | ||
changes in these will be ignored. The type comparison logic is extensible to | ||
work around these limitations, see :ref:`compare_types` for details. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
add:
.. versionchanged:: 1.4 type comparison code has been enhanced to compare column types more deeply as well as to take arguments into account.
@@ -405,18 +407,24 @@ is set to True:: | |||
.. note:: | |||
|
|||
The default type comparison logic (which is end-user extensible) currently |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
"as of Alembic version 1.4" just to make sure people see this
docs/build/autogenerate.rst
Outdated
or ``TEXT``. Dialect implementations can have synonyms that are considered | ||
equivalent- this is because some databases support types by converting them | ||
to another type. For example, in ``NUMERIC`` and ``DECIMAL`` are considered | ||
equivalent. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
"for example, NUMERIC and DECIMAL are considered equivalent on all backends, while on the Oracle backend the additional synonyms BIGINT, INTEGER, NUMBER, SMALLINT are added to this list of equivalents"
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
good one!
docs/build/autogenerate.rst
Outdated
* Next, the arguments within the type, such as the lengths of | ||
strings, precision values for numerics, the elements inside of an | ||
enumeration are compared. If BOTH columns have arguments AND they are | ||
different, a change will be detected. If one column is jsut set to the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
typo "just"
docs/build/autogenerate.rst
Outdated
strings, precision values for numerics, the elements inside of an | ||
enumeration are compared. If BOTH columns have arguments AND they are | ||
different, a change will be detected. If one column is jsut set to the | ||
default and the other has arguments, we don't currently detect this. The |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
"and the other has arguments, Alembic will pass on attempting to compare these. The rationale is that it is difficult to detect what a database backend sets as a default value without generating false positives".
reason here is that it can be hard to know what the database backend sets | ||
as the default values, meaning that INTEGER() and INTEGER(10) could | ||
actually be the same thing, and we don't want to regenerate a diff every | ||
time. | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
add a .. versionchanged:: 1.4
note here also
docs/build/autogenerate.rst
Outdated
@@ -488,6 +496,13 @@ then a basic check for type equivalence is run. | |||
.. versionadded:: 0.7.6 - added support for the ``compare_against_backend()`` | |||
method. | |||
|
|||
For a custom dialect, you could also specify ``impl.type_synonyms``. This |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
this is getting into people making their own "impls" which I think is out of scope for this document, so I would take this blurb out.
Integer(), | ||
Numeric(8, 0), | ||
True, | ||
config.requirements.integer_subtype_comparisons, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
mike bayer (zzzeek) wrote:
this requirement apparently refers to just "is oracle", where we couldn't compare BigInteger to Integer. however, now that we compare the "scale" value, this should work now?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Unfortunately not with the other rules. Integer and Numeric come through as synonyms on Oracle, and the "metadata" column has no arguments...so we ignore the arguments on the "inspect" column.
…re the output text for the type to look for changes. In addition, allow schemas to define sets of types that are functionally equivalent, such as BOOL and TINYINT(1).
Ah, I see- only new lines are formatted, didn't realize! |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, this is sqla-tester setting up my work to try to get revision 1a6a386 of this pull request into gerrit so we can run tests and reviews and stuff
Patchset 1a6a386 added to existing Gerrit review https://gerrit.sqlalchemy.org/#/c/sqlalchemy/alembic/+/1561 |
mike bayer (zzzeek) wrote: next thing this needs is a file docs/build/unreleased/619.rst that describes the change. View this in Gerrit at https://gerrit.sqlalchemy.org/1561 |
mike bayer (zzzeek) wrote: Code-Review+2 Workflow+1 View this in Gerrit at https://gerrit.sqlalchemy.org/1561 |
Gerrit review https://gerrit.sqlalchemy.org/1561 has been merged. Congratulations! :) |
This PR has completely removed support for @zzzeek For me we can just drop it since no one noticed |
for reference it was originally added in dabc7f0 |
how come tests did not fail? |
I haven't checked it. I'll open issue and fix this, also rewriting the tests |
the output text for the type to look for changes. In addition, allow
schemas to define sets of types that are functionally equivalent, such
as BOOL and TINYINT(1).
#605