Skip to content

Commit 25d4583

Browse files
committed
[IMP] util/pg: remove constraint without table prefix
Constraint by default have the table name as prefix. It's a common error to forget that. When a table is renamed it's expected that ir_model_constraint may be missing. The ORM may not know about it yet. closes #73 Related: odoo/upgrade#5915 Signed-off-by: Christophe Simonis (chs) <[email protected]>
1 parent 3787631 commit 25d4583

File tree

1 file changed

+33
-7
lines changed

1 file changed

+33
-7
lines changed

src/util/pg.py

Lines changed: 33 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -642,18 +642,44 @@ def view_exists(cr, view):
642642
return bool(cr.rowcount)
643643

644644

645-
def remove_constraint(cr, table, name, cascade=False):
645+
def remove_constraint(cr, table, name, cascade=False, warn=True):
646+
"""
647+
Remove a table constraint.
648+
649+
This function removes the constraint `name` from `table`. It also removes records from
650+
`ir_model_constraint` and its xml_ids. It logs not found constraints.
651+
652+
.. note::
653+
654+
If there is no constraint `name`, this function will attempt to remove
655+
``{table}_{name}``, the latter is the default name the ORM uses for constraints
656+
created from `_sql_constraints`.
657+
658+
:param str table: table from where to remove the constraint
659+
:param str name: name of the constraint to remove
660+
:param bool cascade: cascade the constraint removal
661+
:param bool warn: use warning level when logging not found constraints, otherwise use
662+
info level
663+
:return: whether the constraint was removed
664+
:rtype: bool
665+
"""
646666
_validate_table(table)
667+
log = _logger.warning if warn else _logger.info
647668
cascade = "CASCADE" if cascade else ""
648669
cr.execute('ALTER TABLE "{}" DROP CONSTRAINT IF EXISTS "{}" {}'.format(table, name, cascade))
649-
# small exception: odoo specific action.
650-
# needs to be kept here to avoid resurive imports.
651-
# a solution would be to not do it now but adds an `end-` script that remove the invalid entries
652-
# from the `ir_model_constraint` table
670+
# Exceptionally remove Odoo records, even if we are in PG land on this file. This is somehow
671+
# valid because ir.model.constraint are ORM low-level objects that relate directly to table
672+
# constraints.
653673
cr.execute("DELETE FROM ir_model_constraint WHERE name = %s RETURNING id", [name])
654674
if cr.rowcount:
655675
ids = tuple(c for (c,) in cr.fetchall())
656676
cr.execute("DELETE FROM ir_model_data WHERE model = 'ir.model.constraint' AND res_id IN %s", [ids])
677+
return True
678+
if name.startswith(table + "_"):
679+
log("%r not found in ir_model_constraint, table=%r", name, table)
680+
return False
681+
log("%r not found in ir_model_constraint, attempting to remove with table %r prefix", name, table)
682+
return remove_constraint(cr, table, "{}_{}".format(table, name), cascade, warn)
657683

658684

659685
def get_fk(cr, table, quote_ident=True):
@@ -728,7 +754,7 @@ class IndexInfo(collections.namedtuple("IndexInfo", "name on isunique isconstrai
728754

729755
def drop(self, cr):
730756
if self.isconstraint:
731-
remove_constraint(cr, self.on, self.name)
757+
remove_constraint(cr, self.on, self.name, warn=False)
732758
else:
733759
cr.execute('DROP INDEX "%s"' % self.name)
734760

@@ -1064,7 +1090,7 @@ def rename_table(cr, old_table, new_table, remove_constraints=True):
10641090
)
10651091
for (const,) in cr.fetchall():
10661092
_logger.info("Dropping constraint %s on table %s", const, new_table)
1067-
remove_constraint(cr, new_table, const)
1093+
remove_constraint(cr, new_table, const, warn=False)
10681094

10691095
# rename fkeys
10701096
cr.execute(

0 commit comments

Comments
 (0)