This is an automated email from the ASF dual-hosted git repository.

kaxilnaik pushed a commit to branch v2-11-test
in repository https://gitbox.apache.org/repos/asf/airflow.git


The following commit(s) were added to refs/heads/v2-11-test by this push:
     new d93ce5ec0bf fix(migrations): from 2.2.0 to 2.11.0 for Sqlite (#50745)
d93ce5ec0bf is described below

commit d93ce5ec0bfacedc187873dd17c3d7843081bee3
Author: Wei Lee <[email protected]>
AuthorDate: Tue May 20 02:34:40 2025 +0800

    fix(migrations): from 2.2.0 to 2.11.0 for Sqlite (#50745)
    
    ## Why
    `airflow db migrate` failed when I migrated an old airflow instance to 
2.11.0rc1
    
    ## What
    Following up https://github.com/apache/airflow/pull/49301 and trying to fix 
some found issues
    
    * `0093 upgrade, 0100 upgrade, 0060 downgrade, 0064 downgrade`: since SQite 
does not support constant drop, follow how 
https://github.com/apache/airflow/pull/49301 deals with fk for SQlite
    * `0110`: backport _drop_fkey_if_exists for handling fk in sqlite
    * `0142`: Explicitly list down the column names when recreating dag_run 
table
    * `0073`: add a safeguard to ensure we're not wrongly update the name
---
 airflow/migrations/utils.py                        | 56 ++++++++++++++++++++++
 .../0060_2_0_0_remove_id_column_from_xcom.py       |  4 +-
 .../0064_2_0_0_add_unique_constraint_to_conn_id.py |  3 +-
 .../versions/0073_2_0_0_prefix_dag_permissions.py  |  3 +-
 .../0093_2_2_0_taskinstance_keyed_to_dagrun.py     |  8 ++--
 ...2_3_0_add_taskmap_and_map_id_on_taskinstance.py |  5 +-
 ...0110_2_3_2_add_cascade_to_dag_tag_foreignkey.py |  4 +-
 ...nconsistency_between_ORM_and_migration_files.py |  7 ++-
 docs/apache-airflow/img/airflow_erd.sha256         |  2 +-
 9 files changed, 81 insertions(+), 11 deletions(-)

diff --git a/airflow/migrations/utils.py b/airflow/migrations/utils.py
index bc31c8f70c5..1bef41813be 100644
--- a/airflow/migrations/utils.py
+++ b/airflow/migrations/utils.py
@@ -58,3 +58,59 @@ def disable_sqlite_fkeys(op):
         op.execute("PRAGMA foreign_keys=on")
     else:
         yield op
+
+
+def mysql_drop_foreignkey_if_exists(constraint_name: str, table_name: str, op) 
-> None:
+    """Older Mysql versions do not support DROP FOREIGN KEY IF EXISTS."""
+    op.execute(f"""
+    CREATE PROCEDURE DropForeignKeyIfExists()
+    BEGIN
+        IF EXISTS (
+            SELECT 1
+            FROM information_schema.TABLE_CONSTRAINTS
+            WHERE
+                CONSTRAINT_SCHEMA = DATABASE() AND
+                TABLE_NAME = '{table_name}' AND
+                CONSTRAINT_NAME = '{constraint_name}' AND
+                CONSTRAINT_TYPE = 'FOREIGN KEY'
+        ) THEN
+            ALTER TABLE {table_name}
+            DROP CONSTRAINT {constraint_name};
+        ELSE
+            SELECT 1;
+        END IF;
+    END;
+    CALL DropForeignKeyIfExists();
+    DROP PROCEDURE DropForeignKeyIfExists;
+    """)
+
+
+def _drop_fkey_if_exists(table: str, constraint_name: str, op) -> None:
+    dialect = op.get_bind().dialect.name
+    if dialect == "sqlite":
+        try:
+            with op.batch_alter_table(table, schema=None) as batch_op:
+                batch_op.drop_constraint(op.f(constraint_name), 
type_="foreignkey")
+        except ValueError:
+            pass
+    elif dialect == "mysql":
+        mysql_drop_foreignkey_if_exists(constraint_name, table, op)
+    else:
+        op.execute(f"ALTER TABLE {table} DROP CONSTRAINT IF EXISTS 
{constraint_name}")
+
+
+def _sqlite_guarded_drop_constraint(
+    *,
+    table: str,
+    key: str,
+    type_: str,
+    op,
+) -> None:
+    conn = op.get_bind()
+    dialect_name = conn.dialect.name
+    try:
+        with op.batch_alter_table(table, schema=None) as batch_op:
+            batch_op.drop_constraint(key, type_=type_)
+    except ValueError:
+        if dialect_name != "sqlite":
+            raise
diff --git 
a/airflow/migrations/versions/0060_2_0_0_remove_id_column_from_xcom.py 
b/airflow/migrations/versions/0060_2_0_0_remove_id_column_from_xcom.py
index 11359e49843..bdaca9ac05b 100644
--- a/airflow/migrations/versions/0060_2_0_0_remove_id_column_from_xcom.py
+++ b/airflow/migrations/versions/0060_2_0_0_remove_id_column_from_xcom.py
@@ -31,6 +31,8 @@ from collections import defaultdict
 from alembic import op
 from sqlalchemy import Column, Integer, inspect, text
 
+from airflow.migrations.utils import _sqlite_guarded_drop_constraint
+
 # revision identifiers, used by Alembic.
 revision = "bbf4a7ad0465"
 down_revision = "cf5dc11e79ad"
@@ -121,7 +123,7 @@ def downgrade():
     conn = op.get_bind()
     with op.batch_alter_table("xcom") as bop:
         if conn.dialect.name != "mssql":
-            bop.drop_constraint("pk_xcom", type_="primary")
+            _sqlite_guarded_drop_constraint(table="xcom", key="pk_xcom", 
type_="primary", op=op)
         bop.add_column(Column("id", Integer, nullable=False))
         bop.create_primary_key("id", ["id"])
         bop.create_index("idx_xcom_dag_task_date", ["dag_id", "task_id", 
"key", "execution_date"])
diff --git 
a/airflow/migrations/versions/0064_2_0_0_add_unique_constraint_to_conn_id.py 
b/airflow/migrations/versions/0064_2_0_0_add_unique_constraint_to_conn_id.py
index b0c9cacbceb..e0582e2192e 100644
--- a/airflow/migrations/versions/0064_2_0_0_add_unique_constraint_to_conn_id.py
+++ b/airflow/migrations/versions/0064_2_0_0_add_unique_constraint_to_conn_id.py
@@ -30,6 +30,7 @@ import sqlalchemy as sa
 from alembic import op
 
 from airflow.exceptions import AirflowException
+from airflow.migrations.utils import _sqlite_guarded_drop_constraint
 from airflow.models.base import COLLATION_ARGS
 
 # revision identifiers, used by Alembic.
@@ -55,6 +56,6 @@ def upgrade():
 def downgrade():
     """Unapply Add unique constraint to ``conn_id`` and set it as 
non-nullable."""
     with op.batch_alter_table("connection") as batch_op:
-        batch_op.drop_constraint(constraint_name="unique_conn_id", 
type_="unique")
+        _sqlite_guarded_drop_constraint(table="connection", 
key="unique_conn_id", type_="unique", op=op)
 
         batch_op.alter_column("conn_id", nullable=True, 
existing_type=sa.String(250))
diff --git a/airflow/migrations/versions/0073_2_0_0_prefix_dag_permissions.py 
b/airflow/migrations/versions/0073_2_0_0_prefix_dag_permissions.py
index 4a0ff8f2dac..40aa5e4b030 100644
--- a/airflow/migrations/versions/0073_2_0_0_prefix_dag_permissions.py
+++ b/airflow/migrations/versions/0073_2_0_0_prefix_dag_permissions.py
@@ -70,7 +70,8 @@ def remove_prefix_in_individual_dag_permissions(session):
         .all()
     )
     for permission in perms:
-        permission.resource.name = permission.resource.name[len(prefix) :]
+        if permission.resource.name.startswith(prefix):
+            permission.resource.name = permission.resource.name[len(prefix) :]
     session.commit()
 
 
diff --git 
a/airflow/migrations/versions/0093_2_2_0_taskinstance_keyed_to_dagrun.py 
b/airflow/migrations/versions/0093_2_2_0_taskinstance_keyed_to_dagrun.py
index 6788fe30105..939e1705001 100644
--- a/airflow/migrations/versions/0093_2_2_0_taskinstance_keyed_to_dagrun.py
+++ b/airflow/migrations/versions/0093_2_2_0_taskinstance_keyed_to_dagrun.py
@@ -31,7 +31,7 @@ from alembic import op
 from sqlalchemy.sql import and_, column, select, table
 
 from airflow.migrations.db_types import TIMESTAMP, StringID
-from airflow.migrations.utils import get_mssql_table_constraints
+from airflow.migrations.utils import _sqlite_guarded_drop_constraint, 
get_mssql_table_constraints
 
 ID_LEN = 250
 
@@ -221,12 +221,14 @@ def upgrade():
 
     with op.batch_alter_table("task_instance", schema=None) as batch_op:
         if dialect_name != "postgresql":
-            # TODO: Is this right for non-postgres?
             if dialect_name == "mssql":
                 constraints = get_mssql_table_constraints(conn, 
"task_instance")
                 pk, _ = constraints["PRIMARY KEY"].popitem()
                 batch_op.drop_constraint(pk, type_="primary")
-            batch_op.drop_constraint("task_instance_pkey", type_="primary")
+            else:
+                _sqlite_guarded_drop_constraint(
+                    table="task_instance", key="task_instance_pkey", 
type_="primary", op=op
+                )
             batch_op.drop_index("ti_dag_date")
             batch_op.drop_index("ti_state_lkp")
             batch_op.drop_column("execution_date")
diff --git 
a/airflow/migrations/versions/0100_2_3_0_add_taskmap_and_map_id_on_taskinstance.py
 
b/airflow/migrations/versions/0100_2_3_0_add_taskmap_and_map_id_on_taskinstance.py
index 8fc4c37162d..a89e162dba7 100644
--- 
a/airflow/migrations/versions/0100_2_3_0_add_taskmap_and_map_id_on_taskinstance.py
+++ 
b/airflow/migrations/versions/0100_2_3_0_add_taskmap_and_map_id_on_taskinstance.py
@@ -31,6 +31,7 @@ from __future__ import annotations
 from alembic import op
 from sqlalchemy import CheckConstraint, Column, ForeignKeyConstraint, Integer, 
text
 
+from airflow.migrations.utils import _sqlite_guarded_drop_constraint
 from airflow.models.base import StringID
 from airflow.utils.sqlalchemy import ExtendedJSON
 
@@ -52,7 +53,9 @@ def upgrade():
     # Change task_instance's primary key.
     with op.batch_alter_table("task_instance") as batch_op:
         # I think we always use this name for TaskInstance after 7b2661a43ba3?
-        batch_op.drop_constraint("task_instance_pkey", type_="primary")
+        _sqlite_guarded_drop_constraint(
+            table="task_instance", key="task_instance_pkey", type_="primary", 
op=op
+        )
         batch_op.add_column(Column("map_index", Integer, nullable=False, 
server_default=text("-1")))
         batch_op.create_primary_key("task_instance_pkey", ["dag_id", 
"task_id", "run_id", "map_index"])
 
diff --git 
a/airflow/migrations/versions/0110_2_3_2_add_cascade_to_dag_tag_foreignkey.py 
b/airflow/migrations/versions/0110_2_3_2_add_cascade_to_dag_tag_foreignkey.py
index 5bb853a971a..4d91865eaef 100644
--- 
a/airflow/migrations/versions/0110_2_3_2_add_cascade_to_dag_tag_foreignkey.py
+++ 
b/airflow/migrations/versions/0110_2_3_2_add_cascade_to_dag_tag_foreignkey.py
@@ -29,7 +29,7 @@ from __future__ import annotations
 from alembic import op
 from sqlalchemy import inspect
 
-from airflow.migrations.utils import get_mssql_table_constraints
+from airflow.migrations.utils import _drop_fkey_if_exists, 
get_mssql_table_constraints
 
 # revision identifiers, used by Alembic.
 revision = "3c94c427fdf6"
@@ -45,10 +45,10 @@ def upgrade():
     if conn.dialect.name in ["sqlite", "mysql"]:
         inspector = inspect(conn.engine)
         foreignkey = inspector.get_foreign_keys("dag_tag")
+        _drop_fkey_if_exists("dag_tag", foreignkey[0]["name"], op)
         with op.batch_alter_table(
             "dag_tag",
         ) as batch_op:
-            batch_op.drop_constraint(foreignkey[0]["name"], type_="foreignkey")
             batch_op.create_foreign_key(
                 "dag_tag_dag_id_fkey", "dag", ["dag_id"], ["dag_id"], 
ondelete="CASCADE"
             )
diff --git 
a/airflow/migrations/versions/0142_2_9_2_fix_inconsistency_between_ORM_and_migration_files.py
 
b/airflow/migrations/versions/0142_2_9_2_fix_inconsistency_between_ORM_and_migration_files.py
index 0a62b550d40..8c1f4735fdb 100644
--- 
a/airflow/migrations/versions/0142_2_9_2_fix_inconsistency_between_ORM_and_migration_files.py
+++ 
b/airflow/migrations/versions/0142_2_9_2_fix_inconsistency_between_ORM_and_migration_files.py
@@ -244,7 +244,12 @@ def upgrade():
         """)
         )
 
-        conn.execute(sa.text("INSERT INTO dag_run_new SELECT * FROM dag_run"))
+        headers = (
+            "id, dag_id, queued_at, execution_date, start_date, end_date, 
state, run_id, creating_job_id, "
+            "external_trigger, run_type, conf, data_interval_start, 
data_interval_end, "
+            "last_scheduling_decision, dag_hash, log_template_id, updated_at, 
clear_number"
+        )
+        conn.execute(sa.text(f"INSERT INTO dag_run_new ({headers}) SELECT 
{headers} FROM dag_run"))
         conn.execute(sa.text("DROP TABLE dag_run"))
         conn.execute(sa.text("ALTER TABLE dag_run_new RENAME TO dag_run"))
         conn.execute(sa.text("PRAGMA foreign_keys=on"))
diff --git a/docs/apache-airflow/img/airflow_erd.sha256 
b/docs/apache-airflow/img/airflow_erd.sha256
index 9ecc324f73a..ddee93beb4e 100644
--- a/docs/apache-airflow/img/airflow_erd.sha256
+++ b/docs/apache-airflow/img/airflow_erd.sha256
@@ -1 +1 @@
-f240c081c0e69e9c213b887cab50dc1b61e4a71010fcc2f177ab9e22adef229f
\ No newline at end of file
+c70c94b125dfd0a0e24d5815b6474e525e42a801d6b4915a3a97ca074d80b67e
\ No newline at end of file

Reply via email to