Commit 589c7865 authored by Julien Muchembled's avatar Julien Muchembled

Add method on ERP5Catalog and ZSQL create methods to upgrade tables

parent f5105aff
......@@ -49,6 +49,8 @@ from Products.ERP5Type.Utils import sqlquote
import warnings
from zLOG import LOG, PROBLEM, WARNING, INFO
from _mysql_exceptions import ProgrammingError
from MySQLdb.constants.ER import NO_SUCH_TABLE
ACQUIRE_PERMISSION_VALUE = []
DYNAMIC_METHOD_NAME = 'z_related_'
......@@ -972,4 +974,26 @@ class CatalogTool (UniqueObject, ZCatalog, CMFCoreCatalogTool, ActiveObject):
"""Restricted version of _searchAndActivate"""
return self._searchAndActivate(restricted=True, *args, **kw)
security.declareProtected(Permissions.ManagePortal, 'upgradeSchema')
def upgradeSchema(self, sql_catalog_id=None, src__=0):
catalog = self.getSQLCatalog(sql_catalog_id)
connection_id = catalog.z_create_catalog.connection_id
src = []
for clear_method in catalog.sql_clear_catalog:
clear_method = catalog[clear_method]
try:
r = clear_method._upgradeSchema(connection_id, src__=1)
except ProgrammingError, e:
if e[0] != NO_SUCH_TABLE:
raise
r = clear_method(src__=1)
if r:
src.append(r)
if src and not src__:
query = self.getPortalObject()[connection_id]().query
for r in src:
query(r)
return src
InitializeClass(CatalogTool)
......@@ -257,9 +257,82 @@ def DA__call__(self, REQUEST=None, __ick__=None, src__=0, test__=0, **kw):
return result
def _getTableSchema(query, name,
create_lstrip = re.compile(r"[^(]+\(\s*").sub,
create_rstrip = re.compile(r"\s*\)[^)]+$").sub,
create_split = re.compile(r",\n\s*").split,
column_match = re.compile(r"`(\w+)`\s+(.+)").match,
):
(_, schema), = query("SHOW CREATE TABLE " + name)[1]
column_list = []
key_set = set()
for spec in create_split(create_rstrip("", create_lstrip("", schema, 1))):
if "KEY" in spec:
key_set.add(spec)
else:
column_list.append(column_match(spec).groups())
return column_list, key_set
_create_search = re.compile(r'\bCREATE\s+TABLE\s+(`?)(\w+)\1\s+', re.I).search
_key_search = re.compile(r'\bKEY\s+(`[^`]+`)\s+(.+)').search
def DA_upgradeSchema(self, connection_id=None, src__=0):
query = self.getPortalObject()[connection_id or self.connection_id]().query
src = self(src__=1)
m = _create_search(src)
if m is None:
return
name = m.group(2)
old_list, old_set = _getTableSchema(query, name)
name_new = '_%s_new' % name
query('CREATE TEMPORARY TABLE %s %s' % (name_new, src[m.end():]))
try:
new_list, new_set = _getTableSchema(query, name_new)
finally:
query("DROP TEMPORARY TABLE " + name_new)
src = []
q = src.append
old_dict = {}
new = set(column[0] for column in new_list)
for pos, (column, spec) in enumerate(old_list):
if column in new:
old_dict[column] = pos, spec
else:
q("DROP COLUMN " + column)
for key in old_set - new_set:
if "PRIMARY" in key:
q("DROP PRIMARY KEY")
else:
q("DROP KEY " + _key_search(key).group(1))
pos = 0
where = "FIRST"
for column, spec in new_list:
try:
if old_dict[column] != (pos, spec):
q("MODIFY COLUMN %s %s %s" % (column, spec, where))
pos += 1
except KeyError:
q("ADD COLUMN %s %s %s" % (column, spec, where))
where = "AFTER " + column
for key in new_set - old_set:
q("ADD " + key)
if src:
src = "ALTER TABLE %s%s" % (name, ','.join("\n " + q for q in src))
if not src__:
query(src)
return src
DA.__call__ = DA__call__
DA.fromFile = DA_fromFile
DA.fromText = DA_fromText
DA.manage_FTPget = DA_manage_FTPget
DA.PUT = DA_PUT
DA._upgradeSchema = DA_upgradeSchema
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment