[FIX] orm._auto_init: fallback to copy method when altering in-place varchar columns failed.

When a varchar column has a dependence on a view, we cannot change the size in-place,
we need to manually re-create the column with the correct type.

bzr revid: chs@openerp.com-20140217182045-qor70r3gb0fch2ki
This commit is contained in:
Christophe Simonis 2014-02-17 19:20:45 +01:00
parent a5b51c2be7
commit d60cf404ca
2 changed files with 26 additions and 2 deletions

View File

@ -2716,7 +2716,16 @@ class BaseModel(object):
('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]), ('float8', 'float', get_pg_type(f)[1], '::'+get_pg_type(f)[1]),
] ]
if f_pg_type == 'varchar' and f._type == 'char' and ((f.size is None and f_pg_size) or f_pg_size < f.size): if f_pg_type == 'varchar' and f._type == 'char' and ((f.size is None and f_pg_size) or f_pg_size < f.size):
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" TYPE %s' % (self._table, k, pg_varchar(f.size))) try:
with cr.savepoint():
cr.execute('ALTER TABLE "%s" ALTER COLUMN "%s" TYPE %s' % (self._table, k, pg_varchar(f.size)))
except psycopg2.NotSupportedError:
# In place alter table cannot be done because a view is depending of this field.
# Do a manual copy. This will drop the view (that will be recreated later)
cr.execute('ALTER TABLE "%s" RENAME COLUMN "%s" TO temp_change_size' % (self._table, k))
cr.execute('ALTER TABLE "%s" ADD COLUMN "%s" %s' % (self._table, k, pg_varchar(f.size)))
cr.execute('UPDATE "%s" SET "%s"=temp_change_size::%s' % (self._table, k, pg_varchar(f.size)))
cr.execute('ALTER TABLE "%s" DROP COLUMN temp_change_size CASCADE' % (self._table,))
cr.commit() cr.commit()
_schema.debug("Table '%s': column '%s' (type varchar) changed size from %s to %s", _schema.debug("Table '%s': column '%s' (type varchar) changed size from %s to %s",
self._table, k, f_pg_size or 'unlimited', f.size or 'unlimited') self._table, k, f_pg_size or 'unlimited', f.size or 'unlimited')

View File

@ -3,7 +3,7 @@
# #
# OpenERP, Open Source Management Solution # OpenERP, Open Source Management Solution
# Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>). # Copyright (C) 2004-2009 Tiny SPRL (<http://tiny.be>).
# Copyright (C) 2010-2013 OpenERP s.a. (<http://openerp.com>). # Copyright (C) 2010-2014 OpenERP s.a. (<http://openerp.com>).
# #
# This program is free software: you can redistribute it and/or modify # This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as # it under the terms of the GNU Affero General Public License as
@ -27,8 +27,10 @@ the database, *not* a database abstraction toolkit. Database abstraction is what
the ORM does, in fact. the ORM does, in fact.
""" """
from contextlib import contextmanager
from functools import wraps from functools import wraps
import logging import logging
import time
import psycopg2.extensions import psycopg2.extensions
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
from psycopg2.pool import PoolError from psycopg2.pool import PoolError
@ -344,6 +346,19 @@ class Cursor(object):
""" """
return self._cnx.rollback() return self._cnx.rollback()
@contextmanager
@check
def savepoint(self):
"""context manager entering in a new savepoint"""
name = hex(int(time.time() * 1000))[1:]
self.execute("SAVEPOINT %s" % (name,))
try:
yield
self.execute('RELEASE SAVEPOINT %s' % (name,))
except Exception:
self.execute('ROLLBACK TO SAVEPOINT %s' % (name,))
raise
@check @check
def __getattr__(self, name): def __getattr__(self, name):
return getattr(self._obj, name) return getattr(self._obj, name)