)]}'
{"/COMMIT_MSG":[{"author":{"_account_id":8412,"name":"Mike Durnosvistov","email":"glacierr.dev@gmail.com","username":"mdurnosvistov"},"change_message_id":"cef3ac418de496b1abf69de7a1e6de313bcabeb3","unresolved":false,"context_lines":[{"line_number":11,"context_line":"(and potentially all) of the schema changes to be performed while"},{"line_number":12,"context_line":"services are still running, reducing downtime during deploys."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Partially-Implements: online-schema-changes"},{"line_number":15,"context_line":"Change-Id: If666d5162674aaa874ff2c40799f29e23856544d"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"da86d52c_e9e61faf","line":14,"updated":"2015-02-12 14:33:07.000000000","message":"Maybe it should be -\u003e\n    Related to blueprint online-schema-changes","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":10618,"name":"Pavel Kholkin","email":"p.v.holkin@mail.ru","username":"pkholkin"},"change_message_id":"ba6da885445da2e7a5233416eb8947846d12d675","unresolved":false,"context_lines":[{"line_number":11,"context_line":"(and potentially all) of the schema changes to be performed while"},{"line_number":12,"context_line":"services are still running, reducing downtime during deploys."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Partially-Implements: online-schema-changes"},{"line_number":15,"context_line":"Change-Id: If666d5162674aaa874ff2c40799f29e23856544d"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"da86d52c_eb909798","line":14,"in_reply_to":"da86d52c_e9e61faf","updated":"2015-02-13 16:26:08.000000000","message":"Yes, or just -\u003e\n    Related blueprint online-schema-changes","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"4f3f50878c7bbe815828350788527361dc18e748","unresolved":false,"context_lines":[{"line_number":11,"context_line":"(and potentially all) of the schema changes to be performed while"},{"line_number":12,"context_line":"services are still running, reducing downtime during deploys."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Partially-Implements: online-schema-changes"},{"line_number":15,"context_line":"Change-Id: If666d5162674aaa874ff2c40799f29e23856544d"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":2,"id":"da86d52c_549e6408","line":14,"in_reply_to":"da86d52c_eb909798","updated":"2015-02-17 21:08:41.000000000","message":"There doesn\u0027t seem to be any consistency:\n\nCommit 6933248ff14f99e53f5e04981a3d8eb062052d66 uses \"Partially-Implements blueprint ...\"\n\nCommit 5f6306985fcc1e16470cb4d175c3deedc7be917d uses \"Partially-Implements: blueprint ...\"\n\nCommit 4dbd37b1fde1adae9b2ca7c2cb081c73998c9442 uses \"Partially implements bp ...\"\n\nAnd there are more varieties too.\n\nI can\u0027t find any preferred style documented, so I\u0027ll just follow the lead of previous commits and add \"blueprint\" into this line.","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"9be402e97b3de83a8bbec2510ee916490992c751","unresolved":false,"context_lines":[{"line_number":10,"context_line":"changes into expand, migrate and contract phases. This allows some"},{"line_number":11,"context_line":"(and potentially all) of the schema changes to be performed while"},{"line_number":12,"context_line":"services are still running, reducing downtime during deploys."},{"line_number":13,"context_line":""},{"line_number":14,"context_line":"Partially-Implements: blueprint online-schema-changes"},{"line_number":15,"context_line":"Change-Id: If666d5162674aaa874ff2c40799f29e23856544d"}],"source_content_type":"text/x-gerrit-commit-message","patch_set":14,"id":"7a016987_7b14e04b","line":13,"updated":"2015-05-21 22:23:38.000000000","message":"Doesn\u0027t this need DocImpact/UpgradeImpact tags given what\u0027s in the spec for doc impact?\n\nhttp://specs.openstack.org/openstack/nova-specs/specs/kilo/approved/online-schema-changes.html\n\nAlso, is there going to be a separate devstack job that does the optional expand/contract upgrade path here rather than the db sync?  We could be running that on the experimental queue until this lands.","commit_id":"b748f22ebba257ba78f7c182701762ad3cae2839"}],"nova/cmd/manage.py":[{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"4c5f5b0d78b446c06f6db5cbb33f686fb5357621","unresolved":false,"context_lines":[{"line_number":913,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"},{"line_number":914,"context_line":"          default\u003dFalse, help\u003d\u0027Print SQL statements instead of executing\u0027)"},{"line_number":915,"context_line":"    def expand(self, dry_run):"},{"line_number":916,"context_line":"        \"\"\"Expand database schema.\"\"\""},{"line_number":917,"context_line":"        return migration.db_expand(dry_run)"},{"line_number":918,"context_line":""},{"line_number":919,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_24201649","line":916,"updated":"2015-02-24 11:36:21.000000000","message":"I have a feeling we need to mark this as experimental?\n\nmaybe we add a --use-experimental option that defaults to False? I duno, I am thinking out loud here.","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"5813209e1de5da725f4ac2fae9c3d2f55799ecb7","unresolved":false,"context_lines":[{"line_number":911,"context_line":"        return migration.db_sync(version)"},{"line_number":912,"context_line":""},{"line_number":913,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"},{"line_number":914,"context_line":"          default\u003dFalse, help\u003d\u0027Print SQL statements instead of executing\u0027)"},{"line_number":915,"context_line":"    def expand(self, dry_run):"},{"line_number":916,"context_line":"        \"\"\"Expand database schema.\"\"\""},{"line_number":917,"context_line":"        return migration.db_expand(dry_run)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_cea6aa0e","line":914,"updated":"2015-03-16 12:09:13.000000000","message":"do we need a note saying this is experimental? or did we get everything sorted?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":4393,"name":"Dan Smith","email":"dms@danplanet.com","username":"danms"},"change_message_id":"8599446842063e984031f6a4e130e544e9d29e90","unresolved":false,"context_lines":[{"line_number":911,"context_line":"        return migration.db_sync(version)"},{"line_number":912,"context_line":""},{"line_number":913,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"},{"line_number":914,"context_line":"          default\u003dFalse, help\u003d\u0027Print SQL statements instead of executing\u0027)"},{"line_number":915,"context_line":"    def expand(self, dry_run):"},{"line_number":916,"context_line":"        \"\"\"Expand database schema.\"\"\""},{"line_number":917,"context_line":"        return migration.db_expand(dry_run)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_84c9ae7b","line":914,"in_reply_to":"9a80dd14_7b529969","updated":"2015-03-17 16:05:37.000000000","message":"Yeah, agreed. We\u0027ll cover this in the release notes, but it would be really good to make sure nobody tries to figure it out themselves and get wedged.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"068ad6e7a3490bf84a51e383e7955c87eba269f7","unresolved":false,"context_lines":[{"line_number":911,"context_line":"        return migration.db_sync(version)"},{"line_number":912,"context_line":""},{"line_number":913,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"},{"line_number":914,"context_line":"          default\u003dFalse, help\u003d\u0027Print SQL statements instead of executing\u0027)"},{"line_number":915,"context_line":"    def expand(self, dry_run):"},{"line_number":916,"context_line":"        \"\"\"Expand database schema.\"\"\""},{"line_number":917,"context_line":"        return migration.db_expand(dry_run)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_7b529969","line":914,"in_reply_to":"9a80dd14_9683df01","updated":"2015-03-17 14:52:49.000000000","message":"cool, thanks.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"45e4db30b9950d0779b6040fd4e6bd381a624b04","unresolved":false,"context_lines":[{"line_number":911,"context_line":"        return migration.db_sync(version)"},{"line_number":912,"context_line":""},{"line_number":913,"context_line":"    @args(\u0027--dry-run\u0027, action\u003d\u0027store_true\u0027, dest\u003d\u0027dry_run\u0027,"},{"line_number":914,"context_line":"          default\u003dFalse, help\u003d\u0027Print SQL statements instead of executing\u0027)"},{"line_number":915,"context_line":"    def expand(self, dry_run):"},{"line_number":916,"context_line":"        \"\"\"Expand database schema.\"\"\""},{"line_number":917,"context_line":"        return migration.db_expand(dry_run)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_9683df01","line":914,"in_reply_to":"9a80dd14_cea6aa0e","updated":"2015-03-16 15:06:48.000000000","message":"I\u0027ll have to see if I can find a standard way to do that.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"}],"nova/db/migration.py":[{"author":{"_account_id":10795,"name":"Rajesh Tailor","email":"tailor.rajesh88@gmail.com","username":"rajeshtailor"},"change_message_id":"a76bf4d445e41d301e09244a53edb0215ce1eabd","unresolved":false,"context_lines":[{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"def db_expand(dryrun\u003dFalse):"},{"line_number":30,"context_line":"    \"\"\"Expand database schame.\"\"\""},{"line_number":31,"context_line":"    return IMPL.db_expand(dryrun\u003ddryrun)"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_ac337da9","line":30,"updated":"2015-02-25 10:48:23.000000000","message":"s/schame/schema","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"7f46c0abe20954f6b984165606f751ddc0493fc3","unresolved":false,"context_lines":[{"line_number":27,"context_line":""},{"line_number":28,"context_line":""},{"line_number":29,"context_line":"def db_expand(dryrun\u003dFalse):"},{"line_number":30,"context_line":"    \"\"\"Expand database schame.\"\"\""},{"line_number":31,"context_line":"    return IMPL.db_expand(dryrun\u003ddryrun)"},{"line_number":32,"context_line":""},{"line_number":33,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_89521965","line":30,"in_reply_to":"ba7be1f8_ac337da9","updated":"2015-02-25 16:49:24.000000000","message":"Done","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":10795,"name":"Rajesh Tailor","email":"tailor.rajesh88@gmail.com","username":"rajeshtailor"},"change_message_id":"a76bf4d445e41d301e09244a53edb0215ce1eabd","unresolved":false,"context_lines":[{"line_number":32,"context_line":""},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"def db_migrate(dryrun\u003dFalse):"},{"line_number":35,"context_line":"    \"\"\"Migrate database schame.\"\"\""},{"line_number":36,"context_line":"    return IMPL.db_migrate(dryrun\u003ddryrun)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_0c22c951","line":35,"updated":"2015-02-25 10:48:23.000000000","message":"ditto","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"7f46c0abe20954f6b984165606f751ddc0493fc3","unresolved":false,"context_lines":[{"line_number":32,"context_line":""},{"line_number":33,"context_line":""},{"line_number":34,"context_line":"def db_migrate(dryrun\u003dFalse):"},{"line_number":35,"context_line":"    \"\"\"Migrate database schame.\"\"\""},{"line_number":36,"context_line":"    return IMPL.db_migrate(dryrun\u003ddryrun)"},{"line_number":37,"context_line":""},{"line_number":38,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_a94d1dc6","line":35,"in_reply_to":"ba7be1f8_0c22c951","updated":"2015-02-25 16:49:24.000000000","message":"Done","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":10795,"name":"Rajesh Tailor","email":"tailor.rajesh88@gmail.com","username":"rajeshtailor"},"change_message_id":"a76bf4d445e41d301e09244a53edb0215ce1eabd","unresolved":false,"context_lines":[{"line_number":37,"context_line":""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"def db_contract(dryrun\u003dFalse):"},{"line_number":40,"context_line":"    \"\"\"Contract database schame.\"\"\""},{"line_number":41,"context_line":"    return IMPL.db_contract(dryrun\u003ddryrun)"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_6c1505e4","line":40,"updated":"2015-02-25 10:48:23.000000000","message":"ditto","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"7f46c0abe20954f6b984165606f751ddc0493fc3","unresolved":false,"context_lines":[{"line_number":37,"context_line":""},{"line_number":38,"context_line":""},{"line_number":39,"context_line":"def db_contract(dryrun\u003dFalse):"},{"line_number":40,"context_line":"    \"\"\"Contract database schame.\"\"\""},{"line_number":41,"context_line":"    return IMPL.db_contract(dryrun\u003ddryrun)"},{"line_number":42,"context_line":""},{"line_number":43,"context_line":""}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_c94891b5","line":40,"in_reply_to":"ba7be1f8_6c1505e4","updated":"2015-02-25 16:49:24.000000000","message":"Done","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"}],"nova/db/sqlalchemy/migration.py":[{"author":{"_account_id":10795,"name":"Rajesh Tailor","email":"tailor.rajesh88@gmail.com","username":"rajeshtailor"},"change_message_id":"a76bf4d445e41d301e09244a53edb0215ce1eabd","unresolved":false,"context_lines":[{"line_number":59,"context_line":"        return False"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"    if \u0027locked\u0027 not in row:"},{"line_number":62,"context_line":"        # No locked column, cannot be locked"},{"line_number":63,"context_line":"        return False"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"    return row[\u0027locked\u0027]"}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_ac80ddc0","line":62,"updated":"2015-02-25 10:48:23.000000000","message":"We could have combined both if conditions into one as follows, but I think you have done this purposely for better readability. \nPlease confirm.\n\nif not (row and \u0027locked\u0027 in row):\n        return False","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"7f46c0abe20954f6b984165606f751ddc0493fc3","unresolved":false,"context_lines":[{"line_number":59,"context_line":"        return False"},{"line_number":60,"context_line":""},{"line_number":61,"context_line":"    if \u0027locked\u0027 not in row:"},{"line_number":62,"context_line":"        # No locked column, cannot be locked"},{"line_number":63,"context_line":"        return False"},{"line_number":64,"context_line":""},{"line_number":65,"context_line":"    return row[\u0027locked\u0027]"}],"source_content_type":"text/x-python","patch_set":9,"id":"ba7be1f8_f477e89d","line":62,"in_reply_to":"ba7be1f8_ac80ddc0","updated":"2015-02-25 16:49:24.000000000","message":"Or:\n\n  if not row or \u0027locked\u0027 not in row:\n\nI think I did that mostly so I could make the comments clearer. If there were no comments, I think either of three is reasonably readable. This isn\u0027t particularly complicated code :)","commit_id":"c474eb02436135a57b79300a6c6b4e0c84196f88"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6ce8f68a3ca29eee9c0d1a0bc51fcfdb4a1a64e0","unresolved":false,"context_lines":[{"line_number":45,"context_line":""},{"line_number":46,"context_line":""},{"line_number":47,"context_line":"def _db_sync_locked(repository):"},{"line_number":48,"context_line":"    engine \u003d get_engine()"},{"line_number":49,"context_line":"    try:"},{"line_number":50,"context_line":"        migrate_version \u003d db_utils.get_table(engine, repository.version_table)"},{"line_number":51,"context_line":"    except sqlalchemy.exc.NoSuchTableError:"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_8b1172b1","line":48,"updated":"2015-03-18 21:00:52.000000000","message":"OK, all of the \"get_engine()\" and \"select().execute()\" would be much better working on a connection at a time.  That is, \"with get_engine().begin() as connection:\", then always use connection.execute(stmt).   this will all need to happen anyway when we migrate to enginefacade.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"5813209e1de5da725f4ac2fae9c3d2f55799ecb7","unresolved":false,"context_lines":[{"line_number":58,"context_line":"    if not row or \u0027locked\u0027 not in row:"},{"line_number":59,"context_line":"        # \u0027db expand\u0027 will create row if missing and it will add locked"},{"line_number":60,"context_line":"        # column if missing. If \u0027db expand\u0027 hasn\u0027t been run, then the"},{"line_number":61,"context_line":"        # repo can\u0027t be locked"},{"line_number":62,"context_line":"        return False"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    return row[\u0027locked\u0027]"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_ee4c4e44","line":61,"updated":"2015-03-16 12:09:13.000000000","message":"Maybe this detail on the error reason should be available to admins?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"068ad6e7a3490bf84a51e383e7955c87eba269f7","unresolved":false,"context_lines":[{"line_number":58,"context_line":"    if not row or \u0027locked\u0027 not in row:"},{"line_number":59,"context_line":"        # \u0027db expand\u0027 will create row if missing and it will add locked"},{"line_number":60,"context_line":"        # column if missing. If \u0027db expand\u0027 hasn\u0027t been run, then the"},{"line_number":61,"context_line":"        # repo can\u0027t be locked"},{"line_number":62,"context_line":"        return False"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    return row[\u0027locked\u0027]"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_db4465b9","line":61,"in_reply_to":"9a80dd14_36a313b3","updated":"2015-03-17 14:52:49.000000000","message":"gotcha, thanks.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"45e4db30b9950d0779b6040fd4e6bd381a624b04","unresolved":false,"context_lines":[{"line_number":58,"context_line":"    if not row or \u0027locked\u0027 not in row:"},{"line_number":59,"context_line":"        # \u0027db expand\u0027 will create row if missing and it will add locked"},{"line_number":60,"context_line":"        # column if missing. If \u0027db expand\u0027 hasn\u0027t been run, then the"},{"line_number":61,"context_line":"        # repo can\u0027t be locked"},{"line_number":62,"context_line":"        return False"},{"line_number":63,"context_line":""},{"line_number":64,"context_line":"    return row[\u0027locked\u0027]"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_36a313b3","line":61,"in_reply_to":"9a80dd14_ee4c4e44","updated":"2015-03-16 15:06:48.000000000","message":"This isn\u0027t an error. It\u0027s just one of the three states we can be in.\n\nThis patch adds a new column \u0027locked\u0027 that it uses to track if expand/migrate have been run, but contract hasn\u0027t.\n\nIf expand has never been run, then the locked column will never be added and then it\u0027s not possible for the table to have been locked by expand.\n\nSo there are three possible states:\n1) expand has never been run. locked column does not exist. treat as not locked\n2) expand has been run, but contract hasn\u0027t. locked column exists and is True\n3) expand has been run, but contract has too. locked column exists and is False","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"def _set_db_sync_lock(repository, locked):"},{"line_number":68,"context_line":"    locked \u003d locked and 1 or 0"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    engine \u003d get_engine()"},{"line_number":71,"context_line":"    migrate_version \u003d db_utils.get_table(engine, repository.version_table)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_8acbb0a2","line":68,"updated":"2015-03-16 16:32:23.000000000","message":"Please include a code comment for this line... If I\u0027m reading it and the remainder of the function correctly, the database value is 1 (True) or 0 (False) so you don\u0027t want to pass a boolean?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":65,"context_line":""},{"line_number":66,"context_line":""},{"line_number":67,"context_line":"def _set_db_sync_lock(repository, locked):"},{"line_number":68,"context_line":"    locked \u003d locked and 1 or 0"},{"line_number":69,"context_line":""},{"line_number":70,"context_line":"    engine \u003d get_engine()"},{"line_number":71,"context_line":"    migrate_version \u003d db_utils.get_table(engine, repository.version_table)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_c7691e8e","line":68,"in_reply_to":"9a80dd14_8acbb0a2","updated":"2015-03-16 17:17:24.000000000","message":"No, the column is defined as an integer (see line 986). I tried making the column a boolean, but because this table isn\u0027t used exclusively by this code (sqlalchemy-migrate adds rows for instance), then we need to ensure there is a server default set.\n\nUnfortunately, this isn\u0027t possible for SQLAlchemy and boolean types:\n\nhttps://bitbucket.org/zzzeek/sqlalchemy/issue/1204/server_default-flag-should-also-accept\n\nThe easiest and cleanest solution is to just use an integer.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6ce8f68a3ca29eee9c0d1a0bc51fcfdb4a1a64e0","unresolved":false,"context_lines":[{"line_number":77,"context_line":"def _set_db_sync_version(repository, version):"},{"line_number":78,"context_line":"    engine \u003d get_engine()"},{"line_number":79,"context_line":"    migrate_version \u003d db_utils.get_table(engine, repository.version_table)"},{"line_number":80,"context_line":"    migrate_version.update().\\"},{"line_number":81,"context_line":"            where(migrate_version.c.repository_id \u003d\u003d repository.id).\\"},{"line_number":82,"context_line":"            values(version\u003dversion).execute()"},{"line_number":83,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_2b2086f7","line":80,"updated":"2015-03-18 21:00:52.000000000","message":"conn.execute(migrate_verison.update()...)","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"5813209e1de5da725f4ac2fae9c3d2f55799ecb7","unresolved":false,"context_lines":[{"line_number":93,"context_line":"    repository \u003d _find_migrate_repo(database)"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    if _db_sync_locked(repository):"},{"line_number":96,"context_line":"        msg \u003d _(\"Cannot run \u0027db sync\u0027 until \u0027db contract\u0027 is run\")"},{"line_number":97,"context_line":"        raise exception.DatabaseMigrationError(reason\u003dmsg)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    if version is None or version \u003e current_version:"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_aec896a8","line":96,"updated":"2015-03-16 12:09:13.000000000","message":"It seems there are other cases, maybe we need some logs for those other edge cases?\n\nBut we can sort that in a later patch.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":782,"name":"John Garbutt","email":"john@johngarbutt.com","username":"johngarbutt"},"change_message_id":"068ad6e7a3490bf84a51e383e7955c87eba269f7","unresolved":false,"context_lines":[{"line_number":93,"context_line":"    repository \u003d _find_migrate_repo(database)"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    if _db_sync_locked(repository):"},{"line_number":96,"context_line":"        msg \u003d _(\"Cannot run \u0027db sync\u0027 until \u0027db contract\u0027 is run\")"},{"line_number":97,"context_line":"        raise exception.DatabaseMigrationError(reason\u003dmsg)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    if version is None or version \u003e current_version:"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_9b3aed32","line":96,"in_reply_to":"9a80dd14_0a997bd0","updated":"2015-03-17 14:52:49.000000000","message":"OK, my miss read, sorry.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":93,"context_line":"    repository \u003d _find_migrate_repo(database)"},{"line_number":94,"context_line":""},{"line_number":95,"context_line":"    if _db_sync_locked(repository):"},{"line_number":96,"context_line":"        msg \u003d _(\"Cannot run \u0027db sync\u0027 until \u0027db contract\u0027 is run\")"},{"line_number":97,"context_line":"        raise exception.DatabaseMigrationError(reason\u003dmsg)"},{"line_number":98,"context_line":""},{"line_number":99,"context_line":"    if version is None or version \u003e current_version:"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_0a997bd0","line":96,"in_reply_to":"9a80dd14_aec896a8","updated":"2015-03-16 17:17:24.000000000","message":"There shouldn\u0027t be any other cases. \u0027db expand\u0027 sets the lock, \u0027db contract\u0027 removes it.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":165,"context_line":"        conn \u003d context.bind.connect()"},{"line_number":166,"context_line":"        tmp_meta \u003d sqlalchemy.MetaData(conn)"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"        randchars \u003d \u0027\u0027.join(chr(random.randint(0, 255)) for _ in xrange(5))"},{"line_number":169,"context_line":"        tmp_table_name \u003d \u0027reflect_\u0027 + base64.b32encode(randchars).lower()"},{"line_number":170,"context_line":"        tmp_table \u003d sqlalchemy.Table(tmp_table_name, tmp_meta,"},{"line_number":171,"context_line":"                                     sqlalchemy.Column(\u0027a\u0027, metadata_type),"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_ea734c4b","line":168,"updated":"2015-03-16 16:32:23.000000000","message":"Could produce some interesting table names with non-printable characters... Would it be reasonable to restrict to the letters a-z?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"0dbe3ca707e24acda3a9eb26f2b541097231db31","unresolved":false,"context_lines":[{"line_number":165,"context_line":"        conn \u003d context.bind.connect()"},{"line_number":166,"context_line":"        tmp_meta \u003d sqlalchemy.MetaData(conn)"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"        randchars \u003d \u0027\u0027.join(chr(random.randint(0, 255)) for _ in xrange(5))"},{"line_number":169,"context_line":"        tmp_table_name \u003d \u0027reflect_\u0027 + base64.b32encode(randchars).lower()"},{"line_number":170,"context_line":"        tmp_table \u003d sqlalchemy.Table(tmp_table_name, tmp_meta,"},{"line_number":171,"context_line":"                                     sqlalchemy.Column(\u0027a\u0027, metadata_type),"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_4d70b273","line":168,"in_reply_to":"9a80dd14_272e7afb","updated":"2015-03-17 17:37:21.000000000","message":"Whoops, missed that bit. Thanks for pointing it out!","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":165,"context_line":"        conn \u003d context.bind.connect()"},{"line_number":166,"context_line":"        tmp_meta \u003d sqlalchemy.MetaData(conn)"},{"line_number":167,"context_line":""},{"line_number":168,"context_line":"        randchars \u003d \u0027\u0027.join(chr(random.randint(0, 255)) for _ in xrange(5))"},{"line_number":169,"context_line":"        tmp_table_name \u003d \u0027reflect_\u0027 + base64.b32encode(randchars).lower()"},{"line_number":170,"context_line":"        tmp_table \u003d sqlalchemy.Table(tmp_table_name, tmp_meta,"},{"line_number":171,"context_line":"                                     sqlalchemy.Column(\u0027a\u0027, metadata_type),"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_272e7afb","line":168,"in_reply_to":"9a80dd14_ea734c4b","updated":"2015-03-16 17:17:24.000000000","message":"The line immediately underneath this uses base64.b32encode() to ensure it\u0027s only alpha-numeric.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":188,"context_line":"    # And compare any specific attributes about this type"},{"line_number":189,"context_line":"    # TODO(johannes): This should handle dialect specific attributes"},{"line_number":190,"context_line":"    # (eg charset, collation, etc on MySQL VARCHAR type). This is"},{"line_number":191,"context_line":"    # probably best done in alembic correctly"},{"line_number":192,"context_line":"    for attr in (\u0027length\u0027, \u0027display_width\u0027):"},{"line_number":193,"context_line":"        if hasattr(inspector_type, attr):"},{"line_number":194,"context_line":"            if getattr(inspector_type, attr) !\u003d getattr(reflected_type, attr):"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_0aa6e0aa","line":191,"updated":"2015-03-16 16:32:23.000000000","message":"Is \u0027correctly\u0027 the intended term in this sentence?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":188,"context_line":"    # And compare any specific attributes about this type"},{"line_number":189,"context_line":"    # TODO(johannes): This should handle dialect specific attributes"},{"line_number":190,"context_line":"    # (eg charset, collation, etc on MySQL VARCHAR type). This is"},{"line_number":191,"context_line":"    # probably best done in alembic correctly"},{"line_number":192,"context_line":"    for attr in (\u0027length\u0027, \u0027display_width\u0027):"},{"line_number":193,"context_line":"        if hasattr(inspector_type, attr):"},{"line_number":194,"context_line":"            if getattr(inspector_type, attr) !\u003d getattr(reflected_type, attr):"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_e7df02d5","line":191,"in_reply_to":"9a80dd14_0aa6e0aa","updated":"2015-03-16 17:17:24.000000000","message":"Yeah. Alembic is the place for all of the dialect specific stuff. It just doesn\u0027t do that right now.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"6348eb619954f6028f62b3b57d629bd7b91228f6","unresolved":false,"context_lines":[{"line_number":280,"context_line":"        return \u0027\u003cDropTable table_name\u003d%r\u003e\u0027 % self.table.name"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"class AddColumn(OperationBase):"},{"line_number":284,"context_line":"    def __init__(self, table_name, column, desired_phase\u003dNone):"},{"line_number":285,"context_line":"        super(AddColumn, self).__init__()"},{"line_number":286,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_c6d7c5ec","line":283,"updated":"2015-03-19 12:28:09.000000000","message":"Why isn\u0027t AddColumn always safe to be in expand? Something to do with relations/FKs, maybe? I\u0027m wondering... if possible relations to existing columns is the reason this operation isn\u0027t safe for expand, then perhaps a future enhancement may be to decouple the column add from any corresponding relation add -- and do the add column in expand and the add foreign key (or constraint) in migrate? Anyway.. just thoughts, nothing bad with this right now.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"5ebea497d39267eeb7028447b3dfe176f9403a39","unresolved":false,"context_lines":[{"line_number":280,"context_line":"        return \u0027\u003cDropTable table_name\u003d%r\u003e\u0027 % self.table.name"},{"line_number":281,"context_line":""},{"line_number":282,"context_line":""},{"line_number":283,"context_line":"class AddColumn(OperationBase):"},{"line_number":284,"context_line":"    def __init__(self, table_name, column, desired_phase\u003dNone):"},{"line_number":285,"context_line":"        super(AddColumn, self).__init__()"},{"line_number":286,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_881cef67","line":283,"in_reply_to":"9a80dd14_c6d7c5ec","updated":"2015-03-19 15:04:43.000000000","message":"Adding/Dropping of foreign keys is always a separate operation from adding a column.\n\nAdding a column is always semantically safe, but it may lock the table depending on the underlying engine. As a result, this patch is being a little conservative at first. There is further work to take into account the differences between various database engines and move some more operations into the expand/contract phases.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"6348eb619954f6028f62b3b57d629bd7b91228f6","unresolved":false,"context_lines":[{"line_number":309,"context_line":"        self.column_name \u003d column_name"},{"line_number":310,"context_line":"        self.args \u003d args"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self.provides \u003d [(\u0027column\u0027, table_name, column_name)]"},{"line_number":313,"context_line":"        # Cannot alter column with foreign key"},{"line_number":314,"context_line":"        self.conflicts \u003d [(\u0027fkcol\u0027, table_name, column_name)]"},{"line_number":315,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_e6de89d9","line":312,"updated":"2015-03-19 12:28:09.000000000","message":"Unless I\u0027m mistaken, I believe this and self.conflicts should be set()s?","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"5ebea497d39267eeb7028447b3dfe176f9403a39","unresolved":false,"context_lines":[{"line_number":309,"context_line":"        self.column_name \u003d column_name"},{"line_number":310,"context_line":"        self.args \u003d args"},{"line_number":311,"context_line":""},{"line_number":312,"context_line":"        self.provides \u003d [(\u0027column\u0027, table_name, column_name)]"},{"line_number":313,"context_line":"        # Cannot alter column with foreign key"},{"line_number":314,"context_line":"        self.conflicts \u003d [(\u0027fkcol\u0027, table_name, column_name)]"},{"line_number":315,"context_line":""}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_88a14ff9","line":312,"in_reply_to":"9a80dd14_e6de89d9","updated":"2015-03-19 15:04:43.000000000","message":"To be consistent with the rest of the code, it should be set()s, but there is no practical difference between using a list and a set in the way the coded uses .provides and .conflicts.\n\nI\u0027ll make sure I get this cleaned up.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":11816,"name":"mike bayer","display_name":"Mike Bayer","email":"mike_mp@zzzcomputing.com","username":"zzzeek","status":"Red Hat"},"change_message_id":"6ce8f68a3ca29eee9c0d1a0bc51fcfdb4a1a64e0","unresolved":false,"context_lines":[{"line_number":621,"context_line":"        return False"},{"line_number":622,"context_line":""},{"line_number":623,"context_line":"    return True"},{"line_number":624,"context_line":""},{"line_number":625,"context_line":""},{"line_number":626,"context_line":"class Converter(object):"},{"line_number":627,"context_line":"    def _handle_add_table(self, table):"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_2b4ec6c2","line":624,"updated":"2015-03-18 21:00:52.000000000","message":"these comparison functions might be in alembic?   or we can make them public?   shrugs","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"6348eb619954f6028f62b3b57d629bd7b91228f6","unresolved":false,"context_lines":[{"line_number":649,"context_line":"        yield tblop"},{"line_number":650,"context_line":""},{"line_number":651,"context_line":"        for fkc in _table_fk_constraints(table):"},{"line_number":652,"context_line":"            yield DropForeignKey(fkc, desired_phase\u003dtblop.desired_phase)"},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"    def _handle_add_column(self, schema, table_name, column):"},{"line_number":655,"context_line":"        # (\u0027add_column\u0027, schema, table_name, Column)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_a1ac7bee","line":652,"updated":"2015-03-19 12:28:09.000000000","message":"Don\u0027t the foreign keys need to be dropped *before* the table that they reference? :)","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"5ebea497d39267eeb7028447b3dfe176f9403a39","unresolved":false,"context_lines":[{"line_number":649,"context_line":"        yield tblop"},{"line_number":650,"context_line":""},{"line_number":651,"context_line":"        for fkc in _table_fk_constraints(table):"},{"line_number":652,"context_line":"            yield DropForeignKey(fkc, desired_phase\u003dtblop.desired_phase)"},{"line_number":653,"context_line":""},{"line_number":654,"context_line":"    def _handle_add_column(self, schema, table_name, column):"},{"line_number":655,"context_line":"        # (\u0027add_column\u0027, schema, table_name, Column)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_08ff1fac","line":652,"in_reply_to":"9a80dd14_a1ac7bee","updated":"2015-03-19 15:04:43.000000000","message":"The FK drops need to be *executed* before the table drop, but it makes no difference what order they are added into the scheduler.\n\nThe schedule forms a Directed Acyclic Graph using the dependency information (op.depends). A topological sort is done on the graph to ensure that the operations are executed in the correct order.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":762,"context_line":"        return ops"},{"line_number":763,"context_line":""},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"class Scheduler(object):"},{"line_number":766,"context_line":"    def __init__(self, ops\u003dNone):"},{"line_number":767,"context_line":"        # Set of operations (vertexes)"},{"line_number":768,"context_line":"        self.ops \u003d set()"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_05a33343","line":765,"updated":"2015-03-16 16:32:23.000000000","message":"It would be nice to have some unit tests for this class.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":762,"context_line":"        return ops"},{"line_number":763,"context_line":""},{"line_number":764,"context_line":""},{"line_number":765,"context_line":"class Scheduler(object):"},{"line_number":766,"context_line":"    def __init__(self, ops\u003dNone):"},{"line_number":767,"context_line":"        # Set of operations (vertexes)"},{"line_number":768,"context_line":"        self.ops \u003d set()"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_eab3474b","line":765,"in_reply_to":"9a80dd14_05a33343","updated":"2015-03-16 17:17:24.000000000","message":"There are some already. I\u0027ll look and see if there are some gaps where more unit tests could help.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":865,"context_line":""},{"line_number":866,"context_line":"            del inbound[op]"},{"line_number":867,"context_line":""},{"line_number":868,"context_line":"        # Anything remaining in inbound is a dependency loop"},{"line_number":869,"context_line":"        if inbound:"},{"line_number":870,"context_line":"            msg \u003d _(\u0027Dependency loop exists in database migrations\u0027)"},{"line_number":871,"context_line":"            raise exception.DatabaseMigrationError(reason\u003dmsg)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_20d2e55b","line":868,"updated":"2015-03-16 16:32:23.000000000","message":"I\u0027m probably overlooking it, but what is the definition of a dependency loop in this context (e.g., a sequence of foreign keys that reference each other)? If is isn\u0027t stated in this file, then it probably should be for the benefit of others who might encounter this exception at some point.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":865,"context_line":""},{"line_number":866,"context_line":"            del inbound[op]"},{"line_number":867,"context_line":""},{"line_number":868,"context_line":"        # Anything remaining in inbound is a dependency loop"},{"line_number":869,"context_line":"        if inbound:"},{"line_number":870,"context_line":"            msg \u003d _(\u0027Dependency loop exists in database migrations\u0027)"},{"line_number":871,"context_line":"            raise exception.DatabaseMigrationError(reason\u003dmsg)"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_67b95279","line":868,"in_reply_to":"9a80dd14_20d2e55b","updated":"2015-03-16 17:17:24.000000000","message":"It\u0027s not actually foreign keys referencing tables in a loop. New tables will be broken down into CREATE TABLE and ALTER TABLE ADD FOREIGN KEY statements. The ALTER TABLE would have a dependency on to the CREATE TABLE. As a result, the operations would be scheduled to create both tables and then create the foreign keys.\n\nThe dependencies we track are to ensure the correct order of the operations.\n\nFor instance, in some cases we need to drop foreign keys to alter columns. We need to ensure that the alter column is ordered before the foreign key create and the foreign key drop is ordered before the alter column.\n\n(eg drop foreign key -\u003e alter column -\u003e add foreign key)\n\nIf there is a bug with creating these dependencies in such a way that a loop is formed, then this would then raise an exception here.","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"828d63cc15fa38b1e90da7db963a11c7d880606e","unresolved":false,"context_lines":[{"line_number":855,"context_line":"        # The topological sort modifies inbound, but we can\u0027t do a deepcopy"},{"line_number":856,"context_line":"        # since that would deepcopy the key too."},{"line_number":857,"context_line":"        inbound \u003d {}"},{"line_number":858,"context_line":"        for key, depends in self.inbound.iteritems():"},{"line_number":859,"context_line":"            inbound[key] \u003d set(depends)"},{"line_number":860,"context_line":""},{"line_number":861,"context_line":"        toprocess \u003d [v for v in self.ops if not inbound[v]]"}],"source_content_type":"text/x-python","patch_set":17,"id":"1af86dd1_196d8d98","line":858,"updated":"2015-06-15 16:04:00.000000000","message":"This should probably be converted to items(), given the discussion currently raging on the list.","commit_id":"5dee3387a1ed44fe2d246693af575855c3193e57"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"828d63cc15fa38b1e90da7db963a11c7d880606e","unresolved":false,"context_lines":[{"line_number":910,"context_line":"        self.order_drop_add()"},{"line_number":911,"context_line":""},{"line_number":912,"context_line":"        # Use mapping to create edges between operations"},{"line_number":913,"context_line":"        for op, depends in self.depends.iteritems():"},{"line_number":914,"context_line":"            if op.removes:"},{"line_number":915,"context_line":"                mapping \u003d self.nonexists"},{"line_number":916,"context_line":"            else:"}],"source_content_type":"text/x-python","patch_set":17,"id":"1af86dd1_59fae5be","line":913,"updated":"2015-06-15 16:04:00.000000000","message":"another case of iteritems()","commit_id":"5dee3387a1ed44fe2d246693af575855c3193e57"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":70,"context_line":""},{"line_number":71,"context_line":""},{"line_number":72,"context_line":"def _set_db_sync_lock(repository, locked):"},{"line_number":73,"context_line":"    locked \u003d locked and 1 or 0"},{"line_number":74,"context_line":""},{"line_number":75,"context_line":"    engine \u003d get_engine()"},{"line_number":76,"context_line":"    migrate_version \u003d db_utils.get_table(engine, repository.version_table)"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_89457db4","line":73,"updated":"2015-06-15 20:12:05.000000000","message":"attonit: could this be changed to:\n\n    locked \u003d bool(locked)\n\n?","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":197,"context_line":"    # probably best done in alembic correctly"},{"line_number":198,"context_line":"    for attr in (\u0027length\u0027, \u0027display_width\u0027):"},{"line_number":199,"context_line":"        if hasattr(inspector_type, attr):"},{"line_number":200,"context_line":"            if getattr(inspector_type, attr) !\u003d getattr(reflected_type, attr):"},{"line_number":201,"context_line":"                return True"},{"line_number":202,"context_line":""},{"line_number":203,"context_line":"    return False"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_0902cd6f","line":200,"updated":"2015-06-15 20:12:05.000000000","message":"femtonit: it looks like the two \u0027if\u0027s can be combined into one.","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":596,"context_line":""},{"line_number":597,"context_line":""},{"line_number":598,"context_line":"def _fkc_matches_key(metadata, ckey):"},{"line_number":599,"context_line":"    for table in metadata.tables.itervalues():"},{"line_number":600,"context_line":"        for fkc in _table_fk_constraints(table):"},{"line_number":601,"context_line":"            fk \u003d fkc.elements[0]"},{"line_number":602,"context_line":"            src_table_name \u003d fk.parent.table.name"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_294b1189","line":599,"updated":"2015-06-15 20:12:05.000000000","message":"Use of itervalues()…","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":692,"context_line":"        # Include any dialect specific options (mysql_length, etc)"},{"line_number":693,"context_line":"        args \u003d {}"},{"line_number":694,"context_line":"        for dialect, options in index.dialect_options.iteritems():"},{"line_number":695,"context_line":"            for k, v in options.iteritems():"},{"line_number":696,"context_line":"                args[\u0027%s_%s\u0027 % (dialect, k)] \u003d v"},{"line_number":697,"context_line":""},{"line_number":698,"context_line":"        yield AddIndex(index, args)"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_29323111","line":695,"updated":"2015-06-15 20:12:05.000000000","message":"Use if iteritems() (both loops)","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":881,"context_line":"    def order_drop_add(self):"},{"line_number":882,"context_line":"        # Alembic will emit drop/add for indexes if the covered columns change."},{"line_number":883,"context_line":"        # Ensure that the add is scheduled after the drop."},{"line_number":884,"context_line":"        keys \u003d set(self.exists.iterkeys()) \u0026 set(self.nonexists.iterkeys())"},{"line_number":885,"context_line":"        for key in keys:"},{"line_number":886,"context_line":"            dropops \u003d self.nonexists[key]"},{"line_number":887,"context_line":"            addops \u003d self.exists[key]"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_e93be9e9","line":884,"updated":"2015-06-15 20:12:05.000000000","message":"Use of iterkeys()","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"},{"author":{"_account_id":679,"name":"Kevin L. Mitchell","email":"klmitch@mit.edu","username":"klmitch"},"change_message_id":"ebca5b06bbcaef6d1dfb21219dad655ce2202ca6","unresolved":false,"context_lines":[{"line_number":959,"context_line":""},{"line_number":960,"context_line":"def _add_generated_tables_to_model(metadata, database\u003d\u0027main\u0027):"},{"line_number":961,"context_line":"    tables \u003d dict(metadata.tables)"},{"line_number":962,"context_line":"    for table_name, table in tables.iteritems():"},{"line_number":963,"context_line":"        if table_name.startswith(\u0027shadow_\u0027) or _ignore_table(table_name):"},{"line_number":964,"context_line":"            # Don\u0027t make a shadow of a shadow table or a table we"},{"line_number":965,"context_line":"            # explicitly ignore"}],"source_content_type":"text/x-python","patch_set":18,"id":"fa32b979_69303902","line":962,"updated":"2015-06-15 20:12:05.000000000","message":"Use of iteritems()","commit_id":"758041cda6b129863ffd4e26aa4344bae1974ccf"}],"nova/db/sqlalchemy/models.py":[{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"6348eb619954f6028f62b3b57d629bd7b91228f6","unresolved":false,"context_lines":[{"line_number":781,"context_line":"    __table_args__ \u003d ("},{"line_number":782,"context_line":"        Index(\u0027migrations_instance_uuid_and_status_idx\u0027, \u0027deleted\u0027,"},{"line_number":783,"context_line":"              \u0027instance_uuid\u0027, \u0027status\u0027),"},{"line_number":784,"context_line":"        # MySQL has a limit of 3072 bytes for an multi-column index. This"},{"line_number":785,"context_line":"        # index ends up being larger than that using the utf-8 encoding."},{"line_number":786,"context_line":"        # Limiting the index to the prefixes will keep it under the limit."},{"line_number":787,"context_line":"        # FIXME: Is it MySQL or InnoDB that imposes the limit?"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_6114434d","line":784,"updated":"2015-03-19 12:28:09.000000000","message":"nit: s/an/a/","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6802,"name":"Joel Coffman","email":"jmc7tp@gmail.com","username":"joel-coffman"},"change_message_id":"124389163793d971535277d3f1971c8875d5f853","unresolved":false,"context_lines":[{"line_number":784,"context_line":"        # MySQL has a limit of 3072 bytes for an multi-column index. This"},{"line_number":785,"context_line":"        # index ends up being larger than that using the utf-8 encoding."},{"line_number":786,"context_line":"        # Limiting the index to the prefixes will keep it under the limit."},{"line_number":787,"context_line":"        # FIXME: Is it MySQL or InnoDB that imposes the limit?"},{"line_number":788,"context_line":"        Index(\u0027migrations_by_host_nodes_and_status_idx\u0027, \u0027deleted\u0027,"},{"line_number":789,"context_line":"              \u0027source_compute\u0027, \u0027dest_compute\u0027, \u0027source_node\u0027, \u0027dest_node\u0027,"},{"line_number":790,"context_line":"              \u0027status\u0027, mysql_length\u003d{\u0027source_compute\u0027: 100,"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_0565f3ad","line":787,"updated":"2015-03-16 16:32:23.000000000","message":"Looks like a MySQL limitation (see http://dev.mysql.com/doc/refman/5.7/en/innodb-restrictions.html):\n\n\u003e The InnoDB internal maximum key length is 3500 bytes, but MySQL itself restricts this to 3072 bytes. This limit applies to the length of the combined index key in a multi-column index.\n\nNote that the innodb_large_prefix option must be set or else the limit is 767 bytes (http://dev.mysql.com/doc/refman/5.7/en/innodb-parameters.html#sysvar_innodb_large_prefix).","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0f6c241f60acce8e24c8a218b25bd04e97c50539","unresolved":false,"context_lines":[{"line_number":784,"context_line":"        # MySQL has a limit of 3072 bytes for an multi-column index. This"},{"line_number":785,"context_line":"        # index ends up being larger than that using the utf-8 encoding."},{"line_number":786,"context_line":"        # Limiting the index to the prefixes will keep it under the limit."},{"line_number":787,"context_line":"        # FIXME: Is it MySQL or InnoDB that imposes the limit?"},{"line_number":788,"context_line":"        Index(\u0027migrations_by_host_nodes_and_status_idx\u0027, \u0027deleted\u0027,"},{"line_number":789,"context_line":"              \u0027source_compute\u0027, \u0027dest_compute\u0027, \u0027source_node\u0027, \u0027dest_node\u0027,"},{"line_number":790,"context_line":"              \u0027status\u0027, mysql_length\u003d{\u0027source_compute\u0027: 100,"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_2a02bf09","line":787,"in_reply_to":"9a80dd14_0565f3ad","updated":"2015-03-16 17:17:24.000000000","message":"I\u0027ll update this comment. Thanks","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"},{"author":{"_account_id":6873,"name":"Matt Riedemann","email":"mriedem.os@gmail.com","username":"mriedem"},"change_message_id":"e8e0b33a6cec596e40fe6aa9563e1d175ac5ed7d","unresolved":false,"context_lines":[{"line_number":718,"context_line":"        # MySQL has a limit of 3072 bytes for an multi-column index. This"},{"line_number":719,"context_line":"        # index ends up being larger than that using the utf-8 encoding."},{"line_number":720,"context_line":"        # Limiting the index to the prefixes will keep it under the limit."},{"line_number":721,"context_line":"        # FIXME: Is it MySQL or InnoDB that imposes the limit?"},{"line_number":722,"context_line":"        Index(\u0027migrations_by_host_nodes_and_status_idx\u0027, \u0027deleted\u0027,"},{"line_number":723,"context_line":"              \u0027source_compute\u0027, \u0027dest_compute\u0027, \u0027source_node\u0027, \u0027dest_node\u0027,"},{"line_number":724,"context_line":"              \u0027status\u0027, mysql_length\u003d{\u0027source_compute\u0027: 100,"}],"source_content_type":"text/x-python","patch_set":14,"id":"7a016987_fe179e42","line":721,"updated":"2015-05-21 22:25:28.000000000","message":"FIXME(jerdfelt)?","commit_id":"b748f22ebba257ba78f7c182701762ad3cae2839"}],"nova/tests/unit/db/test_migrations.py":[{"author":{"_account_id":10618,"name":"Pavel Kholkin","email":"p.v.holkin@mail.ru","username":"pkholkin"},"change_message_id":"ba6da885445da2e7a5233416eb8947846d12d675","unresolved":false,"context_lines":[{"line_number":878,"context_line":"        scheduler.add(dropidx)"},{"line_number":879,"context_line":""},{"line_number":880,"context_line":"        expand, migrate, contract \u003d scheduler.schedule()"},{"line_number":881,"context_line":"        self.assertEqual(expand, [])"},{"line_number":882,"context_line":"        self.assertEqual(migrate, [dropidx, addidx])"},{"line_number":883,"context_line":"        self.assertEqual(contract, [])"},{"line_number":884,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"da86d52c_aba85fdc","line":881,"updated":"2015-02-13 16:26:08.000000000","message":"To provide better debug message if assert fails it would be better to swap arguments to:\n\nassertEqual(expected, actual)","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"4f3f50878c7bbe815828350788527361dc18e748","unresolved":false,"context_lines":[{"line_number":878,"context_line":"        scheduler.add(dropidx)"},{"line_number":879,"context_line":""},{"line_number":880,"context_line":"        expand, migrate, contract \u003d scheduler.schedule()"},{"line_number":881,"context_line":"        self.assertEqual(expand, [])"},{"line_number":882,"context_line":"        self.assertEqual(migrate, [dropidx, addidx])"},{"line_number":883,"context_line":"        self.assertEqual(contract, [])"},{"line_number":884,"context_line":""}],"source_content_type":"text/x-python","patch_set":2,"id":"da86d52c_4d230905","line":881,"in_reply_to":"da86d52c_aba85fdc","updated":"2015-02-17 21:08:41.000000000","message":"Done","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"1b1f894c8ed2c5b16db5f195923d6db7fba2c5e1","unresolved":false,"context_lines":[{"line_number":1025,"context_line":""},{"line_number":1026,"context_line":"        table \u003d oslodbutils.get_table(self.engine, \u0027a\u0027)"},{"line_number":1027,"context_line":"        if self.engine.dialect.name \u003d\u003d \u0027mysql\u0027:"},{"line_number":1028,"context_line":"            # MySQL transparently creates unique constraints as unique"},{"line_number":1029,"context_line":"            # indexes"},{"line_number":1030,"context_line":"            indexes \u003d {i.name: i for i in table.indexes}"},{"line_number":1031,"context_line":"            self.assertIn(\u0027uniq_a_id\u0027, indexes)"}],"source_content_type":"text/x-python","patch_set":2,"id":"da86d52c_37e77b48","line":1028,"updated":"2015-02-13 14:51:00.000000000","message":"AFAIK, postgresql creates UC in the same way, so you can try to check uniques in a same way for the both databases \n\n phidatdltp\u003d\u003e \\d a;\n        Table \"public.a\"\n  Column |  Type   | Modifiers \n --------+---------+-----------\n  id     | integer | \n Indexes:\n     \"uniq_a_id\" UNIQUE CONSTRAINT, btree (id)","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"4f3f50878c7bbe815828350788527361dc18e748","unresolved":false,"context_lines":[{"line_number":1025,"context_line":""},{"line_number":1026,"context_line":"        table \u003d oslodbutils.get_table(self.engine, \u0027a\u0027)"},{"line_number":1027,"context_line":"        if self.engine.dialect.name \u003d\u003d \u0027mysql\u0027:"},{"line_number":1028,"context_line":"            # MySQL transparently creates unique constraints as unique"},{"line_number":1029,"context_line":"            # indexes"},{"line_number":1030,"context_line":"            indexes \u003d {i.name: i for i in table.indexes}"},{"line_number":1031,"context_line":"            self.assertIn(\u0027uniq_a_id\u0027, indexes)"}],"source_content_type":"text/x-python","patch_set":2,"id":"da86d52c_73b51031","line":1028,"in_reply_to":"da86d52c_37e77b48","updated":"2015-02-17 21:08:41.000000000","message":"That\u0027s not quite what I meant.\n\nIn MySQL, creating a unique constraint will appear as a unique index upon reflection:\n\n  mysql\u003e create table foo (a int not null, b int not null);\n  Query OK, 0 rows affected (0.01 sec)\n\n  mysql\u003e create unique index foo_a_uniq on foo(a);\n  Query OK, 0 rows affected (0.03 sec)\n  Records: 0  Duplicates: 0  Warnings: 0\n\n  mysql\u003e alter table foo add constraint foo_b_uniq unique (b);\n  Query OK, 0 rows affected (0.02 sec)\n  Records: 0  Duplicates: 0  Warnings: 0\n\n  mysql\u003e show create table foo;\n  CREATE TABLE `foo` (\n    `a` int(11) NOT NULL,\n    `b` int(11) NOT NULL,\n    UNIQUE KEY `foo_a_uniq` (`a`),\n    UNIQUE KEY `foo_b_uniq` (`b`)\n  ) ENGINE\u003dInnoDB DEFAULT CHARSET\u003dutf8 |\n  1 row in set (0.00 sec)\n\nYou can see that unique constraints are indistinguishable from unique indexes in MySQL. They are the same thing.\n\nHowever, they are different in PostgreSQL:\n\n  test_unique\u003d# create table foo (a int not null, b int not null);        \n  CREATE TABLE\n  test_unique\u003d# create unique index foo_a_uniq on foo (a);\n  CREATE INDEX\n  test_unique\u003d# alter table foo add constraint foo_b_uniq unique (b);\n  NOTICE:  ALTER TABLE / ADD UNIQUE will create implicit index \"foo_b_uniq\" for table \"foo\"\n  ALTER TABLE\n\n  $ pg_dump -st foo test_unique\n  # Some insignificant details elided\n  CREATE TABLE foo (\n      a integer NOT NULL,\n      b integer NOT NULL\n  );\n\n  --\n  -- Name: foo_b_uniq; Type: CONSTRAINT; Schema: public; Owner: postgres; Tablespace: \n  --\n  ALTER TABLE ONLY foo ADD CONSTRAINT foo_b_uniq UNIQUE (b);\n\n  --\n  -- Name: foo_a_uniq; Type: INDEX; Schema: public; Owner: postgres; Tablespace: \n  --\n  CREATE UNIQUE INDEX foo_a_uniq ON foo USING btree (a);\n\nThis difference shows up when reflecting the schema from the database, which is what this code is trying to deal with.\n\nI may try to make the code more generic and look for both unique indexes and constraints and avoid any dialect specific code.","commit_id":"6d490266a13a80ac0d9c9affedb5882dce85ee1d"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"9757812f418d8724868d327fb5e11bfd9853c94a","unresolved":false,"context_lines":[{"line_number":1101,"context_line":"        meta \u003d sqlalchemy.MetaData()"},{"line_number":1102,"context_line":"        a \u003d sqlalchemy.Table(\u0027a\u0027, meta,"},{"line_number":1103,"context_line":"                             sqlalchemy.Column(\u0027id\u0027, sqlalchemy.Integer),"},{"line_number":1104,"context_line":"                             sqlalchemy.UniqueConstraint(\u0027id\u0027))"},{"line_number":1105,"context_line":"        b \u003d sqlalchemy.Table(\u0027b\u0027, meta,"},{"line_number":1106,"context_line":"                             sqlalchemy.Column(\u0027a_id\u0027, sqlalchemy.Integer))"},{"line_number":1107,"context_line":"        meta.create_all(self.engine)"}],"source_content_type":"text/x-python","patch_set":8,"id":"ba7be1f8_c003b471","line":1104,"updated":"2015-02-20 10:27:05.000000000","message":"Default MySQL engine on gates is MyISAM and this engine don\u0027t support foreign keys. So assertion ``self.assertIn(\u0027b_a_id_fk\u0027, fkcs)`` fails. Please add ``mysql_engine\u003d\u0027InnoDB\u0027`` to table to avoid of this issue, this should help.","commit_id":"8976c46c6ef7d3f6451d7ee07a3b11e67e50c3f7"},{"author":{"_account_id":100,"name":"Johannes Erdfelt","email":"johannes@erdfelt.com","username":"johannes.erdfelt"},"change_message_id":"0a2ffe63871f5f98b1703f26ef7161647dea55fb","unresolved":false,"context_lines":[{"line_number":1101,"context_line":"        meta \u003d sqlalchemy.MetaData()"},{"line_number":1102,"context_line":"        a \u003d sqlalchemy.Table(\u0027a\u0027, meta,"},{"line_number":1103,"context_line":"                             sqlalchemy.Column(\u0027id\u0027, sqlalchemy.Integer),"},{"line_number":1104,"context_line":"                             sqlalchemy.UniqueConstraint(\u0027id\u0027))"},{"line_number":1105,"context_line":"        b \u003d sqlalchemy.Table(\u0027b\u0027, meta,"},{"line_number":1106,"context_line":"                             sqlalchemy.Column(\u0027a_id\u0027, sqlalchemy.Integer))"},{"line_number":1107,"context_line":"        meta.create_all(self.engine)"}],"source_content_type":"text/x-python","patch_set":8,"id":"ba7be1f8_0b232406","line":1104,"in_reply_to":"ba7be1f8_c003b471","updated":"2015-02-20 15:34:54.000000000","message":"Ugh, thank you for that.\n\nI completely overlooked that (and it\u0027s right there in the debugging that I added). I also overlooked it while looking at the nodepool setup scripts:\n\nhttps://github.com/openstack-infra/system-config/blob/master/modules/openstack_project/manifests/slave_db.pp\n\nThe fact that MyISAM doesn\u0027t support FKs, but the implicit key got created really threw me for a loop.","commit_id":"8976c46c6ef7d3f6451d7ee07a3b11e67e50c3f7"},{"author":{"_account_id":7491,"name":"Viktor Serhieiev","email":"viktor.sergeyev@gmail.com","username":"vsergeyev"},"change_message_id":"9757812f418d8724868d327fb5e11bfd9853c94a","unresolved":false,"context_lines":[{"line_number":1103,"context_line":"                             sqlalchemy.Column(\u0027id\u0027, sqlalchemy.Integer),"},{"line_number":1104,"context_line":"                             sqlalchemy.UniqueConstraint(\u0027id\u0027))"},{"line_number":1105,"context_line":"        b \u003d sqlalchemy.Table(\u0027b\u0027, meta,"},{"line_number":1106,"context_line":"                             sqlalchemy.Column(\u0027a_id\u0027, sqlalchemy.Integer))"},{"line_number":1107,"context_line":"        meta.create_all(self.engine)"},{"line_number":1108,"context_line":""},{"line_number":1109,"context_line":"        # DEBUG"}],"source_content_type":"text/x-python","patch_set":8,"id":"ba7be1f8_e0f7d88a","line":1106,"updated":"2015-02-20 10:27:05.000000000","message":"ditto","commit_id":"8976c46c6ef7d3f6451d7ee07a3b11e67e50c3f7"},{"author":{"_account_id":7,"name":"Jay Pipes","email":"jaypipes@gmail.com","username":"jaypipes"},"change_message_id":"6348eb619954f6028f62b3b57d629bd7b91228f6","unresolved":false,"context_lines":[{"line_number":1170,"context_line":""},{"line_number":1171,"context_line":"        table \u003d oslodbutils.get_table(self.engine, \u0027b\u0027)"},{"line_number":1172,"context_line":"        fkcs \u003d {c.name: c for c in table.constraints}"},{"line_number":1173,"context_line":"        self.assertNotIn(\u0027b_a_id_fk\u0027, fkcs)"},{"line_number":1174,"context_line":""},{"line_number":1175,"context_line":""},{"line_number":1176,"context_line":"class TestSchemaChangeDDLMySQL(SchemaChangeDDLCheckers,"}],"source_content_type":"text/x-python","patch_set":12,"id":"9a80dd14_bcbade08","line":1173,"updated":"2015-03-19 12:28:09.000000000","message":"Please add a unit test that stresses a DROP TABLE DDL command *when the table has foreign key constraints referencing it*. I believe you will hit an issue due to the table being dropped before the FKs are...","commit_id":"04ddf7e4707c2714c8f94531e9f0ec359a2852af"}]}
