2 # Copyright (C) 2007-2010 Libresoft Research Group
4 # This program is free software; you can redistribute it and/or modify
5 # it under the terms of the GNU General Public License as published by
6 # the Free Software Foundation; either version 2 of the License, or
7 # (at your option) any later version.
9 # This program is distributed in the hope that it will be useful,
10 # but WITHOUT ANY WARRANTY; without even the implied warranty of
11 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 # GNU General Public License for more details.
14 # You should have received a copy of the GNU General Public License
15 # along with this program; if not, write to the Free Software
16 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
19 # Israel Herraiz <herraiz@gsyc.escet.urjc.es>
20 # Germán Poo-Caamaño <gpoo@gnome.org>
23 This module contains a basic SQL wrapper. It uses the standard
24 database API of Python, so any module may be used (just substitute
25 import MySQLdb for any other, for instance import PyGreSQL).
27 @authors: Israel Herraiz
28 @organization: Libresoft Research Group, Universidad Rey Juan Carlos
29 @copyright: Universidad Rey Juan Carlos (Madrid, Spain)
30 @license: GNU GPL version 2 or any later version
31 @contact: libresoft-tools-devel@lists.morfeo-project.org
36 import psycopg2 as dbapi
37 from psycopg2.extensions import ISOLATION_LEVEL_AUTOCOMMIT
39 from pymlstats.database import GenericDatabase
42 class Database(GenericDatabase):
43 def __init__(self, dbname='', username='', password='', hostname=None,
44 admin_user=None, admin_password=None):
45 GenericDatabase.__init__(self)
49 self.password = password
50 self.admin_user = admin_user
51 self.admin_password = admin_password
55 dbname = 'dbname=%s' % (self.name)
56 user = 'user=%s' % (self.user or '')
57 password = 'password=%s' % (self.password or '')
58 host = 'host=%s' % (self.host or '')
60 dsn = ' '.join([dbname, user, password, host])
63 db = dbapi.connect(dsn)
64 db.set_client_encoding('UTF8')
65 db.set_isolation_level(ISOLATION_LEVEL_AUTOCOMMIT)
66 except dbapi.OperationalError, e:
69 GenericDatabase.connect(self, db)
71 def insert_people(self, name, email, mailing_list_url):
73 top_level_domain = email.split(".")[-1]
77 username, domain_name = email.split('@')
79 username, domain_name = ('', '')
81 query_people = '''INSERT INTO people
82 (email_address, name, username,
83 domain_name, top_level_domain)
84 VALUES (%s, %s, %s, %s, %s);'''
85 from_values = [email, name, username, domain_name, top_level_domain]
87 self.write_cursor.execute(query_people, from_values)
88 except dbapi.IntegrityError:
90 except dbapi.DataError:
91 pprint.pprint(from_values)
94 query_mailing_lists_people = '''INSERT INTO mailing_lists_people
95 (email_address, mailing_list_url)
97 mailing_lists_people_values = [email, mailing_list_url]
99 self.write_cursor.execute(query_mailing_lists_people,
100 mailing_lists_people_values)
101 except dbapi.IntegrityError:
102 # Duplicate entry email address-mailing list url
104 except dbapi.DataError:
105 pprint.pprint(mailing_lists_people_values)
108 def store_messages(self, message_list, mailing_list_url):
109 query = 'SET CONSTRAINTS ALL DEFERRED'
110 self.write_cursor.execute(query)
113 query_message = '''INSERT INTO messages (
114 message_id, is_response_of,
115 arrival_date, first_date, first_date_tz,
116 mailing_list, mailing_list_url,
117 subject, message_body)
118 VALUES (%(message-id)s, %(in-reply-to)s,
119 %(received)s, %(date)s, %(date_tz)s,
120 %(list-id)s, %(mailing_list_url)s,
121 %(subject)s, %(body)s);'''
122 query_m_people = '''INSERT INTO messages_people
123 (email_address, type_of_recipient, message_id)
124 VALUES (%s, %s, %s);'''
126 for m in message_list:
128 values['mailing_list_url'] = mailing_list_url
130 # FIXME: If primary key check fails, ignore and continue
131 msgs_people_value = {}
132 for header in ('from', 'to', 'cc'):
133 addresses = self.filter(m[header])
137 for name, email in addresses:
138 self.insert_people(name, email, mailing_list_url)
139 key = '%s-%s' % (header, email)
140 value = (email, header.capitalize(), m['message-id'])
141 msgs_people_value.setdefault(key, value)
143 # Write the rest of the message
145 self.write_cursor.execute(query_message, values)
146 except dbapi.IntegrityError:
149 except dbapi.DataError:
150 pprint.pprint(values, sys.stderr)
153 error_message = """ERROR: Runtime error while trying to write
154 message with message-id '%s'. That message has not been written
155 to the database, but the execution has not been stopped. Please
156 report this failure including the message-id and the URL for
157 the mbox.""" % m['message-id']
159 # Write message to the stderr
160 print >> sys.stderr, error_message
161 print >> sys.stderr, query_message
162 pprint.pprint(values, sys.stderr)
164 for key, values in msgs_people_value.iteritems():
166 self.write_cursor.execute(query_m_people, values)
167 except dbapi.IntegrityError:
168 # Duplicate entry email_address-to|cc-mailing list url
170 except dbapi.DataError:
171 pprint.pprint(values, sys.stderr)
176 # Check that everything is consistent
177 query = 'SET CONSTRAINTS ALL IMMEDIATE'
178 self.write_cursor.execute(query)
181 return stored_messages