Repository navigation
Fix db migrate failure to Airflow 2.9.2 under PyMySQL driver - #70235
vatsrahul1001 merged 5 commits into
Conversation
|
Added a newsfragment for the release notes. |
977c6d0 to
3caee08
Compare
1fanwang
left a comment
There was a problem hiding this comment.
LGTM overall, thanks for addressing this issue.
Verified on MySQL 8.4 the original dynamic SQL works under mysqlclient and fails under PyMySQL.
Upgrading through revision 686269002441 raised pymysql.err.ProgrammingError because the migration used MySQL's PREPARE/EXECUTE/DEALLOCATE PREPARE dynamic SQL to conditionally drop unique constraints, which PyMySQL's driver does not support (see PyMySQL/PyMySQL#202). Replaced with a plain lookup of existing constraints from information_schema.TABLE_CONSTRAINTS followed by conditional ALTER TABLE ... DROP INDEX statements, which works with any MySQL driver. Verified against a real MySQL/PyMySQL backend: downgrading to bff083ad727d and re-running db migrate now completes without error. closes: apache#43690
The PyMySQL online-mode fix in this migration queries information_schema.TABLE_CONSTRAINTS via conn.execute() to decide which legacy unique constraints to drop. In Alembic's offline (--sql) mode there is no live connection, so conn.execute() returns None and iterating over it raises TypeError, breaking the CI "Test offline migration" step. Guard the query-then-conditionally-drop logic behind context.is_offline_mode(), falling back to the original dynamic prepare/execute/deallocate SQL text for the offline branch, since that text is only ever emitted as script output there rather than executed directly.
Bind the table name as a query parameter in the information_schema lookup instead of interpolating it into the SQL string, since it's a value comparison rather than an identifier — matches Airflow's usual parameter-binding convention even though every call site currently passes a hardcoded literal. Also correct the docstring: PyMySQL can run a bare PREPARE statement fine, what it actually can't do is send more than one statement per cursor.execute() call, because it never enables CLIENT.MULTI_STATEMENTS.
3caee08 to
e792ca7
Compare
uranusjr
left a comment
There was a problem hiding this comment.
I think we can call SELECT ... FROM information_schema.TABLE_CONSTRAINTS less in both upgrade in downgrade. But this looks good to me in general. (Five-ish extra calls in a migration won’t destroy the world.)
1fanwang
left a comment
There was a problem hiding this comment.
thank you! I hit the same bug while doing airflow 2->3 upgrade in our infra and this is the same approach I took
stamping my approval again but you'd need committer/PMC who has approval/merge access
Backport successfully created: v3-3-testNote: As of Merging PRs targeted for Airflow 3.X In matter of doubt please ask in #release-management Slack channel.
|
…ver (#70235) (#72613) * Fix db migrate failure to Airflow 2.9.2 under PyMySQL driver Upgrading through revision 686269002441 raised pymysql.err.ProgrammingError because the migration used MySQL's PREPARE/EXECUTE/DEALLOCATE PREPARE dynamic SQL to conditionally drop unique constraints, which PyMySQL's driver does not support (see PyMySQL/PyMySQL#202). Replaced with a plain lookup of existing constraints from information_schema.TABLE_CONSTRAINTS followed by conditional ALTER TABLE ... DROP INDEX statements, which works with any MySQL driver. Verified against a real MySQL/PyMySQL backend: downgrading to bff083ad727d and re-running db migrate now completes without error. closes: #43690 * Add newsfragment for MySQL PyMySQL migration fix * Fix offline migration for 2.9.2 ORM-consistency revision The PyMySQL online-mode fix in this migration queries information_schema.TABLE_CONSTRAINTS via conn.execute() to decide which legacy unique constraints to drop. In Alembic's offline (--sql) mode there is no live connection, so conn.execute() returns None and iterating over it raises TypeError, breaking the CI "Test offline migration" step. Guard the query-then-conditionally-drop logic behind context.is_offline_mode(), falling back to the original dynamic prepare/execute/deallocate SQL text for the offline branch, since that text is only ever emitted as script output there rather than executed directly. * Address review feedback on MySQL PyMySQL migration fix Bind the table name as a query parameter in the information_schema lookup instead of interpolating it into the SQL string, since it's a value comparison rather than an identifier — matches Airflow's usual parameter-binding convention even though every call site currently passes a hardcoded literal. Also correct the docstring: PyMySQL can run a bare PREPARE statement fine, what it actually can't do is send more than one statement per cursor.execute() call, because it never enables CLIENT.MULTI_STATEMENTS. * Fixed the PR comments (cherry picked from commit 08e428c) Co-authored-by: Aaryan Mahajan <aaryanmhjn@gmail.com> Co-authored-by: Rahul Vats <43964496+vatsrahul1001@users.noreply.github.com>
…70235) * Fix db migrate failure to Airflow 2.9.2 under PyMySQL driver Upgrading through revision 686269002441 raised pymysql.err.ProgrammingError because the migration used MySQL's PREPARE/EXECUTE/DEALLOCATE PREPARE dynamic SQL to conditionally drop unique constraints, which PyMySQL's driver does not support (see PyMySQL/PyMySQL#202). Replaced with a plain lookup of existing constraints from information_schema.TABLE_CONSTRAINTS followed by conditional ALTER TABLE ... DROP INDEX statements, which works with any MySQL driver. Verified against a real MySQL/PyMySQL backend: downgrading to bff083ad727d and re-running db migrate now completes without error. closes: apache#43690 * Add newsfragment for MySQL PyMySQL migration fix * Fix offline migration for 2.9.2 ORM-consistency revision The PyMySQL online-mode fix in this migration queries information_schema.TABLE_CONSTRAINTS via conn.execute() to decide which legacy unique constraints to drop. In Alembic's offline (--sql) mode there is no live connection, so conn.execute() returns None and iterating over it raises TypeError, breaking the CI "Test offline migration" step. Guard the query-then-conditionally-drop logic behind context.is_offline_mode(), falling back to the original dynamic prepare/execute/deallocate SQL text for the offline branch, since that text is only ever emitted as script output there rather than executed directly. * Address review feedback on MySQL PyMySQL migration fix Bind the table name as a query parameter in the information_schema lookup instead of interpolating it into the SQL string, since it's a value comparison rather than an identifier — matches Airflow's usual parameter-binding convention even though every call site currently passes a hardcoded literal. Also correct the docstring: PyMySQL can run a bare PREPARE statement fine, what it actually can't do is send more than one statement per cursor.execute() call, because it never enables CLIENT.MULTI_STATEMENTS. * Fixed the PR comments
…70235) * Fix db migrate failure to Airflow 2.9.2 under PyMySQL driver Upgrading through revision 686269002441 raised pymysql.err.ProgrammingError because the migration used MySQL's PREPARE/EXECUTE/DEALLOCATE PREPARE dynamic SQL to conditionally drop unique constraints, which PyMySQL's driver does not support (see PyMySQL/PyMySQL#202). Replaced with a plain lookup of existing constraints from information_schema.TABLE_CONSTRAINTS followed by conditional ALTER TABLE ... DROP INDEX statements, which works with any MySQL driver. Verified against a real MySQL/PyMySQL backend: downgrading to bff083ad727d and re-running db migrate now completes without error. closes: apache#43690 * Add newsfragment for MySQL PyMySQL migration fix * Fix offline migration for 2.9.2 ORM-consistency revision The PyMySQL online-mode fix in this migration queries information_schema.TABLE_CONSTRAINTS via conn.execute() to decide which legacy unique constraints to drop. In Alembic's offline (--sql) mode there is no live connection, so conn.execute() returns None and iterating over it raises TypeError, breaking the CI "Test offline migration" step. Guard the query-then-conditionally-drop logic behind context.is_offline_mode(), falling back to the original dynamic prepare/execute/deallocate SQL text for the offline branch, since that text is only ever emitted as script output there rather than executed directly. * Address review feedback on MySQL PyMySQL migration fix Bind the table name as a query parameter in the information_schema lookup instead of interpolating it into the SQL string, since it's a value comparison rather than an identifier — matches Airflow's usual parameter-binding convention even though every call site currently passes a hardcoded literal. Also correct the docstring: PyMySQL can run a bare PREPARE statement fine, what it actually can't do is send more than one statement per cursor.execute() call, because it never enables CLIENT.MULTI_STATEMENTS. * Fixed the PR comments
…70235) * Fix db migrate failure to Airflow 2.9.2 under PyMySQL driver Upgrading through revision 686269002441 raised pymysql.err.ProgrammingError because the migration used MySQL's PREPARE/EXECUTE/DEALLOCATE PREPARE dynamic SQL to conditionally drop unique constraints, which PyMySQL's driver does not support (see PyMySQL/PyMySQL#202). Replaced with a plain lookup of existing constraints from information_schema.TABLE_CONSTRAINTS followed by conditional ALTER TABLE ... DROP INDEX statements, which works with any MySQL driver. Verified against a real MySQL/PyMySQL backend: downgrading to bff083ad727d and re-running db migrate now completes without error. closes: apache#43690 * Add newsfragment for MySQL PyMySQL migration fix * Fix offline migration for 2.9.2 ORM-consistency revision The PyMySQL online-mode fix in this migration queries information_schema.TABLE_CONSTRAINTS via conn.execute() to decide which legacy unique constraints to drop. In Alembic's offline (--sql) mode there is no live connection, so conn.execute() returns None and iterating over it raises TypeError, breaking the CI "Test offline migration" step. Guard the query-then-conditionally-drop logic behind context.is_offline_mode(), falling back to the original dynamic prepare/execute/deallocate SQL text for the offline branch, since that text is only ever emitted as script output there rather than executed directly. * Address review feedback on MySQL PyMySQL migration fix Bind the table name as a query parameter in the information_schema lookup instead of interpolating it into the SQL string, since it's a value comparison rather than an identifier — matches Airflow's usual parameter-binding convention even though every call site currently passes a hardcoded literal. Also correct the docstring: PyMySQL can run a bare PREPARE statement fine, what it actually can't do is send more than one statement per cursor.execute() call, because it never enables CLIENT.MULTI_STATEMENTS. * Fixed the PR comments
Migrating the metadata database to Airflow 2.9.2 (revision
686269002441) raisedpymysql.err.ProgrammingErroron MySQL when using the PyMySQL driver, because the migration used MySQL'sPREPARE/EXECUTE/DEALLOCATE PREPAREdynamic SQL to conditionally drop unique constraints on theconnectionanddag_runtables. This syntax is not supported by PyMySQL (see PyMySQL#202), so any deployment using PyMySQL as its MySQL driver could not migrate past this revision.Replaced the dynamic SQL with a plain lookup of existing constraints from
information_schema.TABLE_CONSTRAINTS, followed by conditionalALTER TABLE ... DROP INDEXstatements — this works with any MySQL driver.Verified against a real MySQL backend forced to use
mysql+pymysql://: downgrading tobff083ad727dand re-runningairflow db migratenow completes without error, and the expected unique constraints (connection_conn_id_uq,dag_run_dag_id_*_key) are present afterward.closes: #43690
Was generative AI tooling used to co-author this PR?
Generated-by: Claude Code (Sonnet 5) following the guidelines