comparison roundup/backends/back_postgresql.py @ 5751:5cb6e6b594b0

issue2551040: New release of psycopg2 drops support for psycopg1 First try at suport for psycopg2. Change .travis.yml to install newest psycopg2 without psycopg1 support.
author John Rouillard <rouilj@ieee.org>
date Sat, 01 Jun 2019 15:47:34 -0400
parents 62de601bdf6f
children 6a6b4651be1f
comparison
equal deleted inserted replaced
5750:2c0f89edabe1 5751:5cb6e6b594b0
2 # 2 #
3 # This module is free software, and you may redistribute it and/or modify 3 # This module is free software, and you may redistribute it and/or modify
4 # under the same terms as Python, so long as this copyright message and 4 # under the same terms as Python, so long as this copyright message and
5 # disclaimer are retained in their original form. 5 # disclaimer are retained in their original form.
6 # 6 #
7 '''Postgresql backend via psycopg for Roundup.''' 7 '''Postgresql backend via psycopg2 for Roundup.'''
8 __docformat__ = 'restructuredtext' 8 __docformat__ = 'restructuredtext'
9 9
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 15
16 from psycopg2 import psycopg1 as psycopg 16 import psycopg2
17 from psycopg2.extensions import QuotedString 17 from psycopg2.extensions import QuotedString
18 from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED 18 from psycopg2.extensions import ISOLATION_LEVEL_READ_UNCOMMITTED
19 from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED 19 from psycopg2.extensions import ISOLATION_LEVEL_READ_COMMITTED
20 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ 20 from psycopg2.extensions import ISOLATION_LEVEL_REPEATABLE_READ
21 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE 21 from psycopg2.extensions import ISOLATION_LEVEL_SERIALIZABLE
22 from psycopg2.psycopg1 import ProgrammingError 22 from psycopg2 import ProgrammingError
23 from psycopg2.extensions import TransactionRollbackError 23 from psycopg2.extensions import TransactionRollbackError
24 24
25 import logging 25 import logging
26 26
27 from roundup import hyperdb, date 27 from roundup import hyperdb, date
64 def db_command(config, command, database='postgres'): 64 def db_command(config, command, database='postgres'):
65 '''Perform some sort of database-level command. Retry 10 times if we 65 '''Perform some sort of database-level command. Retry 10 times if we
66 fail by conflicting with another user. 66 fail by conflicting with another user.
67 67
68 Since PostgreSQL version 8.1 there is a database "postgres", 68 Since PostgreSQL version 8.1 there is a database "postgres",
69 before "template1" seems to habe been used, so we fall back to it. 69 before "template1" seems to have been used, so we fall back to it.
70 Compare to issue2550543. 70 Compare to issue2550543.
71 ''' 71 '''
72 template1 = connection_dict(config) 72 template1 = connection_dict(config)
73 template1['database'] = database 73 template1['database'] = database
74 74
75 try: 75 try:
76 conn = psycopg.connect(**template1) 76 conn = psycopg2.connect(**template1)
77 except psycopg.OperationalError as message: 77 except psycopg2.OperationalError as message:
78 if str(message).find('database "postgres" does not exist') >= 0: 78 if str(message).find('database "postgres" does not exist') >= 0:
79 return db_command(config, command, database='template1') 79 return db_command(config, command, database='template1')
80 raise hyperdb.DatabaseError(message) 80 raise hyperdb.DatabaseError(message)
81 81
82 conn.set_isolation_level(0) 82 conn.set_isolation_level(0)
95 95
96 If there is a concurrent update, retry the command. 96 If there is a concurrent update, retry the command.
97 ''' 97 '''
98 try: 98 try:
99 cursor.execute(command) 99 cursor.execute(command)
100 except psycopg.DatabaseError as err: 100 except psycopg2.DatabaseError as err:
101 response = str(err).split('\n')[0] 101 response = str(err).split('\n')[0]
102 if "FATAL" not in response : 102 if "FATAL" not in response :
103 msgs = ( 103 msgs = (
104 'is being accessed by other users', 104 'is being accessed by other users',
105 'could not serialize access due to concurrent update', 105 'could not serialize access due to concurrent update',
113 113
114 def db_exists(config): 114 def db_exists(config):
115 """Check if database already exists""" 115 """Check if database already exists"""
116 db = connection_dict(config, 'database') 116 db = connection_dict(config, 'database')
117 try: 117 try:
118 conn = psycopg.connect(**db) 118 conn = psycopg2.connect(**db)
119 conn.close() 119 conn.close()
120 return 1 120 return 1
121 except: 121 except:
122 return 0 122 return 0
123 123
154 def sql_open_connection(self): 154 def sql_open_connection(self):
155 db = connection_dict(self.config, 'database') 155 db = connection_dict(self.config, 'database')
156 logging.getLogger('roundup.hyperdb').info( 156 logging.getLogger('roundup.hyperdb').info(
157 'open database %r'%db['database']) 157 'open database %r'%db['database'])
158 try: 158 try:
159 conn = psycopg.connect(**db) 159 conn = psycopg2.connect(**db)
160 except psycopg.OperationalError as message: 160 except psycopg2.OperationalError as message:
161 raise hyperdb.DatabaseError(message) 161 raise hyperdb.DatabaseError(message)
162 162
163 cursor = conn.cursor() 163 cursor = conn.cursor()
164 if ISOLATION_LEVEL_REPEATABLE_READ is not None: 164 if ISOLATION_LEVEL_REPEATABLE_READ is not None:
165 lvl = isolation_levels [self.config.RDBMS_ISOLATION_LEVEL] 165 lvl = isolation_levels [self.config.RDBMS_ISOLATION_LEVEL]
243 243
244 def __repr__(self): 244 def __repr__(self):
245 return '<roundpsycopgsql 0x%x>' % id(self) 245 return '<roundpsycopgsql 0x%x>' % id(self)
246 246
247 def sql_stringquote(self, value): 247 def sql_stringquote(self, value):
248 ''' psycopg.QuotedString returns a "buffer" object with the 248 ''' psycopg2.QuotedString returns a "buffer" object with the
249 single-quotes around it... ''' 249 single-quotes around it... '''
250 return str(QuotedString(str(value)))[1:-1] 250 return str(QuotedString(str(value)))[1:-1]
251 251
252 def sql_index_exists(self, table_name, index_name): 252 def sql_index_exists(self, table_name, index_name):
253 sql = 'select count(*) from pg_indexes where ' \ 253 sql = 'select count(*) from pg_indexes where ' \

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