Manage DatabaseDataError in ModelSQL
issue11314 review399111003
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Manage DatabaseDataError in ModelSQL
|
||||
* Remove support for pysqlite2
|
||||
* Do not import empty One2Many data
|
||||
* Deduplicate entries in domain inversion's simplify
|
||||
|
||||
@@ -11,8 +11,8 @@ except ImportError:
|
||||
from trytond.config import config
|
||||
|
||||
__all__ = [
|
||||
'name', 'Database', 'DatabaseIntegrityError',
|
||||
'DatabaseOperationalError', 'TableHandler']
|
||||
'name', 'Database', 'TableHandler',
|
||||
'DatabaseIntegrityError', 'DatabaseDataError', 'DatabaseOperationalError']
|
||||
|
||||
|
||||
name = urllib.parse.urlparse(config.get('database', 'uri', default='')).scheme
|
||||
@@ -34,5 +34,6 @@ except ImportError:
|
||||
|
||||
Database = _module.Database
|
||||
DatabaseIntegrityError = _module.DatabaseIntegrityError
|
||||
DatabaseDataError = _module.DatabaseDataError
|
||||
DatabaseOperationalError = _module.DatabaseOperationalError
|
||||
TableHandler = _module.TableHandler
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from .database import (
|
||||
Database, DatabaseIntegrityError, DatabaseOperationalError)
|
||||
Database, DatabaseDataError, DatabaseIntegrityError,
|
||||
DatabaseOperationalError)
|
||||
from .table import TableHandler
|
||||
|
||||
__all__ = [
|
||||
Database, DatabaseIntegrityError, DatabaseOperationalError, TableHandler]
|
||||
Database, TableHandler,
|
||||
DatabaseIntegrityError, DatabaseDataError, DatabaseOperationalError]
|
||||
|
||||
@@ -27,6 +27,7 @@ try:
|
||||
from psycopg2.extensions import PYDATE, PYDATETIME, PYINTERVAL, PYTIME
|
||||
except ImportError:
|
||||
PYDATE, PYDATETIME, PYTIME, PYINTERVAL = None, None, None, None
|
||||
from psycopg2 import DataError as DatabaseDataError
|
||||
from psycopg2 import IntegrityError as DatabaseIntegrityError
|
||||
from psycopg2 import OperationalError as DatabaseOperationalError
|
||||
from psycopg2 import ProgrammingError
|
||||
@@ -40,7 +41,9 @@ from trytond.backend.database import DatabaseInterface, SQLType
|
||||
from trytond.config import config, parse_uri
|
||||
from trytond.tools.gevent import is_gevent_monkey_patched
|
||||
|
||||
__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
|
||||
__all__ = [
|
||||
'Database',
|
||||
'DatabaseIntegrityError', 'DatabaseDataError', 'DatabaseOperationalError']
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from .database import (
|
||||
Database, DatabaseIntegrityError, DatabaseOperationalError)
|
||||
Database, DatabaseDataError, DatabaseIntegrityError,
|
||||
DatabaseOperationalError)
|
||||
from .table import TableHandler
|
||||
|
||||
__all__ = [
|
||||
Database, DatabaseIntegrityError, DatabaseOperationalError, TableHandler]
|
||||
Database, TableHandler,
|
||||
DatabaseIntegrityError, DatabaseDataError, DatabaseOperationalError]
|
||||
|
||||
@@ -11,6 +11,7 @@ import time
|
||||
import urllib.parse
|
||||
import warnings
|
||||
from decimal import Decimal
|
||||
from sqlite3 import DatabaseError
|
||||
from sqlite3 import IntegrityError as DatabaseIntegrityError
|
||||
from sqlite3 import OperationalError as DatabaseOperationalError
|
||||
from weakref import WeakKeyDictionary
|
||||
@@ -26,12 +27,18 @@ from trytond.backend.database import DatabaseInterface, SQLType
|
||||
from trytond.config import config, parse_uri
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
__all__ = ['Database', 'DatabaseIntegrityError', 'DatabaseOperationalError']
|
||||
__all__ = [
|
||||
'Database',
|
||||
'DatabaseIntegrityError', 'DatabaseDataError', 'DatabaseOperationalError']
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
_default_name = config.get('database', 'default_name', default=':memory:')
|
||||
|
||||
|
||||
class DatabaseDataError(DatabaseError):
|
||||
pass
|
||||
|
||||
|
||||
class SQLiteExtract(Function):
|
||||
__slots__ = ()
|
||||
_function = 'EXTRACT'
|
||||
|
||||
@@ -27,8 +27,8 @@ from trytond.transaction import Transaction, record_cache_size
|
||||
from . import fields
|
||||
from .descriptors import dualmethod
|
||||
from .modelstorage import (
|
||||
AccessError, ModelStorage, RequiredValidationError, ValidationError,
|
||||
is_leaf)
|
||||
AccessError, ModelStorage, RequiredValidationError, SizeValidationError,
|
||||
ValidationError, is_leaf)
|
||||
from .modelview import ModelView
|
||||
|
||||
|
||||
@@ -393,6 +393,29 @@ class ModelSQL(ModelStorage):
|
||||
gettext('ir.msg_foreign_model_missing',
|
||||
**error_args))
|
||||
|
||||
@classmethod
|
||||
def __raise_data_error(
|
||||
cls, exception, values, field_names=None, transaction=None):
|
||||
if field_names is None:
|
||||
field_names = list(cls._fields.keys())
|
||||
if transaction is None:
|
||||
transaction = Transaction()
|
||||
for field_name in field_names:
|
||||
if field_name not in cls._fields:
|
||||
continue
|
||||
field = cls._fields[field_name]
|
||||
# Check field size
|
||||
if (hasattr(field, 'size')
|
||||
and isinstance(field.size, int)
|
||||
and field.sql_type()):
|
||||
size = len(values.get(field_name) or '')
|
||||
if size > field.size:
|
||||
error_args = cls.__names__(field_name)
|
||||
error_args['size'] = size
|
||||
error_args['max_size'] = field.size
|
||||
raise SizeValidationError(
|
||||
gettext('ir.msg_size_validation_record', **error_args))
|
||||
|
||||
@classmethod
|
||||
def history_revisions(cls, ids):
|
||||
pool = Pool()
|
||||
@@ -640,12 +663,18 @@ class ModelSQL(ModelStorage):
|
||||
[insert_values]))
|
||||
id_new = transaction.database.lastid(cursor)
|
||||
new_ids.append(id_new)
|
||||
except backend.DatabaseIntegrityError as exception:
|
||||
except (
|
||||
backend.DatabaseIntegrityError,
|
||||
backend.DatabaseDataError) as exception:
|
||||
transaction = Transaction()
|
||||
with Transaction().new_transaction(), \
|
||||
Transaction().set_context(_check_access=False):
|
||||
cls.__raise_integrity_error(
|
||||
exception, values, transaction=transaction)
|
||||
if isinstance(exception, backend.DatabaseIntegrityError):
|
||||
cls.__raise_integrity_error(
|
||||
exception, values, transaction=transaction)
|
||||
elif isinstance(exception, backend.DatabaseDataError):
|
||||
cls.__raise_data_error(
|
||||
exception, values, transaction=transaction)
|
||||
raise
|
||||
|
||||
transaction.create_records[cls.__name__].update(new_ids)
|
||||
@@ -1049,13 +1078,21 @@ class ModelSQL(ModelStorage):
|
||||
try:
|
||||
cursor.execute(*table.update(columns, update_values,
|
||||
where=red_sql))
|
||||
except backend.DatabaseIntegrityError as exception:
|
||||
except (
|
||||
backend.DatabaseIntegrityError,
|
||||
backend.DatabaseDataError) as exception:
|
||||
transaction = Transaction()
|
||||
with Transaction().new_transaction(), \
|
||||
Transaction().set_context(_check_access=False):
|
||||
cls.__raise_integrity_error(
|
||||
exception, values, list(values.keys()),
|
||||
transaction=transaction)
|
||||
if isinstance(
|
||||
exception, backend.DatabaseIntegrityError):
|
||||
cls.__raise_integrity_error(
|
||||
exception, values, list(values.keys()),
|
||||
transaction=transaction)
|
||||
elif isinstance(exception, backend.DatabaseDataError):
|
||||
cls.__raise_data_error(
|
||||
exception, values, list(values.keys()),
|
||||
transaction=transaction)
|
||||
raise
|
||||
|
||||
for fname, value in values.items():
|
||||
|
||||
@@ -416,8 +416,7 @@ class FieldCharTestCase(unittest.TestCase, CommonTestCaseMixin):
|
||||
"Test create char with invalid size"
|
||||
Char = Pool().get('test.char_size')
|
||||
|
||||
# XXX: should be UserError but postgresql raises DataError
|
||||
with self.assertRaises(Exception):
|
||||
with self.assertRaises(SizeValidationError):
|
||||
Char.create([{
|
||||
'char': "foobar",
|
||||
}])
|
||||
@@ -492,8 +491,7 @@ class FieldCharTestCase(unittest.TestCase, CommonTestCaseMixin):
|
||||
'char': "Test",
|
||||
}])
|
||||
|
||||
# XXX: should be UserError but postgresql raises DataError
|
||||
with self.assertRaises(Exception):
|
||||
with self.assertRaises(SizeValidationError):
|
||||
Char.write([char], {
|
||||
'char': 'foobar',
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user