kaxil commented on code in PR #62234:
URL: https://github.com/apache/airflow/pull/62234#discussion_r2914981222


##########
airflow-core/src/airflow/utils/db.py:
##########
@@ -1291,9 +1305,40 @@ def _resetdb_default(session: Session) -> None:
         external_db_manager.drop_tables(session, connection)
 
 
+def _drop_remaining_tables() -> None:
+    """
+    Drop any tables still remaining in the database after the normal reset.
+
+    The squashed migration (0000_2_6_2) creates tables like FAB ab_* tables 
that
+    are now managed by external auth managers. When the default auth manager
+    (SimpleAuthManager) has no DB manager, those tables are not dropped by
+    external_db_manager.drop_tables(). This function reflects the actual 
database
+    and drops anything left over so the migration has a clean slate.
+    """
+    from sqlalchemy import MetaData
+
+    engine = settings.get_engine()
+    metadata = MetaData()
+    metadata.reflect(bind=engine)
+    if not metadata.tables:
+        return
+    remaining = list(metadata.tables.keys())

Review Comment:
   `_drop_remaining_tables` reflects and drops *all* tables in the database 
without any filtering. If there are non-Airflow tables in a shared schema, this 
would drop those too. Probably fine for the dev workflow this targets, but 
worth a note or a safety check.
   
   Also, on MySQL with AUTOCOMMIT isolation, `resetdb` goes through 
`_resetdb_mysql` which manages its own session/connection lifecycle. 
`_drop_remaining_tables` creates a separate engine connection outside that 
flow. Does this work correctly with MySQL's locking behavior?



##########
airflow-core/src/airflow/cli/commands/db_command.py:
##########
@@ -135,6 +135,7 @@ def run_db_migrate_command(args, command, 
revision_heads_map: dict[str, str]):
         to_revision=to_revision,
         from_revision=from_revision,
         show_sql_only=args.show_sql_only,
+        use_migration_files=getattr(args, "use_migration_files", False),

Review Comment:
   `run_db_migrate_command` now passes `use_migration_files` to `command()`, 
but this function is also called by `fab-db migrate` and `db-manager migrate` 
where `command` is `FABDBManager.upgradedb` or `BaseDBManager.upgradedb`. 
Neither of those accepts a `use_migration_files` kwarg, so `fab-db migrate` and 
`db-manager migrate` will crash with `TypeError: upgradedb() got an unexpected 
keyword argument 'use_migration_files'`.
   
   The `getattr` guards the `args` side correctly, but the value is still 
unconditionally forwarded to the command callable. One option would be to only 
pass it when the attribute is truthy, or add `**kwargs` to 
`BaseDBManager.upgradedb`.



##########
providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py:
##########
@@ -38,15 +39,23 @@
     func,
     select,
 )
-from sqlalchemy.orm import Mapped, backref, declared_attr, relationship
+from sqlalchemy.orm import Mapped, backref, declared_attr, registry, 
relationship
 
 from airflow.api_fastapi.auth.managers.models.base_user import BaseUser
+from airflow.models.base import _get_schema, naming_convention
 from airflow.providers.common.compat.sqlalchemy.orm import mapped_column
 
 """
 Compatibility note: The models in this file are duplicated from Flask 
AppBuilder.
 """
 
+metadata = MetaData(schema=_get_schema(), naming_convention=naming_convention)
+_mapper_registry = registry(metadata=metadata)

Review Comment:
   `Model.metadata = Base.metadata` mutates FAB's Model class metadata at 
import time. This is a global side effect that changes `Model.metadata` for all 
code that imports Flask-AppBuilder's `Model`, not just this module. If anything 
else depends on the original FAB metadata (its own naming conventions, schema 
config), it'll silently pick up Airflow's conventions instead. Is the global 
override intentional, or could this be scoped more tightly?



##########
airflow-core/src/airflow/utils/db.py:
##########
@@ -1148,7 +1155,9 @@ def _revisions_above_min_for_offline(config, revisions) 
-> None:
             )
 
 

Review Comment:
   `run_post_migration_steps` is added here but never passed as `False` 
anywhere in this PR. Is this intended for a follow-up? If so, might be better 
to leave it out until it's needed to avoid dead code.



##########
providers/fab/src/airflow/providers/fab/auth_manager/models/__init__.py:
##########
@@ -199,9 +210,13 @@ class Permission(Model):
         Sequence("ab_permission_view_id_seq", start=1, increment=1, 
minvalue=1, cycle=False),
         primary_key=True,
     )
-    action_id: Mapped[int] = mapped_column("permission_id", Integer, 
ForeignKey("ab_permission.id"))
+    action_id: Mapped[int] = mapped_column(

Review Comment:
   Changing `action_id` and `resource_id` to `nullable=True` while keeping 
`Mapped[int]` (not `Mapped[int | None]`) means the Python type says it's always 
an int, but the DB allows NULL. If a row has NULL here, accessing `.action_id` 
returns `None` despite the type hint. Should the annotation be `Mapped[int | 
None]` to match?



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to