Use RETURNING in INSERT if available

review21003
This commit is contained in:
Cédric Krier
2011-08-21 10:20:23 +02:00
parent a76e23a51f
commit 0f3ba1f69f
4 changed files with 53 additions and 13 deletions
+1
View File
@@ -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
+8
View File
@@ -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 -4
View File
@@ -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)
+18 -9
View File
@@ -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)):