5 @contact: Debian FTPMaster <ftpmaster@debian.org>
6 @copyright: 2000, 2001, 2002, 2003, 2004, 2006 James Troup <james@nocrew.org>
7 @copyright: 2008-2009 Mark Hymers <mhy@debian.org>
8 @copyright: 2009 Joerg Jaspert <joerg@debian.org>
9 @license: GNU General Public License version 2 or later
12 # This program is free software; you can redistribute it and/or modify
13 # it under the terms of the GNU General Public License as published by
14 # the Free Software Foundation; either version 2 of the License, or
15 # (at your option) any later version.
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
26 ################################################################################
28 # < mhy> I need a funny comment
29 # < sgran> two peanuts were walking down a dark street
30 # < sgran> one was a-salted
31 # * mhy looks up the definition of "funny"
33 ################################################################################
36 from psycopg2.extras import DictCursor
38 from Singleton import Singleton
39 from Config import Config
41 ################################################################################
44 def __init__(self, hashfunc=None):
46 self.hashfunc = hashfunc
48 self.hashfunc = lambda x: x['value']
52 def SetValue(self, keys, value):
53 self.data[self.hashfunc(keys)] = value
55 def GetValue(self, keys):
56 return self.data.get(self.hashfunc(keys))
58 ################################################################################
60 class DBConn(Singleton):
64 def __init__(self, *args, **kwargs):
65 super(DBConn, self).__init__(*args, **kwargs)
67 def _startup(self, *args, **kwargs):
71 ## Connection functions
72 def __createconn(self):
73 connstr = Config().GetDBConnString()
74 self.db_con = psycopg2.connect(connstr)
79 except psycopg2.InterfaceError:
86 def __init_caches(self):
87 self.caches = {'suite': Cache(),
90 'override_type': Cache(),
91 'architecture': Cache(),
94 'location': Cache(lambda x: '%s_%s_%s' % (x['location'], x['component'], x['location'])),
95 'maintainer': {}, # TODO
97 'source': Cache(lambda x: '%s_%s_' % (x['source'], x['version'])),
99 'maintainer': {}, # TODO
100 'fingerprint': {}, # TODO
103 'suite_version': Cache(lambda x: '%s_%s' % (x['source'], x['suite'])),
106 def clear_caches(self):
109 ## Functions to pass through to the database connector
111 return self.db_con.cursor()
114 return self.db_con.commit()
117 def __get_single_id(self, query, values, cachename=None):
118 # This is a bit of a hack but it's an internal function only
119 if cachename is not None:
120 res = self.caches[cachename].GetValue(values)
124 c = self.db_con.cursor()
125 c.execute(query, values)
130 res = c.fetchone()[0]
132 if cachename is not None:
133 self.caches[cachename].SetValue(values, res)
137 def __get_id(self, retfield, table, qfield, value):
138 query = "SELECT %s FROM %s WHERE %s = %%(value)s" % (retfield, table, qfield)
139 return self.__get_single_id(query, {'value': value}, cachename=table)
141 def get_suite_id(self, suite):
143 Returns database id for given C{suite}.
144 Results are kept in a cache during runtime to minimize database queries.
147 @param suite: The name of the suite
150 @return: the database id for the given suite
153 return self.__get_id('id', 'suite', 'suite_name', suite)
155 def get_section_id(self, section):
157 Returns database id for given C{section}.
158 Results are kept in a cache during runtime to minimize database queries.
160 @type section: string
161 @param section: The name of the section
164 @return: the database id for the given section
167 return self.__get_id('id', 'section', 'section', section)
169 def get_priority_id(self, priority):
171 Returns database id for given C{priority}.
172 Results are kept in a cache during runtime to minimize database queries.
174 @type priority: string
175 @param priority: The name of the priority
178 @return: the database id for the given priority
181 return self.__get_id('id', 'priority', 'priority', priority)
183 def get_override_type_id(self, override_type):
185 Returns database id for given override C{type}.
186 Results are kept in a cache during runtime to minimize database queries.
189 @param type: The name of the override type
192 @return: the database id for the given override type
195 return self.__get_id('id', 'override_type', 'override_type', override_type)
197 def get_architecture_id(self, architecture):
199 Returns database id for given C{architecture}.
200 Results are kept in a cache during runtime to minimize database queries.
202 @type architecture: string
203 @param architecture: The name of the override type
206 @return: the database id for the given architecture
209 return self.__get_id('id', 'architecture', 'arch_string', architecture)
211 def get_archive_id(self, archive):
213 returns database id for given c{archive}.
214 results are kept in a cache during runtime to minimize database queries.
216 @type archive: string
217 @param archive: the name of the override type
220 @return: the database id for the given archive
223 return self.__get_id('id', 'archive', 'lower(name)', archive)
225 def get_component_id(self, component):
227 Returns database id for given C{component}.
228 Results are kept in a cache during runtime to minimize database queries.
230 @type component: string
231 @param component: The name of the override type
234 @return: the database id for the given component
237 return self.__get_id('id', 'component', 'lower(name)', component)
239 def get_location_id(self, location, component, archive):
241 Returns database id for the location behind the given combination of
242 - B{location} - the path of the location, eg. I{/srv/ftp.debian.org/ftp/pool/}
243 - B{component} - the id of the component as returned by L{get_component_id}
244 - B{archive} - the id of the archive as returned by L{get_archive_id}
245 Results are kept in a cache during runtime to minimize database queries.
247 @type location: string
248 @param location: the path of the location
251 @param component: the id of the component
254 @param archive: the id of the archive
257 @return: the database id for the location
261 archive_id = self.get_archive_id(archive)
269 component_id = self.get_component_id(component)
271 res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND component=%(component)d AND archive=%(archive)d",
272 {'location': location, 'archive': archive_id, 'component': component_id}, cachename='location')
274 res = self.__get_single_id("SELECT id FROM location WHERE path=%(location)s AND archive=%(archive)d",
275 {'location': location, 'archive': archive_id, 'component': ''}, cachename='location')
279 def get_source_id(self, source, version):
281 Returns database id for the combination of C{source} and C{version}
282 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
284 Results are kept in a cache during runtime to minimize database queries.
287 @param source: source package name
289 @type version: string
290 @param version: the source version
293 @return: the database id for the source
296 return self.__get_single_id("SELECT id FROM source s WHERE s.source=%(source)s AND s.version=%(version)s",
297 {'source': source, 'version': version}, cachename='source')
299 def get_suite_version(self, source, suite):
301 Returns database id for a combination of C{source} and C{suite}.
303 - B{source} - source package name, eg. I{mailfilter}, I{bbdb}, I{glibc}
304 - B{suite} - a suite name, eg. I{unstable}
306 Results are kept in a cache during runtime to minimize database queries.
309 @param source: source package name
312 @param suite: the suite name
315 @return: the version for I{source} in I{suite}
318 return self.__get_single_id("""
319 SELECT s.version FROM source s, suite su, src_associations sa
322 AND su.suite_name=%(suite)s
323 AND s.source=%(source)""", {'suite': suite, 'source': source}, cachename='suite_version')