[MERGE]: Merge with latest trunk-server
[odoo/odoo.git] / openerp / addons / base / ir / ir_model_constraint.py
1 import logging
2
3 import openerp
4 from openerp import SUPERUSER_ID
5 from openerp.osv import fields
6 from openerp.osv.orm import Model
7
8 _logger = logging.getLogger(__name__)
9
10 class ir_model_constraint(Model):
11     """
12     This model tracks PostgreSQL foreign keys and constraints used by OpenERP
13     models.
14     """
15     _name = 'ir.model.constraint'
16     _columns = {
17         'name': fields.char('Constraint', required=True, size=128, select=1,
18             help="PostgreSQL constraint or foreign key name."),
19         'model': fields.many2one('ir.model', string='Model',
20             required=True, select=1),
21         'module': fields.many2one('ir.module.module', string='Module',
22             required=True, select=1),
23         'type': fields.char('Constraint Type', required=True, size=1, select=1,
24             help="Type of the constraint: `f` for a foreign key, "
25                 "`u` for other constraints."),
26         'date_update': fields.datetime('Update Date'),
27         'date_init': fields.datetime('Initialization Date')
28     }
29
30     _sql_constraints = [
31         ('module_name_uniq', 'unique(name, module)',
32             'Constraints with the same name are unique per module.'),
33     ]
34
35     def _module_data_uninstall(self, cr, uid, ids, context=None):
36         """
37         Delete PostgreSQL foreign keys and constraints tracked by this model.
38         """ 
39
40         if uid != SUPERUSER_ID and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"):
41             raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module')))
42
43         context = dict(context or {})
44
45         ids_set = set(ids)
46         ids.sort()
47         ids.reverse()
48         to_unlink = []
49         for data in self.browse(cr, uid, ids, context):
50             model = data.model.model
51             model_obj = self.pool.get(model)
52             name = openerp.tools.ustr(data.name)
53             typ = data.type
54
55             # double-check we are really going to delete all the owners of this schema element
56             cr.execute("""SELECT id from ir_model_constraint where name=%s""", (data.name,))
57             external_ids = [x[0] for x in cr.fetchall()]
58             if (set(external_ids)-ids_set):
59                 # as installed modules have defined this element we must not delete it!
60                 continue
61
62             if typ == 'f':
63                 # test if FK exists on this table (it could be on a related m2m table, in which case we ignore it)
64                 cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
65                               WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table))
66                 if cr.fetchone():
67                     cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
68                     _logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
69
70             if typ == 'u':
71                 # test if constraint exists
72                 cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
73                               WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table))
74                 if cr.fetchone():
75                     cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
76                     _logger.info('Dropped CONSTRAINT %s@%s', name, model)
77
78             to_unlink.append(data.id)
79         self.unlink(cr, uid, to_unlink, context)