From d60cf404ca5f7b3cf776fa04a14f362bcebf89a9 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Mon, 17 Feb 2014 19:20:45 +0100 Subject: [PATCH] [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 --- openerp/osv/orm.py | 11 ++++++++++- openerp/sql_db.py | 17 ++++++++++++++++- 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/openerp/osv/orm.py b/openerp/osv/orm.py index 62ff24a2a3c..133ac5e6653 100644 --- a/openerp/osv/orm.py +++ b/openerp/osv/orm.py @@ -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') diff --git a/openerp/sql_db.py b/openerp/sql_db.py index de9d21dcd82..fb214fa068b 100644 --- a/openerp/sql_db.py +++ b/openerp/sql_db.py @@ -3,7 +3,7 @@ # # OpenERP, Open Source Management Solution # Copyright (C) 2004-2009 Tiny SPRL (). -# Copyright (C) 2010-2013 OpenERP s.a. (). +# Copyright (C) 2010-2014 OpenERP s.a. (). # # 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)