summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVo Minh Thu <vmt@openerp.com>2012-06-01 15:14:14 +0200
committerVo Minh Thu <vmt@openerp.com>2012-06-01 15:14:14 +0200
commitd790650bfb703ba30a7abde8d4d3d111034fbbb5 (patch)
tree0d825760d02420521443d933a008ae75ce6f20f0
parent5df4aa8ccad22430cc1467ea0820c2bb16aaf726 (diff)
[IMP] uninstall: use dedicated table instead of overloading ir.model.data.
bzr revid: vmt@openerp.com-20120601131414-880vmpctmjfxl84f
-rw-r--r--openerp/addons/base/ir/ir_model.py26
-rw-r--r--openerp/addons/base/ir/ir_model_constraint.py22
-rw-r--r--openerp/addons/base/module/module.py3
-rw-r--r--openerp/osv/orm.py5
-rw-r--r--openerp/tests/addons/test_uninstall/models.py7
-rw-r--r--t.py78
6 files changed, 99 insertions, 42 deletions
diff --git a/openerp/addons/base/ir/ir_model.py b/openerp/addons/base/ir/ir_model.py
index 421342cd625..174f52b1944 100644
--- a/openerp/addons/base/ir/ir_model.py
+++ b/openerp/addons/base/ir/ir_model.py
@@ -29,8 +29,7 @@ from openerp import netsvc, pooler, tools
from openerp.tools.safe_eval import safe_eval as eval
from openerp.tools import config
from openerp.tools.translate import _
-from openerp.osv.orm import except_orm, browse_record, EXT_ID_PREFIX_FK, \
- EXT_ID_PREFIX_M2M_TABLE, EXT_ID_PREFIX_CONSTRAINT
+from openerp.osv.orm import except_orm, browse_record, EXT_ID_PREFIX_M2M_TABLE
_logger = logging.getLogger(__name__)
@@ -857,8 +856,7 @@ class ir_model_data(osv.osv):
model_obj = self.pool.get(model)
name = tools.ustr(data.name)
- if name.startswith(EXT_ID_PREFIX_FK) or name.startswith(EXT_ID_PREFIX_M2M_TABLE)\
- or name.startswith(EXT_ID_PREFIX_CONSTRAINT):
+ if name.startswith(EXT_ID_PREFIX_M2M_TABLE):
# double-check we are really going to delete all the owners of this schema element
cr.execute("""SELECT id from ir_model_data where name = %s and res_id IS NULL""", (data.name,))
external_ids = [x[0] for x in cr.fetchall()]
@@ -866,16 +864,6 @@ class ir_model_data(osv.osv):
# as installed modules have defined this element we must not delete it!
continue
- if name.startswith(EXT_ID_PREFIX_FK):
- name = name[len(EXT_ID_PREFIX_FK):]
- # test if FK exists on this table (it could be on a related m2m table, in which case we ignore it)
- cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
- WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table))
- if cr.fetchone():
- cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
- _logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
- continue
-
if name.startswith(EXT_ID_PREFIX_M2M_TABLE):
name = name[len(EXT_ID_PREFIX_M2M_TABLE):]
cr.execute("SELECT 1 FROM information_schema.tables WHERE table_name=%s", (name,))
@@ -883,16 +871,6 @@ class ir_model_data(osv.osv):
to_drop_table.append(name)
continue
- if name.startswith(EXT_ID_PREFIX_CONSTRAINT):
- name = name[len(EXT_ID_PREFIX_CONSTRAINT):]
- # test if constraint exists
- cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
- WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table))
- if cr.fetchone():
- cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
- _logger.info('Dropped CONSTRAINT %s@%s', name, model)
- continue
-
pair_to_unlink = (model, res_id)
if pair_to_unlink not in to_unlink:
to_unlink.append(pair_to_unlink)
diff --git a/openerp/addons/base/ir/ir_model_constraint.py b/openerp/addons/base/ir/ir_model_constraint.py
index 790b598763a..620edb32363 100644
--- a/openerp/addons/base/ir/ir_model_constraint.py
+++ b/openerp/addons/base/ir/ir_model_constraint.py
@@ -1,8 +1,12 @@
+import logging
import openerp
+from openerp import SUPERUSER_ID
from openerp.osv import fields
from openerp.osv.orm import Model
+_logger = logging.getLogger(__name__)
+
class ir_model_constraint(Model):
"""
This model tracks PostgreSQL foreign keys and constraints used by OpenERP
@@ -33,7 +37,7 @@ class ir_model_constraint(Model):
Delete PostgreSQL foreign keys and constraints tracked by this model.
"""
- if uid != 1 and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"):
+ if uid != SUPERUSER_ID and not self.pool.get('ir.model.access').check_groups(cr, uid, "base.group_system"):
raise except_orm(_('Permission Denied'), (_('Administrator access is required to uninstall a module')))
context = dict(context or {})
@@ -41,10 +45,11 @@ class ir_model_constraint(Model):
ids_set = set(ids)
ids.sort()
ids.reverse()
+ to_unlink = []
for data in self.browse(cr, uid, ids, context):
- model = data.model
+ model = data.model.name
model_obj = self.pool.get(model)
- name = tools.ustr(data.name)
+ name = openerp.tools.ustr(data.name)
typ = data.type
# double-check we are really going to delete all the owners of this schema element
@@ -52,20 +57,25 @@ class ir_model_constraint(Model):
external_ids = [x[0] for x in cr.fetchall()]
if (set(external_ids)-ids_set):
# as installed modules have defined this element we must not delete it!
- pass
+ continue
- elif typ == 'f':
+ if typ == 'f':
# test if FK exists on this table (it could be on a related m2m table, in which case we ignore it)
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('f', name, model_obj._table))
if cr.fetchone():
+ print '>>> ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name)
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
_logger.info('Dropped FK CONSTRAINT %s@%s', name, model)
- elif typ == 'u':
+ if typ == 'u':
# test if constraint exists
cr.execute("""SELECT 1 from pg_constraint cs JOIN pg_class cl ON (cs.conrelid = cl.oid)
WHERE cs.contype=%s and cs.conname=%s and cl.relname=%s""", ('u', name, model_obj._table))
if cr.fetchone():
+ print '>>> ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name)
cr.execute('ALTER TABLE "%s" DROP CONSTRAINT "%s"' % (model_obj._table, name),)
_logger.info('Dropped CONSTRAINT %s@%s', name, model)
+
+ to_unlink.append(data.id)
+ self.unlink(cr, uid, to_unlink, context)
diff --git a/openerp/addons/base/module/module.py b/openerp/addons/base/module/module.py
index e04e4e4a02b..371bfb1b93c 100644
--- a/openerp/addons/base/module/module.py
+++ b/openerp/addons/base/module/module.py
@@ -364,7 +364,10 @@ class module(osv.osv):
including the deletion of all database structures created by the module:
tables, columns, constraints, etc."""
ir_model_data = self.pool.get('ir.model.data')
+ ir_model_constraint = self.pool.get('ir.model.constraint')
modules_to_remove = [m.name for m in self.browse(cr, uid, ids, context)]
+ constraint_ids = ir_model_constraint.search(cr, uid, [('module', 'in', modules_to_remove)])
+ ir_model_constraint._module_data_uninstall(cr, uid, constraint_ids, context)
data_ids = ir_model_data.search(cr, uid, [('module', 'in', modules_to_remove)])
ir_model_data._module_data_uninstall(cr, uid, data_ids, context)
ir_model_data.unlink(cr, uid, data_ids, context)
diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py
index be55c1d305d..64c627849ac 100644
--- a/openerp/osv/orm.py
+++ b/openerp/osv/orm.py
@@ -71,9 +71,7 @@ _schema = logging.getLogger(__name__ + '.schema')
from openerp.tools import SKIPPED_ELEMENT_TYPES
# Prefixes for external IDs of schema elements
-EXT_ID_PREFIX_FK = "_foreign_key_"
EXT_ID_PREFIX_M2M_TABLE = "_m2m_rel_table_"
-EXT_ID_PREFIX_CONSTRAINT = "_constraint_"
regex_order = re.compile('^(([a-z0-9_]+|"[a-z0-9_]+")( *desc| *asc)?( *, *|))+$', re.I)
regex_object_name = re.compile(r'^[a-z0-9_.]+$')
@@ -3108,7 +3106,6 @@ class BaseModel(object):
""" Create the foreign keys recorded by _auto_init. """
for t, k, r, d in self._foreign_keys:
cr.execute('ALTER TABLE "%s" ADD FOREIGN KEY ("%s") REFERENCES "%s" ON DELETE %s' % (t, k, r, d))
- self._make_ext_id(cr, "%s%s_%s_fkey" % (EXT_ID_PREFIX_FK, t, k))
self._save_constraint(cr, "%s_%s_fkey" % (t, k), 'f')
cr.commit()
del self._foreign_keys
@@ -3234,7 +3231,7 @@ class BaseModel(object):
for (key, con, _) in self._sql_constraints:
conname = '%s_%s' % (self._table, key)
- self._make_ext_id(cr, EXT_ID_PREFIX_CONSTRAINT + conname)
+ self._save_constraint(cr, conname, 'u')
cr.execute("SELECT conname, pg_catalog.pg_get_constraintdef(oid, true) as condef FROM pg_constraint where conname=%s", (conname,))
existing_constraints = cr.dictfetchall()
sql_actions = {
diff --git a/openerp/tests/addons/test_uninstall/models.py b/openerp/tests/addons/test_uninstall/models.py
index 645853cc2f8..335aedc941a 100644
--- a/openerp/tests/addons/test_uninstall/models.py
+++ b/openerp/tests/addons/test_uninstall/models.py
@@ -1,11 +1,18 @@
# -*- coding: utf-8 -*-
import openerp
+from openerp.osv import fields
from openerp.osv.orm import Model
class test_uninstall_model(Model):
_name = 'test_uninstall.model'
_columns = {
+ 'name': fields.char('Name', size=64),
+ 'ref': fields.many2one('res.users', string='User'),
}
+ _sql_constraints = [
+ ('name_uniq', 'unique (name)', 'Each name must be unique.')
+ ]
+
# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
diff --git a/t.py b/t.py
index f5497943a59..7fc33f7d281 100644
--- a/t.py
+++ b/t.py
@@ -1,18 +1,80 @@
import openerp
+from openerp import SUPERUSER_ID
from openerp.osv import fields
from openerp.osv.orm import Model
conf = openerp.tools.config
+# TODO Exception handling (especially on cursors).
+
+def get_registry(database_name):
+ registry = openerp.modules.registry.RegistryManager.get(database_name)
+ return registry
+
+def reload_registry(database_name):
+ openerp.modules.registry.RegistryManager.new(
+ database_name, update_module=True)
+
+def search_registry(database_name, model_name, domain):
+ registry = get_registry(database_name)
+ cr = registry.db.cursor()
+ model = registry.get(model_name)
+ record_ids = model.search(cr, SUPERUSER_ID,
+ domain, {})
+ cr.close()
+ return record_ids
+
+def install_module(database_name, module_name):
+ registry = get_registry(database_name)
+ ir_module_module = registry.get('ir.module.module')
+ cr = registry.db.cursor()
+ module_ids = ir_module_module.search(cr, SUPERUSER_ID,
+ [('name', '=', module_name)], {})
+ assert len(module_ids) == 1
+ ir_module_module.button_install(cr, SUPERUSER_ID, module_ids, {})
+ cr.commit()
+ cr.close()
+ reload_registry(database_name)
+
+def uninstall_module(database_name, module_name):
+ registry = get_registry(database_name)
+ ir_module_module = registry.get('ir.module.module')
+ cr = registry.db.cursor()
+ module_ids = ir_module_module.search(cr, SUPERUSER_ID,
+ [('name', '=', module_name)], {})
+ assert len(module_ids) == 1
+ ir_module_module.button_uninstall(cr, SUPERUSER_ID, module_ids, {})
+ cr.commit()
+ cr.close()
+ reload_registry(database_name)
+
if __name__ == '__main__':
openerp.netsvc.init_logger()
- conf['addons_path'] = './openerp/tests/addons'
- conf['init'] = {'test_uninstall': 1}
- registry = openerp.modules.registry.RegistryManager.new('xx', update_module=True)
+ conf['addons_path'] = './openerp/tests/addons,../../addons/trunk,../../web/trunk/addons'
+
+ install_module('xx', 'test_uninstall')
+ registry = get_registry('xx')
+ assert registry.get('test_uninstall.model')
+
+ assert search_registry('xx', 'ir.model.data',
+ [('module', '=', 'test_uninstall')])
+
+ assert search_registry('xx', 'ir.model.fields',
+ [('model', '=', 'test_uninstall.model')])
+
+ uninstall_module('xx', 'test_uninstall')
+ registry = get_registry('xx')
+ assert not registry.get('test_uninstall.model')
+
+ assert not search_registry('xx', 'ir.model.data',
+ [('module', '=', 'test_uninstall')])
+
+ assert not search_registry('xx', 'ir.model.fields',
+ [('model', '=', 'test_uninstall.model')])
+
ir_model_constraint = registry.get('ir.model.constraint')
- print ir_model_constraint
cr = registry.db.cursor()
- ids = ir_model_constraint.search(cr, openerp.SUPERUSER_ID, [], {})
- print ir_model_constraint.browse(cr, openerp.SUPERUSER_ID, ids, {})
+ ids = ir_model_constraint.search(cr, SUPERUSER_ID, [], {})
+ #print ir_model_constraint.browse(cr, SUPERUSER_ID, ids, {})
cr.close()
#####################################################################
@@ -33,8 +95,8 @@ MY_MODULE = {
'depends': ['base'],
}
-def create_virtual_module(db_name, module_name, info):
- registry = openerp.modules.registry.RegistryManager.get(db_name)
+def create_virtual_module(database_name, module_name, info):
+ registry = get_registry(database_name)
cr = registry.db.cursor()
cr.execute("""SELECT 1 FROM ir_module_module WHERE name=%s""", (module_name,))