[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) <dle@odoo.com>
This commit is contained in:
Denis Ledoux
2021-06-16 13:15:26 +00:00
parent 4cd9bb5552
commit b06e4454d5
2 changed files with 21 additions and 1 deletions
+2 -1
View File
@@ -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):
+19
View File
@@ -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.