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.

140 lines
5.6 KiB

11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
11 years ago
  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. from ..identifier_adapter import IdentifierAdapter
  24. class CleanupPurgeLineTable(orm.TransientModel):
  25. _inherit = 'cleanup.purge.line'
  26. _name = 'cleanup.purge.line.table'
  27. _columns = {
  28. 'wizard_id': fields.many2one(
  29. 'cleanup.purge.wizard.table', 'Purge Wizard', readonly=True),
  30. }
  31. def purge(self, cr, uid, ids, context=None):
  32. """
  33. Unlink tables upon manual confirmation.
  34. """
  35. lines = self.browse(cr, uid, ids, context=context)
  36. tables = [line.name for line in lines]
  37. for line in lines:
  38. if line.purged:
  39. continue
  40. # Retrieve constraints on the tables to be dropped
  41. # This query is referenced in numerous places
  42. # on the Internet but credits probably go to Tom Lane
  43. # in this post http://www.postgresql.org/\
  44. # message-id/22895.1226088573@sss.pgh.pa.us
  45. # Only using the constraint name and the source table,
  46. # but I'm leaving the rest in for easier debugging
  47. cr.execute(
  48. """
  49. SELECT conname, confrelid::regclass, af.attname AS fcol,
  50. conrelid::regclass, a.attname AS col
  51. FROM pg_attribute af, pg_attribute a,
  52. (SELECT conname, conrelid, confrelid,conkey[i] AS conkey,
  53. confkey[i] AS confkey
  54. FROM (select conname, conrelid, confrelid, conkey,
  55. confkey, generate_series(1,array_upper(conkey,1)) AS i
  56. FROM pg_constraint WHERE contype = 'f') ss) ss2
  57. WHERE af.attnum = confkey AND af.attrelid = confrelid AND
  58. a.attnum = conkey AND a.attrelid = conrelid
  59. AND confrelid::regclass = '%s'::regclass;
  60. """, (IdentifierAdapter(line.name, quote=False),))
  61. for constraint in cr.fetchall():
  62. if constraint[3] in tables:
  63. self.logger.info(
  64. 'Dropping constraint %s on table %s (to be dropped)',
  65. constraint[0], constraint[3])
  66. cr.execute(
  67. "ALTER TABLE %s DROP CONSTRAINT %s", (
  68. IdentifierAdapter(constraint[3]),
  69. IdentifierAdapter(constraint[0]),
  70. )
  71. )
  72. self.logger.info(
  73. 'Dropping table %s', line.name)
  74. cr.execute("DROP TABLE %s", (IdentifierAdapter(line.name),))
  75. line.write({'purged': True})
  76. cr.commit()
  77. return True
  78. class CleanupPurgeWizardTable(orm.TransientModel):
  79. _inherit = 'cleanup.purge.wizard'
  80. _name = 'cleanup.purge.wizard.table'
  81. def default_get(self, cr, uid, fields, context=None):
  82. res = super(CleanupPurgeWizardTable, self).default_get(
  83. cr, uid, fields, context=context)
  84. if 'name' in fields:
  85. res['name'] = _('Purge tables')
  86. return res
  87. def find(self, cr, uid, context=None):
  88. """
  89. Search for tables that cannot be instantiated.
  90. Ignore views for now.
  91. """
  92. model_ids = self.pool['ir.model'].search(cr, uid, [], context=context)
  93. # Start out with known tables with no model
  94. known_tables = ['wkf_witm_trans']
  95. for model in self.pool['ir.model'].browse(
  96. cr, uid, model_ids, context=context):
  97. model_pool = self.pool.get(model.model)
  98. if not model_pool:
  99. continue
  100. known_tables.append(model_pool._table)
  101. known_tables += [
  102. column._sql_names(model_pool)[0]
  103. for column in model_pool._columns.values()
  104. if (column._type == 'many2many' and
  105. hasattr(column, '_rel')) # unstored function fields of
  106. # type m2m don't have _rel
  107. ]
  108. # Cannot pass table names as a psycopg argument
  109. cr.execute(
  110. """
  111. SELECT table_name FROM information_schema.tables
  112. WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
  113. AND table_name NOT IN %s""", (tuple(known_tables),))
  114. res = [(0, 0, {'name': row[0]}) for row in cr.fetchall()]
  115. if not res:
  116. raise orm.except_orm(
  117. _('Nothing to do'),
  118. _('No orphaned tables found'))
  119. return res
  120. _columns = {
  121. 'purge_line_ids': fields.one2many(
  122. 'cleanup.purge.line.table',
  123. 'wizard_id', 'Tables to purge'),
  124. }