From e2cb94b3d6e061241279317dd237ed7070ebcc73 Mon Sep 17 00:00:00 2001 From: Diego Medina Date: Wed, 6 Apr 2022 11:46:21 -0400 Subject: [PATCH] fix: cannot delete a database if team member has SQL editor tab that uses that db (#19243) * fix: update sql lab models constraints to support db deletion * update with master * solve db migration conflict * fix tests (cherry picked from commit 350f21d9d34525ae47d4b95a8b95918afa891f01) --- ..._lab_models_database_constraint_updates.py | 138 ++++++++++++++++++ superset/models/sql_lab.py | 10 +- 2 files changed, 145 insertions(+), 3 deletions(-) create mode 100644 superset/migrations/versions/8b841273bec3_sql_lab_models_database_constraint_updates.py diff --git a/superset/migrations/versions/8b841273bec3_sql_lab_models_database_constraint_updates.py b/superset/migrations/versions/8b841273bec3_sql_lab_models_database_constraint_updates.py new file mode 100644 index 0000000000000..a497cf80f4bc0 --- /dev/null +++ b/superset/migrations/versions/8b841273bec3_sql_lab_models_database_constraint_updates.py @@ -0,0 +1,138 @@ +# Licensed to the Apache Software Foundation (ASF) under one +# or more contributor license agreements. See the NOTICE file +# distributed with this work for additional information +# regarding copyright ownership. The ASF licenses this file +# to you under the Apache License, Version 2.0 (the +# "License"); you may not use this file except in compliance +# with the License. You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, +# software distributed under the License is distributed on an +# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +# KIND, either express or implied. See the License for the +# specific language governing permissions and limitations +# under the License. +"""sql_lab_models_database_constraint_updates + +Revision ID: 8b841273bec3 +Revises: 2ed890b36b94 +Create Date: 2022-03-16 21:07:48.768425 + +""" + +# revision identifiers, used by Alembic. +revision = "8b841273bec3" +down_revision = "2ed890b36b94" + +import sqlalchemy as sa +from alembic import op + +from superset.utils.core import generic_find_fk_constraint_name + + +def upgrade(): + bind = op.get_bind() + insp = sa.engine.reflection.Inspector.from_engine(bind) + + with op.batch_alter_table("tab_state") as batch_op: + table_schema_id_constraint = generic_find_fk_constraint_name( + "tab_state", {"id"}, "dbs", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + table_schema_id_constraint = generic_find_fk_constraint_name( + "tab_state", {"client_id"}, "query", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + batch_op.create_foreign_key( + "tab_state_database_id_fkey", + "dbs", + ["database_id"], + ["id"], + ondelete="CASCADE", + ) + + batch_op.create_foreign_key( + "tab_state_latest_query_id_fkey", + "query", + ["latest_query_id"], + ["client_id"], + ondelete="SET NULL", + ) + + with op.batch_alter_table("table_schema") as batch_op: + table_schema_id_constraint = generic_find_fk_constraint_name( + "table_schema", {"id"}, "dbs", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + batch_op.create_foreign_key( + "table_schema_database_id_fkey", + "dbs", + ["database_id"], + ["id"], + ondelete="CASCADE", + ) + + +def downgrade(): + bind = op.get_bind() + insp = sa.engine.reflection.Inspector.from_engine(bind) + + with op.batch_alter_table("tab_state") as batch_op: + table_schema_id_constraint = generic_find_fk_constraint_name( + "tab_state", {"id"}, "dbs", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + table_schema_id_constraint = generic_find_fk_constraint_name( + "tab_state", {"client_id"}, "query", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + batch_op.create_foreign_key( + "tab_state_database_id_fkey", "dbs", ["database_id"], ["id"] + ) + batch_op.create_foreign_key( + "tab_state_latest_query_id_fkey", + "query", + ["latest_query_id"], + ["client_id"], + ) + + with op.batch_alter_table("table_schema") as batch_op: + table_schema_id_constraint = generic_find_fk_constraint_name( + "table_schema", {"id"}, "dbs", insp + ) + if table_schema_id_constraint: + batch_op.drop_constraint( + table_schema_id_constraint, + type_="foreignkey", + ) + + batch_op.create_foreign_key( + "table_schema_database_id_fkey", "dbs", ["database_id"], ["id"] + ) diff --git a/superset/models/sql_lab.py b/superset/models/sql_lab.py index 6a3b4ad8bfd7c..3c117c629d7df 100644 --- a/superset/models/sql_lab.py +++ b/superset/models/sql_lab.py @@ -265,7 +265,7 @@ class TabState(Model, AuditMixinNullable, ExtraJSONMixin): active = Column(Boolean, default=False) # selected DB and schema - database_id = Column(Integer, ForeignKey("dbs.id")) + database_id = Column(Integer, ForeignKey("dbs.id", ondelete="CASCADE")) database = relationship("Database", foreign_keys=[database_id]) schema = Column(String(256)) @@ -282,7 +282,9 @@ class TabState(Model, AuditMixinNullable, ExtraJSONMixin): query_limit = Column(Integer) # latest query that was run - latest_query_id = Column(Integer, ForeignKey("query.client_id")) + latest_query_id = Column( + Integer, ForeignKey("query.client_id", ondelete="SET NULL") + ) latest_query = relationship("Query") # other properties @@ -322,7 +324,9 @@ class TableSchema(Model, AuditMixinNullable, ExtraJSONMixin): id = Column(Integer, primary_key=True, autoincrement=True) tab_state_id = Column(Integer, ForeignKey("tab_state.id", ondelete="CASCADE")) - database_id = Column(Integer, ForeignKey("dbs.id"), nullable=False) + database_id = Column( + Integer, ForeignKey("dbs.id", ondelete="CASCADE"), nullable=False + ) database = relationship("Database", foreign_keys=[database_id]) schema = Column(String(256)) table = Column(String(256))