You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

137 lines
5.4 KiB

  1. # -*- coding: utf-8 -*-
  2. ##############################################################################
  3. #
  4. # OpenERP, Open Source Management Solution
  5. # This module copyright (C) 2014 Therp BV (<http://therp.nl>).
  6. #
  7. # This program is free software: you can redistribute it and/or modify
  8. # it under the terms of the GNU Affero General Public License as
  9. # published by the Free Software Foundation, either version 3 of the
  10. # License, or (at your option) any later version.
  11. #
  12. # This program is distributed in the hope that it will be useful,
  13. # but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. # GNU Affero General Public License for more details.
  16. #
  17. # You should have received a copy of the GNU Affero General Public License
  18. # along with this program. If not, see <http://www.gnu.org/licenses/>.
  19. #
  20. ##############################################################################
  21. from openerp.osv import orm, fields
  22. from openerp.tools.translate import _
  23. class CleanupPurgeLineTable(orm.TransientModel):
  24. _inherit = 'cleanup.purge.line'
  25. _name = 'cleanup.purge.line.table'
  26. _columns = {
  27. 'wizard_id': fields.many2one(
  28. 'cleanup.purge.wizard.table', 'Purge Wizard', readonly=True),
  29. }
  30. def purge(self, cr, uid, ids, context=None):
  31. """
  32. Unlink tables upon manual confirmation.
  33. """
  34. lines = self.browse(cr, uid, ids, context=context)
  35. tables = [line.name for line in lines]
  36. for line in lines:
  37. if line.purged:
  38. continue
  39. # Retrieve constraints on the tables to be dropped
  40. # This query is referenced in numerous places
  41. # on the Internet but credits probably go to Tom Lane
  42. # in this post http://www.postgresql.org/\
  43. # message-id/22895.1226088573@sss.pgh.pa.us
  44. # Only using the constraint name and the source table,
  45. # but I'm leaving the rest in for easier debugging
  46. cr.execute(
  47. """
  48. SELECT conname, confrelid::regclass, af.attname AS fcol,
  49. conrelid::regclass, a.attname AS col
  50. FROM pg_attribute af, pg_attribute a,
  51. (SELECT conname, conrelid, confrelid,conkey[i] AS conkey,
  52. confkey[i] AS confkey
  53. FROM (select conname, conrelid, confrelid, conkey, confkey,
  54. generate_series(1,array_upper(conkey,1)) AS i
  55. FROM pg_constraint WHERE contype = 'f') ss) ss2
  56. WHERE af.attnum = confkey AND af.attrelid = confrelid AND
  57. a.attnum = conkey AND a.attrelid = conrelid
  58. AND confrelid::regclass = '%s'::regclass;
  59. """ % line.name)
  60. for constraint in cr.fetchall():
  61. if constraint[3] in tables:
  62. self.logger.info(
  63. 'Dropping constraint %s on table %s (to be dropped)',
  64. constraint[0], constraint[3])
  65. cr.execute(
  66. "ALTER TABLE %s DROP CONSTRAINT %s" % (
  67. constraint[3], constraint[0]))
  68. self.logger.info(
  69. 'Dropping table %s', line.name)
  70. cr.execute("DROP TABLE \"%s\"" % (line.name,))
  71. line.write({'purged': True})
  72. cr.commit()
  73. return True
  74. class CleanupPurgeWizardTable(orm.TransientModel):
  75. _inherit = 'cleanup.purge.wizard'
  76. _name = 'cleanup.purge.wizard.table'
  77. def default_get(self, cr, uid, fields, context=None):
  78. res = super(CleanupPurgeWizardTable, self).default_get(
  79. cr, uid, fields, context=context)
  80. if 'name' in fields:
  81. res['name'] = _('Purge modules')
  82. return res
  83. def find(self, cr, uid, context=None):
  84. """
  85. Search for tables that cannot be instantiated.
  86. Ignore views for now.
  87. """
  88. model_ids = self.pool['ir.model'].search(cr, uid, [], context=context)
  89. line_pool = self.pool['cleanup.purge.line.table']
  90. known_tables = []
  91. for model in self.pool['ir.model'].browse(
  92. cr, uid, model_ids, context=context):
  93. model_pool = self.pool.get(model.model)
  94. if not model_pool:
  95. continue
  96. known_tables.append(model_pool._table)
  97. known_tables += [
  98. column._sql_names(model_pool)[0]
  99. for column in model_pool._columns.values()
  100. if column._type == 'many2many'
  101. # unstored function fields of type m2m don't have _rel
  102. and hasattr(column, '_rel')
  103. ]
  104. # Cannot pass table names as a psycopg argument
  105. known_tables_repr = ",".join(
  106. [("'%s'" % table) for table in known_tables])
  107. cr.execute(
  108. """
  109. SELECT table_name FROM information_schema.tables
  110. WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
  111. AND table_name NOT IN (%s)""" % known_tables_repr)
  112. res = [(0, 0, {'name': row[0]}) for row in cr.fetchall()]
  113. if not res:
  114. raise orm.except_orm(
  115. _('Nothing to do'),
  116. _('No orphaned tables found'))
  117. return res
  118. _columns = {
  119. 'purge_line_ids': fields.one2many(
  120. 'cleanup.purge.line.table',
  121. 'wizard_id', 'Tables to purge'),
  122. }