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.

111 lines
4.3 KiB

  1. # Copyright 2014-2016 Therp BV <http://therp.nl>
  2. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  3. # pylint: disable=consider-merging-classes-inherited
  4. from odoo import api, fields, models, _
  5. from odoo.exceptions import UserError
  6. from ..identifier_adapter import IdentifierAdapter
  7. class CleanupPurgeLineTable(models.TransientModel):
  8. _inherit = 'cleanup.purge.line'
  9. _name = 'cleanup.purge.line.table'
  10. _description = 'Purge tables wizard lines'
  11. wizard_id = fields.Many2one(
  12. 'cleanup.purge.wizard.table', 'Purge Wizard', readonly=True)
  13. @api.multi
  14. def purge(self):
  15. """
  16. Unlink tables upon manual confirmation.
  17. """
  18. if self:
  19. objs = self
  20. else:
  21. objs = self.env['cleanup.purge.line.table']\
  22. .browse(self._context.get('active_ids'))
  23. tables = objs.mapped('name')
  24. for line in objs:
  25. if line.purged:
  26. continue
  27. # Retrieve constraints on the tables to be dropped
  28. # This query is referenced in numerous places
  29. # on the Internet but credits probably go to Tom Lane
  30. # in this post http://www.postgresql.org/\
  31. # message-id/22895.1226088573@sss.pgh.pa.us
  32. # Only using the constraint name and the source table,
  33. # but I'm leaving the rest in for easier debugging
  34. self.env.cr.execute(
  35. """
  36. SELECT conname, confrelid::regclass, af.attname AS fcol,
  37. conrelid::regclass, a.attname AS col
  38. FROM pg_attribute af, pg_attribute a,
  39. (SELECT conname, conrelid, confrelid,conkey[i] AS conkey,
  40. confkey[i] AS confkey
  41. FROM (select conname, conrelid, confrelid, conkey,
  42. confkey, generate_series(1,array_upper(conkey,1)) AS i
  43. FROM pg_constraint WHERE contype = 'f') ss) ss2
  44. WHERE af.attnum = confkey AND af.attrelid = confrelid AND
  45. a.attnum = conkey AND a.attrelid = conrelid
  46. AND confrelid::regclass = '%s'::regclass;
  47. """, (IdentifierAdapter(line.name, quote=False),))
  48. for constraint in self.env.cr.fetchall():
  49. if constraint[3] in tables:
  50. self.logger.info(
  51. 'Dropping constraint %s on table %s (to be dropped)',
  52. constraint[0], constraint[3])
  53. self.env.cr.execute(
  54. "ALTER TABLE %s DROP CONSTRAINT %s",
  55. (
  56. IdentifierAdapter(constraint[3]),
  57. IdentifierAdapter(constraint[0])
  58. ))
  59. self.logger.info(
  60. 'Dropping table %s', line.name)
  61. self.env.cr.execute(
  62. "DROP TABLE %s", (IdentifierAdapter(line.name),))
  63. line.write({'purged': True})
  64. return True
  65. class CleanupPurgeWizardTable(models.TransientModel):
  66. _inherit = 'cleanup.purge.wizard'
  67. _name = 'cleanup.purge.wizard.table'
  68. _description = 'Purge tables'
  69. @api.model
  70. def find(self):
  71. """
  72. Search for tables that cannot be instantiated.
  73. Ignore views for now.
  74. """
  75. known_tables = []
  76. for model in self.env['ir.model'].search([]):
  77. if model.model not in self.env:
  78. continue
  79. model_pool = self.env[model.model]
  80. known_tables.append(model_pool._table)
  81. known_tables += [
  82. column.relation
  83. for column in model_pool._fields.values()
  84. if column.type == 'many2many' and
  85. (column.compute is None or column.store)
  86. and column.relation
  87. ]
  88. self.env.cr.execute(
  89. """
  90. SELECT table_name FROM information_schema.tables
  91. WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
  92. AND table_name NOT IN %s""", (tuple(known_tables),))
  93. res = [(0, 0, {'name': row[0]}) for row in self.env.cr.fetchall()]
  94. if not res:
  95. raise UserError(_('No orphaned tables found'))
  96. return res
  97. purge_line_ids = fields.One2many(
  98. 'cleanup.purge.line.table', 'wizard_id', 'Tables to purge')