[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]),
]
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()
_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')

View File

@ -3,7 +3,7 @@
#
# OpenERP, Open Source Management Solution
# 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
# 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.
"""
from contextlib import contextmanager
from functools import wraps
import logging
import time
import psycopg2.extensions
from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT, ISOLATION_LEVEL_READ_COMMITTED, ISOLATION_LEVEL_REPEATABLE_READ
from psycopg2.pool import PoolError
@ -344,6 +346,19 @@ class Cursor(object):
"""
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
def __getattr__(self, name):
return getattr(self._obj, name)