@@ -1351,6 +1351,83 @@ def create_m2m(cr, m2m, fk1, fk2, col1=None, col2=None):
1351
1351
)
1352
1352
1353
1353
1354
+ def update_m2m_tables (cr , old_table , new_table , ignored_m2ms = ()):
1355
+ """
1356
+ Update m2m table names and columns.
1357
+
1358
+ This function renames m2m tables still referring to `old_table`. It also updates
1359
+ column names and constraints of those tables.
1360
+
1361
+ :param str old_table: former table name
1362
+ :param str new_table: new table name
1363
+ :param list(str) ignored_m2ms: explicit list of m2m tables to ignore
1364
+
1365
+ :meta private: exclude from online docs
1366
+ """
1367
+ assert isinstance (ignored_m2ms , (list , tuple ))
1368
+ if old_table == new_table or not version_gte ("10.0" ):
1369
+ return
1370
+ ignored_m2ms = set (ignored_m2ms )
1371
+ for orig_m2m_table in get_m2m_tables (cr , new_table ):
1372
+ if orig_m2m_table in ignored_m2ms :
1373
+ continue
1374
+ m = re .match (r"^(\w+)_{0}_rel|{0}_(\w+)_rel$" .format (re .escape (old_table )), orig_m2m_table )
1375
+ if m :
1376
+ m2m_table = "{}_{}_rel" .format (* sorted ([m .group (1 ) or m .group (2 ), new_table ]))
1377
+ # Due to the 63 chars limit in generated constraint names, for long table names the FK
1378
+ # constraint is dropped when renaming the table. We need the constraint to correctly
1379
+ # identify the FK targets. The FK constraints will be dropped and recreated below.
1380
+ rename_table (cr , orig_m2m_table , m2m_table , remove_constraints = False )
1381
+ _logger .info ("Renamed m2m table %s to %s" , orig_m2m_table , m2m_table )
1382
+ else :
1383
+ m2m_table = orig_m2m_table
1384
+ for m2m_col in get_columns (cr , m2m_table ).iter_unquoted ():
1385
+ col_info = target_of (cr , m2m_table , m2m_col )
1386
+ if not col_info or col_info [0 ] != new_table or col_info [1 ] != "id" :
1387
+ continue
1388
+ old_col , new_col = map ("{}_id" .format , [old_table , new_table ])
1389
+ if m2m_col != old_col :
1390
+ _logger .warning (
1391
+ "Possibly missing rename: the column %s of m2m table %s references the table %s" ,
1392
+ m2m_col ,
1393
+ m2m_table ,
1394
+ new_table ,
1395
+ )
1396
+ continue
1397
+ old_constraint = col_info [2 ]
1398
+ cr .execute (
1399
+ """
1400
+ SELECT c.confdeltype
1401
+ FROM pg_constraint c
1402
+ JOIN pg_class t
1403
+ ON c.conrelid = t.oid
1404
+ WHERE t.relname = %s
1405
+ AND c.conname = %s
1406
+ """ ,
1407
+ [m2m_table , old_constraint ],
1408
+ )
1409
+ on_delete = cr .fetchone ()[0 ]
1410
+ query = format_query (
1411
+ cr ,
1412
+ """
1413
+ ALTER TABLE {m2m_table}
1414
+ RENAME COLUMN {old_col} TO {new_col};
1415
+
1416
+ ALTER TABLE {m2m_table}
1417
+ DROP CONSTRAINT {old_constraint},
1418
+ ADD FOREIGN KEY ({new_col}) REFERENCES {new_table} (id) ON DELETE {del_action}
1419
+ """ ,
1420
+ m2m_table = m2m_table ,
1421
+ old_col = old_col ,
1422
+ new_col = new_col ,
1423
+ old_constraint = old_constraint ,
1424
+ new_table = new_table ,
1425
+ del_action = SQLStr ("RESTRICT" ) if on_delete == "r" else SQLStr ("CASCADE" ),
1426
+ )
1427
+ cr .execute (query )
1428
+ _logger .info ("Renamed m2m column of table %s from %s to %s" , m2m_table , old_col , new_col )
1429
+
1430
+
1354
1431
def fixup_m2m (cr , m2m , fk1 , fk2 , col1 = None , col2 = None ):
1355
1432
if col1 is None :
1356
1433
col1 = "%s_id" % fk1
0 commit comments