]> git.decadent.org.uk Git - dak.git/blob - dak/dakdb/update2.py
merge from master
[dak.git] / dak / dakdb / update2.py
1 #!/usr/bin/env python
2 # coding=utf8
3
4 """ Database Update Script - debversion """
5 # Copyright © 2008  Michael Casadevall <mcasadevall@debian.org>
6 # Copyright © 2008  Roger Leigh <rleigh@debian.org>
7
8 # This program is free software; you can redistribute it and/or modify
9 # it under the terms of the GNU General Public License as published by
10 # the Free Software Foundation; either version 2 of the License, or
11 # (at your option) any later version.
12
13 # This program is distributed in the hope that it will be useful,
14 # but WITHOUT ANY WARRANTY; without even the implied warranty of
15 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 # GNU General Public License for more details.
17
18 # You should have received a copy of the GNU General Public License
19 # along with this program; if not, write to the Free Software
20 # Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
21
22 ################################################################################
23
24 import psycopg2
25 import time
26 from daklib.dak_exceptions import DBUpdateError
27
28 ################################################################################
29
30 def do_update(self):
31 vvvvvvvvvvvvvvvvvvvv
32     print "Note: to be able to enable the the PL/Perl (plperl) procedural language, we do"
33     print "need postgresql-plperl-$postgres-version installed. Make sure that this is the"
34     print "case before you continue. Interrupt if it isn't, sleeping 5 seconds now."
35     print "(We need to be database superuser for this to work!)"
36     time.sleep (5)
37 ^^^^^^^^^^^^^^^^^^^^
38
39     try:
40         c = self.db.cursor()
41
42         print "Enabling PL/Perl language"
43         c.execute("CREATE LANGUAGE plperl;")
44         c.execute("CREATE LANGUAGE plpgsql;")
45
46         print "Adding debversion type to database."
47
48 # Not present in all databases, maybe PL/Perl version-dependent?
49 #        c.execute("SET SESSION plperl.use_strict TO 't';")
50
51         c.execute("CREATE DOMAIN debversion AS TEXT;")
52         c.execute("COMMENT ON DOMAIN debversion IS 'Debian package version number';")
53
54         c.execute("""ALTER DOMAIN debversion
55                      ADD CONSTRAINT debversion_syntax
56                      CHECK (VALUE !~ '[^-+:.0-9a-zA-Z~]');""")
57
58         # From Dpkg::Version::parseversion
59         c.execute("""CREATE OR REPLACE FUNCTION debversion_split (debversion)
60   RETURNS text[] AS $$
61     my $ver = shift;
62     my %verhash;
63     if ($ver =~ /:/)
64     {
65         $ver =~ /^(\d+):(.+)/ or die "bad version number '$ver'";
66         $verhash{epoch} = $1;
67         $ver = $2;
68     }
69     else
70     {
71         $verhash{epoch} = 0;
72     }
73     if ($ver =~ /(.+)-(.*)$/)
74     {
75         $verhash{version} = $1;
76         $verhash{revision} = $2;
77     }
78     else
79     {
80         $verhash{version} = $ver;
81         $verhash{revision} = 0;
82     }
83
84     return [$verhash{'epoch'}, $verhash{'version'}, $verhash{'revision'}];
85 $$
86   LANGUAGE plperl
87   IMMUTABLE STRICT;""")
88         c.execute("""COMMENT ON FUNCTION debversion_split (debversion)
89                    IS 'Split debian version into epoch, upstream version and revision';""")
90
91         c.execute("""CREATE OR REPLACE FUNCTION debversion_epoch (version debversion)
92   RETURNS text AS $$
93 DECLARE
94   split text[];
95 BEGIN
96   split := debversion_split(version);
97   RETURN split[1];
98 END;
99 $$
100   LANGUAGE plpgsql
101   IMMUTABLE STRICT;
102 COMMENT ON FUNCTION debversion_epoch (debversion)
103   IS 'Get debian version epoch';
104
105 CREATE OR REPLACE FUNCTION debversion_version (version debversion)
106   RETURNS text AS $$
107 DECLARE
108   split text[];
109 BEGIN
110   split := debversion_split(version);
111   RETURN split[2];
112 END;
113 $$
114   LANGUAGE plpgsql
115   IMMUTABLE STRICT;""")
116         c.execute("""COMMENT ON FUNCTION debversion_version (debversion)
117                    IS 'Get debian version upstream version';""")
118
119         c.execute("""CREATE OR REPLACE FUNCTION debversion_revision (version debversion)
120   RETURNS text AS $$
121 DECLARE
122   split text[];
123 BEGIN
124   split := debversion_split(version);
125   RETURN split[3];
126 END;
127 $$
128   LANGUAGE plpgsql
129   IMMUTABLE STRICT;""")
130         c.execute("""COMMENT ON FUNCTION debversion_revision (debversion)
131                    IS 'Get debian version revision';""")
132
133 # From Dpkg::Version::parseversion
134         c.execute("""CREATE OR REPLACE FUNCTION debversion_compare_single (version1 text, version2 text)
135   RETURNS integer AS $$
136      sub order{
137           my ($x) = @_;
138           ##define order(x) ((x) == '~' ? -1 \
139           #           : cisdigit((x)) ? 0 \
140           #           : !(x) ? 0 \
141           #           : cisalpha((x)) ? (x) \
142           #           : (x) + 256)
143           # This comparison is out of dpkg's order to avoid
144           # comparing things to undef and triggering warnings.
145           if (not defined $x or not length $x) {
146                return 0;
147           }
148           elsif ($x eq '~') {
149                return -1;
150           }
151           elsif ($x =~ /^\d$/) {
152                return 0;
153           }
154           elsif ($x =~ /^[A-Z]$/i) {
155                return ord($x);
156           }
157           else {
158                return ord($x) + 256;
159           }
160      }
161
162      sub next_elem(\@){
163           my $a = shift;
164           return @{$a} ? shift @{$a} : undef;
165      }
166      my ($val, $ref) = @_;
167      $val = "" if not defined $val;
168      $ref = "" if not defined $ref;
169      my @val = split //,$val;
170      my @ref = split //,$ref;
171      my $vc = next_elem @val;
172      my $rc = next_elem @ref;
173      while (defined $vc or defined $rc) {
174           my $first_diff = 0;
175           while ((defined $vc and $vc !~ /^\d$/) or
176                  (defined $rc and $rc !~ /^\d$/)) {
177                my $vo = order($vc); my $ro = order($rc);
178                # Unlike dpkg's verrevcmp, we only return 1 or -1 here.
179                return (($vo - $ro > 0) ? 1 : -1) if $vo != $ro;
180                $vc = next_elem @val; $rc = next_elem @ref;
181           }
182           while (defined $vc and $vc eq '0') {
183                $vc = next_elem @val;
184           }
185           while (defined $rc and $rc eq '0') {
186                $rc = next_elem @ref;
187           }
188           while (defined $vc and $vc =~ /^\d$/ and
189                  defined $rc and $rc =~ /^\d$/) {
190                $first_diff = ord($vc) - ord($rc) if !$first_diff;
191                $vc = next_elem @val; $rc = next_elem @ref;
192           }
193           return 1 if defined $vc and $vc =~ /^\d$/;
194           return -1 if defined $rc and $rc =~ /^\d$/;
195           return (($first_diff  > 0) ? 1 : -1) if $first_diff;
196      }
197      return 0;
198 $$
199   LANGUAGE plperl
200   IMMUTABLE STRICT;""")
201         c.execute("""COMMENT ON FUNCTION debversion_compare_single (text, text)
202                    IS 'Compare upstream or revision parts of Debian versions';""")
203
204 # Logic only derived from Dpkg::Version::parseversion
205         c.execute("""CREATE OR REPLACE FUNCTION debversion_compare (version1 debversion, version2 debversion)
206   RETURNS integer AS $$
207 DECLARE
208   split1 text[];
209   split2 text[];
210   result integer;
211 BEGIN
212   result := 0;
213   split1 := debversion_split(version1);
214   split2 := debversion_split(version2);
215
216   -- RAISE NOTICE 'Version 1: %', version1;
217   -- RAISE NOTICE 'Version 2: %', version2;
218   -- RAISE NOTICE 'Split 1: %', split1;
219   -- RAISE NOTICE 'Split 2: %', split2;
220
221   IF split1[1] > split2[1] THEN
222     result := 1;
223   ELSIF split1[1] < split2[1] THEN
224     result := -1;
225   ELSE
226     result := debversion_compare_single(split1[2], split2[2]);
227     IF result = 0 THEN
228       result := debversion_compare_single(split1[3], split2[3]);
229     END IF;
230   END IF;
231
232   RETURN result;
233 END;
234 $$
235   LANGUAGE plpgsql
236   IMMUTABLE STRICT;""")
237         c.execute("""COMMENT ON FUNCTION debversion_compare (debversion, debversion)
238   IS 'Compare Debian versions';""")
239
240         c.execute("""CREATE OR REPLACE FUNCTION debversion_eq (version1 debversion, version2 debversion)
241   RETURNS boolean AS $$
242 DECLARE
243   comp integer;
244   result boolean;
245 BEGIN
246   comp := debversion_compare(version1, version2);
247   result := comp = 0;
248   RETURN result;
249 END;
250 $$
251   LANGUAGE plpgsql
252   IMMUTABLE STRICT;""")
253         c.execute("""COMMENT ON FUNCTION debversion_eq (debversion, debversion)
254   IS 'debversion equal';""")
255
256         c.execute("""CREATE OR REPLACE FUNCTION debversion_ne (version1 debversion, version2 debversion)
257   RETURNS boolean AS $$
258 DECLARE
259   comp integer;
260   result boolean;
261 BEGIN
262   comp := debversion_compare(version1, version2);
263   result := comp <> 0;
264   RETURN result;
265 END;
266 $$
267   LANGUAGE plpgsql
268   IMMUTABLE STRICT;""")
269         c.execute("""COMMENT ON FUNCTION debversion_ne (debversion, debversion)
270   IS 'debversion not equal';""")
271
272         c.execute("""CREATE OR REPLACE FUNCTION debversion_lt (version1 debversion, version2 debversion)
273   RETURNS boolean AS $$
274 DECLARE
275   comp integer;
276   result boolean;
277 BEGIN
278   comp := debversion_compare(version1, version2);
279   result := comp < 0;
280   RETURN result;
281 END;
282 $$
283   LANGUAGE plpgsql
284   IMMUTABLE STRICT;""")
285         c.execute("""COMMENT ON FUNCTION debversion_lt (debversion, debversion)
286                    IS 'debversion less-than';""")
287
288         c.execute("""CREATE OR REPLACE FUNCTION debversion_gt (version1 debversion, version2 debversion) RETURNS boolean AS $$
289 DECLARE
290   comp integer;
291   result boolean;
292 BEGIN
293   comp := debversion_compare(version1, version2);
294   result := comp > 0;
295   RETURN result;
296 END;
297 $$
298   LANGUAGE plpgsql
299   IMMUTABLE STRICT;""")
300         c.execute("""COMMENT ON FUNCTION debversion_gt (debversion, debversion)
301                    IS 'debversion greater-than';""")
302
303         c.execute("""CREATE OR REPLACE FUNCTION debversion_le (version1 debversion, version2 debversion)
304   RETURNS boolean AS $$
305 DECLARE
306   comp integer;
307   result boolean;
308 BEGIN
309   comp := debversion_compare(version1, version2);
310   result := comp <= 0;
311   RETURN result;
312 END;
313 $$
314   LANGUAGE plpgsql
315   IMMUTABLE STRICT;""")
316         c.execute("""COMMENT ON FUNCTION debversion_le (debversion, debversion)
317                    IS 'debversion less-than-or-equal';""")
318
319         c.execute("""CREATE OR REPLACE FUNCTION debversion_ge (version1 debversion, version2 debversion)
320   RETURNS boolean AS $$
321 DECLARE
322   comp integer;
323   result boolean;
324 BEGIN
325   comp := debversion_compare(version1, version2);
326   result := comp >= 0;
327   RETURN result;
328 END;
329 $$
330   LANGUAGE plpgsql
331   IMMUTABLE STRICT;""")
332         c.execute("""COMMENT ON FUNCTION debversion_ge (debversion, debversion)
333                    IS 'debversion greater-than-or-equal';""")
334
335         c.execute("""CREATE OPERATOR = (
336                    PROCEDURE = debversion_eq,
337                    LEFTARG = debversion,
338                    RIGHTARG = debversion,
339                    COMMUTATOR = =,
340                    NEGATOR = !=);""")
341         c.execute("""COMMENT ON OPERATOR = (debversion, debversion)
342                    IS 'debversion equal';""")
343
344         c.execute("""CREATE OPERATOR != (
345                    PROCEDURE = debversion_eq,
346                    LEFTARG = debversion,
347                    RIGHTARG = debversion,
348                    COMMUTATOR = !=,
349                    NEGATOR = =);""")
350         c.execute("""COMMENT ON OPERATOR != (debversion, debversion)
351                    IS 'debversion not equal';""")
352
353         c.execute("""CREATE OPERATOR < (
354                    PROCEDURE = debversion_lt,
355                    LEFTARG = debversion,
356                    RIGHTARG = debversion,
357                    COMMUTATOR = >,
358                    NEGATOR = >=);""")
359         c.execute("""COMMENT ON OPERATOR < (debversion, debversion)
360                    IS 'debversion less-than';""")
361
362         c.execute("""CREATE OPERATOR > (
363                    PROCEDURE = debversion_gt,
364                    LEFTARG = debversion,
365                    RIGHTARG = debversion,
366                    COMMUTATOR = <,
367                    NEGATOR = >=);""")
368         c.execute("""COMMENT ON OPERATOR > (debversion, debversion)
369                    IS 'debversion greater-than';""")
370
371         c.execute("""CREATE OPERATOR <= (
372                    PROCEDURE = debversion_le,
373                    LEFTARG = debversion,
374                    RIGHTARG = debversion,
375                    COMMUTATOR = >=,
376                    NEGATOR = >);""")
377         c.execute("""COMMENT ON OPERATOR <= (debversion, debversion)
378                    IS 'debversion less-than-or-equal';""")
379
380         c.execute("""CREATE OPERATOR >= (
381                    PROCEDURE = debversion_ge,
382                    LEFTARG = debversion,
383                    RIGHTARG = debversion,
384                    COMMUTATOR = <=,
385                    NEGATOR = <);""")
386         c.execute("""COMMENT ON OPERATOR >= (debversion, debversion)
387                    IS 'debversion greater-than-or-equal';""")
388
389         c.execute("ALTER TABLE source ALTER COLUMN version TYPE debversion;")
390         c.execute("ALTER TABLE binaries ALTER COLUMN version TYPE debversion;")
391
392         c.execute("UPDATE config SET value = '2' WHERE name = 'db_revision'")
393
394         self.db.commit()
395
396     except psycopg2.ProgrammingError, msg:
397         self.db.rollback()
398         raise DBUpdateError, "Unable to appy debversion updates, rollback issued. Error message : %s" % (str(msg))