Skip to content

Commit 05a3def

Browse files
committed
issue2550853 - better error handling and cleanup on some postgres
tests by Stuart McGraw. My postgres tests passed both before and after I applied his patch, but the code change seems rational. issue2086536 - back_postgresql: fixing pg_command and prefering psycopg2. Patch done by Philipp Gortan (mephinet). His patch also improves handling of retryable errors. Applied and edited by John Rouillard. Edits included removing support for psycopg1. See: https://sourceforge.net/p/roundup/mailman/message/32855027/ for rational for dropping it Again all 137 postgres tests pass.
1 parent a170cdb commit 05a3def

File tree

3 files changed

+46
-42
lines changed

3 files changed

+46
-42
lines changed

CHANGES.txt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,15 @@ Fixed:
221221
String fileds is 'no' not 'yes'. So to get a new string field into
222222
the full text/all text index you need to use String(indexme='yes').
223223
Reported by Michael Belleville. (John Rouillard)
224+
- issue2550853 - better error handling and cleanup on some postgres
225+
tests by Stuart McGraw.
226+
- issue2086536 - back_postgresql: fixing pg_command and prefering
227+
psycopg2. Patch done by Philipp Gortan (mephinet). His patch
228+
also improves handling of retryable errors. Applied and
229+
edited by John Rouillard. Edits included removing support for
230+
psycopg1. See:
231+
https://sourceforge.net/p/roundup/mailman/message/32855027/
232+
for rational for dropping it.
224233

225234
2016-01-11: 1.5.1
226235

roundup/backends/back_postgresql.py

Lines changed: 21 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -12,27 +12,16 @@
1212
ISOLATION_LEVEL_READ_COMMITTED = None
1313
ISOLATION_LEVEL_REPEATABLE_READ = None
1414
ISOLATION_LEVEL_SERIALIZABLE = None
15-
try:
16-
import psycopg
17-
from psycopg import QuotedString
18-
from psycopg import ProgrammingError
19-
TransactionRollbackError = ProgrammingError
20-
try:
21-
from psycopg.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED
22-
from psycopg.extensions import ISOLATION_LEVEL_READ_COMMITTED
23-
from psycopg.extensions import ISOLATION_LEVEL_REPEATABLE_READ
24-
from psycopg.extensions import ISOLATION_LEVEL_SERIALIZABLE
25-
except ImportError:
26-
pass
27-
except:
28-
from psycopg2 import psycopg1 as psycopg
29-
from psycopg2.extensions import QuotedString
30-
from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED
31-
from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED
32-
from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
33-
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
34-
from psycopg2.psycopg1 import ProgrammingError
35-
from psycopg2.extensions import TransactionRollbackError
15+
16+
from psycopg2 import psycopg1 as psycopg
17+
from psycopg2.extensions import QuotedString
18+
from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED
19+
from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED
20+
from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
21+
from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
22+
from psycopg2.psycopg1 import ProgrammingError
23+
from psycopg2.extensions import TransactionRollbackError
24+
3625
import logging
3726

3827
from roundup import hyperdb, date
@@ -108,23 +97,18 @@ def pg_command(cursor, command):
10897
'''
10998
try:
11099
cursor.execute(command)
111-
except psycopg.ProgrammingError, err:
100+
except psycopg.DatabaseError, err:
112101
response = str(err).split('\n')[0]
113-
if response.find('FATAL') != -1:
114-
raise RuntimeError(response)
115-
else:
116-
msgs = [
102+
if "FATAL" not in response :
103+
msgs = (
117104
'is being accessed by other users',
118105
'could not serialize access due to concurrent update',
119-
]
120-
can_retry = 0
121-
for msg in msgs:
122-
if response.find(msg) == -1:
123-
can_retry = 1
124-
if can_retry:
125-
time.sleep(1)
126-
return 0
127-
raise RuntimeError(response)
106+
)
107+
for msg in msgs :
108+
if msg in response :
109+
time.sleep(0.1)
110+
return 0
111+
raise RuntimeError (response)
128112
return 1
129113

130114
def db_exists(config):
@@ -194,7 +178,7 @@ def open_connection(self):
194178

195179
try:
196180
self.load_dbschema()
197-
except psycopg.ProgrammingError, message:
181+
except ProgrammingError, message:
198182
if str(message).find('schema') == -1:
199183
raise
200184
self.rollback()
@@ -267,7 +251,7 @@ def sql_commit(self, fail_ok=False):
267251

268252
try:
269253
self.conn.commit()
270-
except psycopg.ProgrammingError, message:
254+
except ProgrammingError, message:
271255
# we've been instructed that this commit is allowed to fail
272256
if fail_ok and str(message).endswith('could not serialize '
273257
'access due to concurrent update'):

test/test_postgresql.py

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
from db_test_base import ClassicInitBase, setupTracker
2626

2727
from roundup.backends import get_backend, have_backend
28+
from roundup.backends.back_postgresql import psycopg
2829

2930
if not have_backend('postgresql'):
3031
# FIX: workaround for a bug in pytest.mark.skip():
@@ -100,8 +101,12 @@ def setUp(self):
100101
db.close()
101102

102103
def tearDown(self):
103-
self.db1.close()
104-
self.db2.close()
104+
try:
105+
self.db1.close()
106+
self.db2.close()
107+
except psycopg.InterfaceError, exc:
108+
if 'connection already closed' in str(exc): pass
109+
else: raise
105110
ClassicInitBase.tearDown(self)
106111
postgresqlOpener.tearDown(self)
107112

@@ -117,9 +122,15 @@ def _test_journal(self, expected_journal):
117122
db1.commit()
118123
db1.close()
119124

120-
db2.issue.set (id, title='t2')
121-
db2.commit()
122-
db2.close()
125+
# Test testConcurrentRepeatableRead is expected to raise
126+
# an error when the db2.issue.set() call is executed.
127+
try:
128+
db2.issue.set (id, title='t2')
129+
db2.commit()
130+
finally:
131+
# Make sure that the db2 connection is closed, even when
132+
# an error is raised.
133+
db2.close()
123134
self.db = self.tracker.open('admin')
124135
journal = self.db.getjournal('issue', id)
125136
for n, line in enumerate(journal):

0 commit comments

Comments
 (0)