fix: resolve migration transaction issue with CONCURRENTLY

- Detect transaction context using connection.in_atomic_block
- Use regular CREATE INDEX when in transaction (test environment)
- Use CREATE INDEX CONCURRENTLY when not in transaction (production)
- Maintains production safety while fixing CI test failures
- All 8 indexes now create successfully in both environments

Fixes CI error: 'CREATE INDEX CONCURRENTLY cannot run inside a transaction block'
This commit is contained in:
Oliver Falk
2025-10-15 17:17:38 +02:00
parent 23c36604b8
commit b4598212e5

View File

@@ -8,7 +8,7 @@ from django.db import migrations, connection
def create_indexes(apps: Any, schema_editor: Any) -> None:
"""
Create performance indexes for both PostgreSQL and MySQL compatibility.
Uses CONCURRENTLY for PostgreSQL and regular CREATE INDEX for MySQL.
Uses CONCURRENTLY for PostgreSQL production, regular CREATE INDEX for tests/transactions.
"""
db_engine = connection.vendor
@@ -53,14 +53,30 @@ def create_indexes(apps: Any, schema_editor: Any) -> None:
]
with connection.cursor() as cursor:
# Check if we're in a transaction (test environment)
try:
cursor.execute("SELECT 1")
in_transaction = connection.in_atomic_block
except Exception:
in_transaction = True
for index_name, table_name, columns, where_clause in indexes:
try:
if db_engine == "postgresql":
# PostgreSQL with CONCURRENTLY for production safety
if where_clause:
sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};"
# Use CONCURRENTLY only if not in a transaction (production)
# Use regular CREATE INDEX if in a transaction (tests)
if in_transaction:
# In transaction (test environment) - use regular CREATE INDEX
if where_clause:
sql = f"CREATE INDEX IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};"
else:
sql = f"CREATE INDEX IF NOT EXISTS {index_name} ON {table_name}({columns});"
else:
sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns});"
# Not in transaction (production) - use CONCURRENTLY
if where_clause:
sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns}) {where_clause};"
else:
sql = f"CREATE INDEX CONCURRENTLY IF NOT EXISTS {index_name} ON {table_name}({columns});"
else:
# MySQL and other databases - skip partial indexes
if where_clause: