Use RETURNING in INSERT if available
review21003
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
* Add has_returning on Cursor
|
||||
* Remove use of python code in workflow XML
|
||||
* Use SQL sequence on PostgreSQL for ir.sequence
|
||||
* Allow to specify more than one interface
|
||||
|
||||
@@ -225,3 +225,11 @@ class CursorInterface(object):
|
||||
:param value: the auto_increment value
|
||||
'''
|
||||
pass
|
||||
|
||||
def has_returning(self):
|
||||
'''
|
||||
Return True if database implements RETURNING clause in INSERT or UPDATE
|
||||
statements.
|
||||
|
||||
:return: a boolean
|
||||
'''
|
||||
|
||||
@@ -26,6 +26,7 @@ from trytond.protocols.datatype import Float
|
||||
|
||||
RE_FROM = re.compile('.* from "?([a-zA-Z_0-9]+)"?.*$')
|
||||
RE_INTO = re.compile('.* into "?([a-zA-Z_0-9]+)"?.*$')
|
||||
RE_VERSION = re.compile(r'\S+ (\d+)\.(\d+)')
|
||||
|
||||
|
||||
class Database(DatabaseInterface):
|
||||
@@ -34,6 +35,7 @@ class Database(DatabaseInterface):
|
||||
_connpool = None
|
||||
_list_cache = None
|
||||
_list_cache_timestamp = None
|
||||
_version_cache = {}
|
||||
|
||||
def __new__(cls, database_name='template1'):
|
||||
if database_name in cls._databases:
|
||||
@@ -69,7 +71,7 @@ class Database(DatabaseInterface):
|
||||
conn.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
|
||||
else:
|
||||
conn.set_isolation_level(ISOLATION_LEVEL_SERIALIZABLE)
|
||||
return Cursor(self._connpool, conn, self.database_name)
|
||||
return Cursor(self._connpool, conn, self)
|
||||
|
||||
def close(self):
|
||||
if self._connpool is None:
|
||||
@@ -86,6 +88,14 @@ class Database(DatabaseInterface):
|
||||
cursor.execute('DROP DATABASE "' + database_name + '"')
|
||||
Database._list_cache = None
|
||||
|
||||
def get_version(self, cursor):
|
||||
if self.database_name not in self._version_cache:
|
||||
cursor.execute('SELECT version()')
|
||||
version, = cursor.fetchone()
|
||||
self._version_cache[self.database_name] = map(int,
|
||||
RE_VERSION.search(version).groups())
|
||||
return self._version_cache[self.database_name]
|
||||
|
||||
@staticmethod
|
||||
def dump(database_name):
|
||||
from trytond.tools import exec_pg_command_pipe
|
||||
@@ -270,12 +280,11 @@ class _Cursor(PsycopgCursor):
|
||||
|
||||
class Cursor(CursorInterface):
|
||||
|
||||
def __init__(self, connpool, conn, database_name):
|
||||
def __init__(self, connpool, conn, database):
|
||||
super(Cursor, self).__init__()
|
||||
self._connpool = connpool
|
||||
self._conn = conn
|
||||
self.database_name = database_name
|
||||
self.dbname = self.database_name #XXX to remove
|
||||
self._database = database
|
||||
self.cursor = conn.cursor(cursor_factory=_Cursor)
|
||||
self.commit()
|
||||
self.sql_from_log = {}
|
||||
@@ -285,6 +294,15 @@ class Cursor(CursorInterface):
|
||||
'into': 0,
|
||||
}
|
||||
|
||||
@property
|
||||
def database_name(self):
|
||||
return self._database.database_name
|
||||
|
||||
# TODO to remove
|
||||
@property
|
||||
def dbname(self):
|
||||
return self.database_name
|
||||
|
||||
def __getattr__(self, name):
|
||||
return getattr(self.cursor, name)
|
||||
|
||||
@@ -401,6 +419,10 @@ class Cursor(CursorInterface):
|
||||
select += ' OFFSET %d' % offset
|
||||
return select
|
||||
|
||||
def has_returning(self):
|
||||
# RETURNING clause is available since PostgreSQL 8.2
|
||||
return self._database.get_version(self) >= (8, 2)
|
||||
|
||||
register_type(UNICODE)
|
||||
if PYDATE:
|
||||
register_type(PYDATE)
|
||||
|
||||
@@ -333,16 +333,25 @@ class ModelSQL(ModelStorage):
|
||||
upd2.append(Transaction().user)
|
||||
upd2.append(datetime.datetime.now())
|
||||
try:
|
||||
id_new = cursor.nextid(self._table)
|
||||
if id_new:
|
||||
cursor.execute('INSERT INTO "' + self._table + '" ' \
|
||||
'(id' + upd0 + ') ' \
|
||||
'VALUES (' + str(id_new) + upd1 + ')', tuple(upd2))
|
||||
if cursor.has_returning():
|
||||
cursor.execute('INSERT INTO "' + self._table + '" '
|
||||
'(' + upd0[1:] + ') '
|
||||
'VALUES (' + upd1[1:] + ') RETURNING id',
|
||||
tuple(upd2))
|
||||
id_new, = cursor.fetchone()
|
||||
else:
|
||||
cursor.execute('INSERT INTO "' + self._table + '" ' \
|
||||
'(' + upd0[1:] + ') ' \
|
||||
'VALUES (' + upd1[1:] + ')', tuple(upd2))
|
||||
id_new = cursor.lastid()
|
||||
id_new = cursor.nextid(self._table)
|
||||
if id_new:
|
||||
cursor.execute('INSERT INTO "' + self._table + '" '
|
||||
'(id' + upd0 + ') '
|
||||
'VALUES (' + str(id_new) + upd1 + ')',
|
||||
tuple(upd2))
|
||||
else:
|
||||
cursor.execute('INSERT INTO "' + self._table + '" '
|
||||
'(' + upd0[1:] + ') '
|
||||
'VALUES (' + upd1[1:] + ')',
|
||||
tuple(upd2))
|
||||
id_new = cursor.lastid()
|
||||
except DatabaseIntegrityError, exception:
|
||||
with contextlib.nested(Transaction().new_cursor(),
|
||||
Transaction().set_user(0)):
|
||||
|
||||
Reference in New Issue
Block a user