|
31 | 31 | import sqlalchemy as sa |
32 | 32 | from alembic import op |
33 | 33 |
|
34 | | -from airflow.migrations.utils import raise_if_rows_exist |
| 34 | +from airflow.migrations.utils import raise_if_rows_exist, sqlite_rebuilds |
35 | 35 | from airflow.models.base import StringID |
36 | 36 | from airflow.utils.sqlalchemy import CompactUUID, UtcDateTime, compact_uuid_default |
37 | 37 |
|
@@ -79,15 +79,9 @@ def _replace_unique(table_name, constraint_name, columns): |
79 | 79 | """ |
80 | 80 | op.execute(dedent(sql)) |
81 | 81 | else: |
82 | | - with op.get_context().autocommit_block(): |
83 | | - foreign_keys = op.get_bind().exec_driver_sql("PRAGMA foreign_keys").scalar_one() |
84 | | - op.execute("PRAGMA foreign_keys=OFF") |
85 | | - try: |
86 | | - with op.batch_alter_table(table_name) as batch_op: |
87 | | - batch_op.drop_constraint(constraint_name, type_="unique") |
88 | | - batch_op.create_unique_constraint(constraint_name, columns) |
89 | | - finally: |
90 | | - op.execute(f"PRAGMA foreign_keys={foreign_keys}") |
| 82 | + with op.batch_alter_table(table_name) as batch_op: |
| 83 | + batch_op.drop_constraint(constraint_name, type_="unique") |
| 84 | + batch_op.create_unique_constraint(constraint_name, columns) |
91 | 85 |
|
92 | 86 |
|
93 | 87 | def _build_collision_query(table_name, columns, where): |
@@ -153,63 +147,65 @@ def _configure_index_builds(): |
153 | 147 |
|
154 | 148 | def upgrade(): |
155 | 149 | _configure_index_builds() |
156 | | - op.create_table( |
157 | | - "dynamic_region", |
158 | | - sa.Column("id", CompactUUID(), nullable=False), |
159 | | - sa.Column("dag_id", StringID(), nullable=False), |
160 | | - sa.Column("run_id", StringID(), nullable=False), |
161 | | - sa.Column("node_id", StringID(), nullable=False), |
162 | | - sa.Column("parent_region_id", CompactUUID(), nullable=True), |
163 | | - sa.Column("parent_region_index", sa.Integer(), nullable=True), |
164 | | - sa.Column("forked_from_region_id", CompactUUID(), nullable=True), |
165 | | - sa.Column("resumes_from_index", sa.Integer(), nullable=False, server_default="0"), |
166 | | - sa.Column("created_at", UtcDateTime(), nullable=False), |
167 | | - sa.PrimaryKeyConstraint("id", name="dynamic_region_pkey"), |
168 | | - sa.ForeignKeyConstraint( |
169 | | - ["dag_id", "run_id"], |
170 | | - ["dag_run.dag_id", "dag_run.run_id"], |
171 | | - name="dynamic_region_dag_run_fkey", |
172 | | - ondelete="CASCADE", |
173 | | - ), |
174 | | - sa.ForeignKeyConstraint( |
175 | | - ["parent_region_id"], |
176 | | - ["dynamic_region.id"], |
177 | | - name="dynamic_region_parent_region_id_fkey", |
178 | | - ondelete="CASCADE", |
179 | | - ), |
180 | | - # Fork lineage is unbounded; a cascading self-FK would exceed MySQL's cascade depth limit. |
181 | | - sa.UniqueConstraint("forked_from_region_id", name="dynamic_region_forked_from_region_id_uq"), |
182 | | - sa.CheckConstraint( |
183 | | - "(parent_region_id IS NULL AND parent_region_index IS NULL) OR " |
184 | | - "(parent_region_id IS NOT NULL AND parent_region_index IS NOT NULL)", |
185 | | - name="parent_coordinates_paired", |
186 | | - ), |
187 | | - sa.CheckConstraint("resumes_from_index >= 0", name="resumes_from_index_nonnegative"), |
188 | | - ) |
189 | | - op.create_index( |
190 | | - "idx_dynamic_region_slot", |
191 | | - "dynamic_region", |
192 | | - ["dag_id", "run_id", "node_id", "parent_region_id", "parent_region_index"], |
193 | | - ) |
194 | | - op.create_index("idx_dynamic_region_parent_region_id", "dynamic_region", ["parent_region_id"]) |
195 | | - for table_name in ("task_instance", "task_state_store"): |
196 | | - op.add_column( |
197 | | - table_name, |
198 | | - sa.Column( |
199 | | - "region_id", CompactUUID(), nullable=False, server_default=compact_uuid_default(_SENTINEL) |
| 150 | + with sqlite_rebuilds(op): |
| 151 | + op.create_table( |
| 152 | + "dynamic_region", |
| 153 | + sa.Column("id", CompactUUID(), nullable=False), |
| 154 | + sa.Column("dag_id", StringID(), nullable=False), |
| 155 | + sa.Column("run_id", StringID(), nullable=False), |
| 156 | + sa.Column("node_id", StringID(), nullable=False), |
| 157 | + sa.Column("parent_region_id", CompactUUID(), nullable=True), |
| 158 | + sa.Column("parent_region_index", sa.Integer(), nullable=True), |
| 159 | + sa.Column("forked_from_region_id", CompactUUID(), nullable=True), |
| 160 | + sa.Column("resumes_from_index", sa.Integer(), nullable=False, server_default="0"), |
| 161 | + sa.Column("created_at", UtcDateTime(), nullable=False), |
| 162 | + sa.PrimaryKeyConstraint("id", name="dynamic_region_pkey"), |
| 163 | + sa.ForeignKeyConstraint( |
| 164 | + ["dag_id", "run_id"], |
| 165 | + ["dag_run.dag_id", "dag_run.run_id"], |
| 166 | + name="dynamic_region_dag_run_fkey", |
| 167 | + ondelete="CASCADE", |
200 | 168 | ), |
| 169 | + sa.ForeignKeyConstraint( |
| 170 | + ["parent_region_id"], |
| 171 | + ["dynamic_region.id"], |
| 172 | + name="dynamic_region_parent_region_id_fkey", |
| 173 | + ondelete="CASCADE", |
| 174 | + ), |
| 175 | + # Fork lineage is unbounded; a cascading self-FK would exceed MySQL's cascade depth limit. |
| 176 | + sa.UniqueConstraint("forked_from_region_id", name="dynamic_region_forked_from_region_id_uq"), |
| 177 | + sa.CheckConstraint( |
| 178 | + "(parent_region_id IS NULL AND parent_region_index IS NULL) OR " |
| 179 | + "(parent_region_id IS NOT NULL AND parent_region_index IS NOT NULL)", |
| 180 | + name="parent_coordinates_paired", |
| 181 | + ), |
| 182 | + sa.CheckConstraint("resumes_from_index >= 0", name="resumes_from_index_nonnegative"), |
201 | 183 | ) |
202 | | - for table_name, constraint_name, columns, _ in _KEYS: |
203 | | - new_columns = list(columns) |
204 | | - new_columns.insert(new_columns.index("map_index"), "region_id") |
205 | | - _replace_unique(table_name, constraint_name, new_columns) |
| 184 | + op.create_index( |
| 185 | + "idx_dynamic_region_slot", |
| 186 | + "dynamic_region", |
| 187 | + ["dag_id", "run_id", "node_id", "parent_region_id", "parent_region_index"], |
| 188 | + ) |
| 189 | + op.create_index("idx_dynamic_region_parent_region_id", "dynamic_region", ["parent_region_id"]) |
| 190 | + for table_name in ("task_instance", "task_state_store"): |
| 191 | + op.add_column( |
| 192 | + table_name, |
| 193 | + sa.Column( |
| 194 | + "region_id", CompactUUID(), nullable=False, server_default=compact_uuid_default(_SENTINEL) |
| 195 | + ), |
| 196 | + ) |
| 197 | + for table_name, constraint_name, columns, _ in _KEYS: |
| 198 | + new_columns = list(columns) |
| 199 | + new_columns.insert(new_columns.index("map_index"), "region_id") |
| 200 | + _replace_unique(table_name, constraint_name, new_columns) |
206 | 201 |
|
207 | 202 |
|
208 | 203 | def downgrade(): |
209 | 204 | _configure_index_builds() |
210 | 205 | _assert_downgrade_is_lossless() |
211 | | - for table_name, constraint_name, columns, _ in _KEYS: |
212 | | - _replace_unique(table_name, constraint_name, list(columns)) |
213 | | - for table_name in ("task_instance", "task_state_store"): |
214 | | - op.drop_column(table_name, "region_id") |
215 | | - op.drop_table("dynamic_region") |
| 206 | + with sqlite_rebuilds(op): |
| 207 | + for table_name, constraint_name, columns, _ in _KEYS: |
| 208 | + _replace_unique(table_name, constraint_name, list(columns)) |
| 209 | + for table_name in ("task_instance", "task_state_store"): |
| 210 | + op.drop_column(table_name, "region_id") |
| 211 | + op.drop_table("dynamic_region") |
0 commit comments