From b06e4454d55773dc42c46d3290c1b58bf341a6a0 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 3 Jun 2021 09:42:12 +0000 Subject: [PATCH] [FIX] registry: check_foreign_keys, constraint names are limited to 63 chars When computing the foreign key name, `check_foreign_keys` didn't take into account the limit of 63 characters for constraint names. Because of this, some constraints were dropped and recreated over and over while they were correct, during install and upgrades. For instance, when installing `base` when adding the foreign key for which the name was computed `base_partner_merge_automatic_wizard_res_partner_rel_base_partner_merge_automatic_wizard_id_fkey` Postgresql created the constraint under the name `base_partner_merge_automatic__base_partner_merge_automatic_fkey` and therefore, as the name did not match, the constraint was dropped and re-created. closes odoo/odoo#72234 X-original-commit: 43a4738ebf8a74a389b99f8f58330b3044beaa0c Signed-off-by: Denis Ledoux (dle) --- odoo/modules/registry.py | 3 ++- odoo/tools/sql.py | 19 +++++++++++++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/odoo/modules/registry.py b/odoo/modules/registry.py index e537e3f8a18..cf79f47a692 100644 --- a/odoo/modules/registry.py +++ b/odoo/modules/registry.py @@ -506,15 +506,16 @@ class Registry(Mapping): for key, val in self._foreign_keys.items(): table1, column1 = key table2, column2, ondelete, model, module = val - conname = '%s_%s_fkey' % key deltype = sql._CONFDELTYPES[ondelete.upper()] spec = existing.get(key) if spec is None: sql.add_foreign_key(cr, table1, column1, table2, column2, ondelete) + conname = sql.get_foreign_keys(cr, table1, column1, table2, column2, ondelete)[0] model.env['ir.model.constraint']._reflect_constraint(model, conname, 'f', None, module) elif (spec[1], spec[2], spec[3]) != (table2, column2, deltype): sql.drop_constraint(cr, table1, spec[0]) sql.add_foreign_key(cr, table1, column1, table2, column2, ondelete) + conname = sql.get_foreign_keys(cr, table1, column1, table2, column2, ondelete)[0] model.env['ir.model.constraint']._reflect_constraint(model, conname, 'f', None, module) def check_tables_exist(self, cr): diff --git a/odoo/tools/sql.py b/odoo/tools/sql.py index 7445396856b..2bc82358416 100644 --- a/odoo/tools/sql.py +++ b/odoo/tools/sql.py @@ -172,6 +172,25 @@ def add_foreign_key(cr, tablename1, columnname1, tablename2, columnname2, ondele tablename1, columnname1, tablename2, columnname2, ondelete) return True +def get_foreign_keys(cr, tablename1, columnname1, tablename2, columnname2, ondelete): + cr.execute( + """ + SELECT fk.conname as name + FROM pg_constraint AS fk + JOIN pg_class AS c1 ON fk.conrelid = c1.oid + JOIN pg_class AS c2 ON fk.confrelid = c2.oid + JOIN pg_attribute AS a1 ON a1.attrelid = c1.oid AND fk.conkey[1] = a1.attnum + JOIN pg_attribute AS a2 ON a2.attrelid = c2.oid AND fk.confkey[1] = a2.attnum + WHERE fk.contype = 'f' + AND c1.relname = %s + AND a1.attname = %s + AND c2.relname = %s + AND a2.attname = %s + AND fk.confdeltype = %s + """, [tablename1, columnname1, tablename2, columnname2, _CONFDELTYPES[ondelete.upper()]] + ) + return [r[0] for r in cr.fetchall()] + def fix_foreign_key(cr, tablename1, columnname1, tablename2, columnname2, ondelete): """ Update the foreign keys between tables to match the given one, and return ``True`` if the given foreign key has been recreated.