comparison roundup/backends/back_postgresql.py @ 5118:57452bc6d989

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.
author John Rouillard <rouilj@ieee.org>
date Sat, 02 Jul 2016 21:15:23 -0400
parents e74c3611b138
children 198b6e810c67
comparison
equal deleted inserted replaced
5117:14abd0a67207 5118:57452bc6d989
10 import os, shutil, time 10 import os, shutil, time
11 ISOLATION_LEVEL_READ_UNCOMMITTED = None 11 ISOLATION_LEVEL_READ_UNCOMMITTED = None
12 ISOLATION_LEVEL_READ_COMMITTED = None 12 ISOLATION_LEVEL_READ_COMMITTED = None
13 ISOLATION_LEVEL_REPEATABLE_READ = None 13 ISOLATION_LEVEL_REPEATABLE_READ = None
14 ISOLATION_LEVEL_SERIALIZABLE = None 14 ISOLATION_LEVEL_SERIALIZABLE = None
15 try: 15
16 import psycopg 16 from psycopg2 import psycopg1 as psycopg
17 from psycopg import QuotedString 17 from psycopg2.extensions import QuotedString
18 from psycopg import ProgrammingError 18 from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED
19 TransactionRollbackError = ProgrammingError 19 from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED
20 try: 20 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
21 from psycopg.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED 21 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
22 from psycopg.extensions import ISOLATION_LEVEL_READ_COMMITTED 22 from psycopg2.psycopg1 import ProgrammingError
23 from psycopg.extensions import ISOLATION_LEVEL_REPEATABLE_READ 23 from psycopg2.extensions import TransactionRollbackError
24 from psycopg.extensions import ISOLATION_LEVEL_SERIALIZABLE 24
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
36 import logging 25 import logging
37 26
38 from roundup import hyperdb, date 27 from roundup import hyperdb, date
39 from roundup.backends import rdbms_common 28 from roundup.backends import rdbms_common
40 from roundup.backends import sessions_rdbms 29 from roundup.backends import sessions_rdbms
106 95
107 If there is a concurrent update, retry the command. 96 If there is a concurrent update, retry the command.
108 ''' 97 '''
109 try: 98 try:
110 cursor.execute(command) 99 cursor.execute(command)
111 except psycopg.ProgrammingError, err: 100 except psycopg.DatabaseError, err:
112 response = str(err).split('\n')[0] 101 response = str(err).split('\n')[0]
113 if response.find('FATAL') != -1: 102 if "FATAL" not in response :
114 raise RuntimeError(response) 103 msgs = (
115 else:
116 msgs = [
117 'is being accessed by other users', 104 'is being accessed by other users',
118 'could not serialize access due to concurrent update', 105 'could not serialize access due to concurrent update',
119 ] 106 )
120 can_retry = 0 107 for msg in msgs :
121 for msg in msgs: 108 if msg in response :
122 if response.find(msg) == -1: 109 time.sleep(0.1)
123 can_retry = 1 110 return 0
124 if can_retry: 111 raise RuntimeError (response)
125 time.sleep(1)
126 return 0
127 raise RuntimeError(response)
128 return 1 112 return 1
129 113
130 def db_exists(config): 114 def db_exists(config):
131 """Check if database already exists""" 115 """Check if database already exists"""
132 db = connection_dict(config, 'database') 116 db = connection_dict(config, 'database')
192 176
193 self.conn, self.cursor = self.sql_open_connection() 177 self.conn, self.cursor = self.sql_open_connection()
194 178
195 try: 179 try:
196 self.load_dbschema() 180 self.load_dbschema()
197 except psycopg.ProgrammingError, message: 181 except ProgrammingError, message:
198 if str(message).find('schema') == -1: 182 if str(message).find('schema') == -1:
199 raise 183 raise
200 self.rollback() 184 self.rollback()
201 self.init_dbschema() 185 self.init_dbschema()
202 self.sql("CREATE TABLE schema (schema TEXT)") 186 self.sql("CREATE TABLE schema (schema TEXT)")
265 ''' 249 '''
266 logging.getLogger('roundup.hyperdb').info('commit') 250 logging.getLogger('roundup.hyperdb').info('commit')
267 251
268 try: 252 try:
269 self.conn.commit() 253 self.conn.commit()
270 except psycopg.ProgrammingError, message: 254 except ProgrammingError, message:
271 # we've been instructed that this commit is allowed to fail 255 # we've been instructed that this commit is allowed to fail
272 if fail_ok and str(message).endswith('could not serialize ' 256 if fail_ok and str(message).endswith('could not serialize '
273 'access due to concurrent update'): 257 'access due to concurrent update'):
274 logging.getLogger('roundup.hyperdb').info( 258 logging.getLogger('roundup.hyperdb').info(
275 'commit FAILED, but fail_ok') 259 'commit FAILED, but fail_ok')

Roundup Issue Tracker: http://roundup-tracker.org/