]> git.decadent.org.uk Git - dak.git/blob - daklib/database.py
Merge commit 'ftpmaster/master' into psycopg2
[dak.git] / daklib / database.py
1 #!/usr/bin/env python
2
3 # DB access fucntions
4 # Copyright (C) 2000, 2001, 2002, 2003, 2004, 2006  James Troup <james@nocrew.org>
5
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10
11 # This program is distributed in the hope that it will be useful,
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 # GNU General Public License for more details.
15
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
20 ################################################################################
21
22 import sys
23 import time
24 import types
25
26 ################################################################################
27
28 Cnf = None
29 projectB = None
30 suite_id_cache = {}
31 section_id_cache = {}
32 priority_id_cache = {}
33 override_type_id_cache = {}
34 architecture_id_cache = {}
35 archive_id_cache = {}
36 component_id_cache = {}
37 location_id_cache = {}
38 maintainer_id_cache = {}
39 keyring_id_cache = {}
40 source_id_cache = {}
41 files_id_cache = {}
42 maintainer_cache = {}
43 fingerprint_id_cache = {}
44 queue_id_cache = {}
45 uid_id_cache = {}
46 suite_version_cache = {}
47
48 ################################################################################
49
50 def init (config, sql):
51     """ database module init. Just sets two variables"""
52     global Cnf, projectB
53
54     Cnf = config
55     projectB = sql
56
57
58 def do_query(q):
59     """
60     Executes a database query q. Writes statistics to stderr and returns
61     the result.
62
63     """
64     sys.stderr.write("query: \"%s\" ... " % (q))
65     before = time.time()
66     r = projectB.query(q)
67     time_diff = time.time()-before
68     sys.stderr.write("took %.3f seconds.\n" % (time_diff))
69     if type(r) is int:
70         sys.stderr.write("int result: %s\n" % (r))
71     elif type(r) is types.NoneType:
72         sys.stderr.write("result: None\n")
73     else:
74         sys.stderr.write("pgresult: %s\n" % (r.getresult()))
75     return r
76
77 ################################################################################
78
79 def get_suite_id (suite):
80     """ Returns database suite_id for given suite, caches result. """
81     global suite_id_cache
82
83     if suite_id_cache.has_key(suite):
84         return suite_id_cache[suite]
85
86     q = projectB.query("SELECT id FROM suite WHERE suite_name = '%s'" % (suite))
87     ql = q.getresult()
88     if not ql:
89         return -1
90
91     suite_id = ql[0][0]
92     suite_id_cache[suite] = suite_id
93
94     return suite_id
95
96 def get_section_id (section):
97     """ Returns database section_id for given section, caches result. """
98     global section_id_cache
99
100     if section_id_cache.has_key(section):
101         return section_id_cache[section]
102
103     q = projectB.query("SELECT id FROM section WHERE section = '%s'" % (section))
104     ql = q.getresult()
105     if not ql:
106         return -1
107
108     section_id = ql[0][0]
109     section_id_cache[section] = section_id
110
111     return section_id
112
113 def get_priority_id (priority):
114     """ Returns database priority_id for given priority, caches result. """
115     global priority_id_cache
116
117     if priority_id_cache.has_key(priority):
118         return priority_id_cache[priority]
119
120     q = projectB.query("SELECT id FROM priority WHERE priority = '%s'" % (priority))
121     ql = q.getresult()
122     if not ql:
123         return -1
124
125     priority_id = ql[0][0]
126     priority_id_cache[priority] = priority_id
127
128     return priority_id
129
130 def get_override_type_id (type):
131     """ Returns database override_id for given override_type type, caches result. """
132     global override_type_id_cache
133
134     if override_type_id_cache.has_key(type):
135         return override_type_id_cache[type]
136
137     q = projectB.query("SELECT id FROM override_type WHERE type = '%s'" % (type))
138     ql = q.getresult()
139     if not ql:
140         return -1
141
142     override_type_id = ql[0][0]
143     override_type_id_cache[type] = override_type_id
144
145     return override_type_id
146
147 def get_architecture_id (architecture):
148     """ Returns database architecture_id for given architecture, caches result. """
149     global architecture_id_cache
150
151     if architecture_id_cache.has_key(architecture):
152         return architecture_id_cache[architecture]
153
154     q = projectB.query("SELECT id FROM architecture WHERE arch_string = '%s'" % (architecture))
155     ql = q.getresult()
156     if not ql:
157         return -1
158
159     architecture_id = ql[0][0]
160     architecture_id_cache[architecture] = architecture_id
161
162     return architecture_id
163
164 def get_archive_id (archive):
165     """ Returns database archive_id for given archive, caches result. """
166     global archive_id_cache
167
168     archive = archive.lower()
169
170     if archive_id_cache.has_key(archive):
171         return archive_id_cache[archive]
172
173     q = projectB.query("SELECT id FROM archive WHERE lower(name) = '%s'" % (archive))
174     ql = q.getresult()
175     if not ql:
176         return -1
177
178     archive_id = ql[0][0]
179     archive_id_cache[archive] = archive_id
180
181     return archive_id
182
183 def get_component_id (component):
184     """ Returns database component_id for given component, caches result. """
185     global component_id_cache
186
187     component = component.lower()
188
189     if component_id_cache.has_key(component):
190         return component_id_cache[component]
191
192     q = projectB.query("SELECT id FROM component WHERE lower(name) = '%s'" % (component))
193     ql = q.getresult()
194     if not ql:
195         return -1
196
197     component_id = ql[0][0]
198     component_id_cache[component] = component_id
199
200     return component_id
201
202 def get_location_id (location, component, archive):
203     """
204     Returns database location_id for given combination of
205     location
206     component
207     archive.
208
209     The 3 parameters are the database ids returned by the respective
210     "get_foo_id" functions.
211
212     The result will be cached.
213
214     """
215     global location_id_cache
216
217     cache_key = location + '_' + component + '_' + location
218     if location_id_cache.has_key(cache_key):
219         return location_id_cache[cache_key]
220
221     archive_id = get_archive_id (archive)
222     if component != "":
223         component_id = get_component_id (component)
224         if component_id != -1:
225             q = projectB.query("SELECT id FROM location WHERE path = '%s' AND component = %d AND archive = %d" % (location, component_id, archive_id))
226     else:
227         q = projectB.query("SELECT id FROM location WHERE path = '%s' AND archive = %d" % (location, archive_id))
228     ql = q.getresult()
229     if not ql:
230         return -1
231
232     location_id = ql[0][0]
233     location_id_cache[cache_key] = location_id
234
235     return location_id
236
237 def get_source_id (source, version):
238     """ Returns database source_id for given combination of source and version, caches result. """
239     global source_id_cache
240
241     cache_key = source + '_' + version + '_'
242     if source_id_cache.has_key(cache_key):
243         return source_id_cache[cache_key]
244
245     q = projectB.query("SELECT id FROM source s WHERE s.source = '%s' AND s.version = '%s'" % (source, version))
246
247     if not q.getresult():
248         return None
249
250     source_id = q.getresult()[0][0]
251     source_id_cache[cache_key] = source_id
252
253     return source_id
254
255 def get_suite_version(source, suite):
256     """ Returns database version for a given source in a given suite, caches result. """
257     global suite_version_cache
258     cache_key = "%s_%s" % (source, suite)
259
260     if suite_version_cache.has_key(cache_key):
261         return suite_version_cache[cache_key]
262
263     q = projectB.query("""
264     SELECT s.version FROM source s, suite su, src_associations sa
265     WHERE sa.source=s.id
266       AND sa.suite=su.id
267       AND su.suite_name='%s'
268       AND s.source='%s'"""
269                               % (suite, source))
270
271     if not q.getresult():
272         return None
273
274     version = q.getresult()[0][0]
275     suite_version_cache[cache_key] = version
276
277     return version
278
279 ################################################################################
280
281 def get_or_set_maintainer_id (maintainer):
282     """
283     If maintainer does not have an entry in the maintainer table yet, create one
284     and return its id.
285     If maintainer already has an entry, simply return its id.
286
287     Result is cached.
288
289     """
290     global maintainer_id_cache
291
292     if maintainer_id_cache.has_key(maintainer):
293         return maintainer_id_cache[maintainer]
294
295     q = projectB.query("SELECT id FROM maintainer WHERE name = '%s'" % (maintainer))
296     if not q.getresult():
297         projectB.query("INSERT INTO maintainer (name) VALUES ('%s')" % (maintainer))
298         q = projectB.query("SELECT id FROM maintainer WHERE name = '%s'" % (maintainer))
299     maintainer_id = q.getresult()[0][0]
300     maintainer_id_cache[maintainer] = maintainer_id
301
302     return maintainer_id
303
304 ################################################################################
305
306 def get_or_set_keyring_id (keyring):
307     """
308     If keyring does not have an entry in the keyring table yet, create one
309     and return its id.
310     If keyring already has an entry, simply return its id.
311
312     Result is cached.
313
314     """
315     global keyring_id_cache
316
317     if keyring_id_cache.has_key(keyring):
318         return keyring_id_cache[keyring]
319
320     q = projectB.query("SELECT id FROM keyrings WHERE name = '%s'" % (keyring))
321     if not q.getresult():
322         projectB.query("INSERT INTO keyrings (name) VALUES ('%s')" % (keyring))
323         q = projectB.query("SELECT id FROM keyrings WHERE name = '%s'" % (keyring))
324     keyring_id = q.getresult()[0][0]
325     keyring_id_cache[keyring] = keyring_id
326
327     return keyring_id
328
329 ################################################################################
330
331 def get_or_set_uid_id (uid):
332     """
333     If uid does not have an entry in the uid table yet, create one
334     and return its id.
335     If uid already has an entry, simply return its id.
336
337     Result is cached.
338
339     """
340     global uid_id_cache
341
342     if uid_id_cache.has_key(uid):
343         return uid_id_cache[uid]
344
345     q = projectB.query("SELECT id FROM uid WHERE uid = '%s'" % (uid))
346     if not q.getresult():
347         projectB.query("INSERT INTO uid (uid) VALUES ('%s')" % (uid))
348         q = projectB.query("SELECT id FROM uid WHERE uid = '%s'" % (uid))
349     uid_id = q.getresult()[0][0]
350     uid_id_cache[uid] = uid_id
351
352     return uid_id
353
354 ################################################################################
355
356 def get_or_set_fingerprint_id (fingerprint):
357     """
358     If fingerprintd does not have an entry in the fingerprint table yet, create one
359     and return its id.
360     If fingerprint already has an entry, simply return its id.
361
362     Result is cached.
363
364     """
365     global fingerprint_id_cache
366
367     if fingerprint_id_cache.has_key(fingerprint):
368         return fingerprint_id_cache[fingerprint]
369
370     q = projectB.query("SELECT id FROM fingerprint WHERE fingerprint = '%s'" % (fingerprint))
371     if not q.getresult():
372         projectB.query("INSERT INTO fingerprint (fingerprint) VALUES ('%s')" % (fingerprint))
373         q = projectB.query("SELECT id FROM fingerprint WHERE fingerprint = '%s'" % (fingerprint))
374     fingerprint_id = q.getresult()[0][0]
375     fingerprint_id_cache[fingerprint] = fingerprint_id
376
377     return fingerprint_id
378
379 ################################################################################
380
381 def get_files_id (filename, size, md5sum, location_id):
382     """
383     Returns -1, -2 or the file_id for a given combination of
384     filename
385     size
386     md5sum
387     location_id.
388
389     The database is queried using filename and location_id, size and md5sum are for
390     extra checks.
391
392     Return values:
393     -1 - The given combination of arguments result in more (or less) than
394          one result from the database
395     -2 - The given size and md5sum do not match the values in the database
396     anything else is a file_id
397
398     Result is cached.
399
400     """
401     global files_id_cache
402
403     cache_key = "%s_%d" % (filename, location_id)
404
405     if files_id_cache.has_key(cache_key):
406         return files_id_cache[cache_key]
407
408     size = int(size)
409     q = projectB.query("SELECT id, size, md5sum FROM files WHERE filename = '%s' AND location = %d" % (filename, location_id))
410     ql = q.getresult()
411     if ql:
412         if len(ql) != 1:
413             return -1
414         ql = ql[0]
415         orig_size = int(ql[1])
416         orig_md5sum = ql[2]
417         if orig_size != size or orig_md5sum != md5sum:
418             return -2
419         files_id_cache[cache_key] = ql[0]
420         return files_id_cache[cache_key]
421     else:
422         return None
423
424 ################################################################################
425
426 def get_or_set_queue_id (queue):
427     """
428     If queue does not have an entry in the queue_name table yet, create one
429     and return its id.
430     If queue already has an entry, simply return its id.
431
432     Result is cached.
433
434     """
435     global queue_id_cache
436
437     if queue_id_cache.has_key(queue):
438         return queue_id_cache[queue]
439
440     q = projectB.query("SELECT id FROM queue WHERE queue_name = '%s'" % (queue))
441     if not q.getresult():
442         projectB.query("INSERT INTO queue (queue_name) VALUES ('%s')" % (queue))
443         q = projectB.query("SELECT id FROM queue WHERE queue_name = '%s'" % (queue))
444     queue_id = q.getresult()[0][0]
445     queue_id_cache[queue] = queue_id
446
447     return queue_id
448
449 ################################################################################
450
451 def set_files_id (filename, size, md5sum, sha1sum, sha256sum, location_id):
452     """
453     Insert a new entry into the files table.
454
455     Returns the new file_id
456
457     """
458     global files_id_cache
459
460     projectB.query("INSERT INTO files (filename, size, md5sum, sha1sum, sha256sum, location) VALUES ('%s', %d, '%s', '%s', '%s', %d)" % (filename, long(size), md5sum, sha1sum, sha256sum, location_id))
461
462     return get_files_id (filename, size, md5sum, location_id)
463
464     ### currval has issues with postgresql 7.1.3 when the table is big
465     ### it was taking ~3 seconds to return on auric which is very Not
466     ### Cool(tm).
467     ##
468     ##q = projectB.query("SELECT id FROM files WHERE id = currval('files_id_seq')")
469     ##ql = q.getresult()[0]
470     ##cache_key = "%s_%d" % (filename, location_id)
471     ##files_id_cache[cache_key] = ql[0]
472     ##return files_id_cache[cache_key]
473
474 ################################################################################
475
476 def get_maintainer (maintainer_id):
477     """ Return the name of the maintainer behind maintainer_id """
478     global maintainer_cache
479
480     if not maintainer_cache.has_key(maintainer_id):
481         q = projectB.query("SELECT name FROM maintainer WHERE id = %s" % (maintainer_id))
482         maintainer_cache[maintainer_id] = q.getresult()[0][0]
483
484     return maintainer_cache[maintainer_id]
485
486 ################################################################################
487
488 def get_suites(pkgname, src=False):
489     """ Return the suites in which pkgname is. If src is True, query for source package, else binary. """
490     if src:
491         sql = """
492         SELECT suite_name
493         FROM source,
494              src_associations,
495              suite
496         WHERE source.id = src_associations.source
497         AND   source.source = '%s'
498         AND   src_associations.suite = suite.id
499         """ % (pkgname)
500     else:
501         sql = """
502         SELECT suite_name
503         FROM binaries,
504              bin_associations,
505              suite
506         WHERE binaries.id = bin_associations.bin
507         AND   package = '%s'
508         AND   bin_associations.suite = suite.id
509         """ % (pkgname)
510
511     q = projectB.query(sql)
512     return map(lambda x: x[0], q.getresult())